@nerviq/cli 1.20.1 → 1.22.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 +20 -2
- package/bin/cli.js +3 -3
- 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/audit.js +20 -0
- 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/csv.js +69 -0
- package/src/formatters/junit.js +99 -0
- package/src/formatters/markdown.js +118 -0
- 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
package/src/aider/techniques.js
CHANGED
|
@@ -91,6 +91,98 @@ function findFillerLine(content) {
|
|
|
91
91
|
return firstLineMatching(content, (line) => FILLER_PATTERNS.some((pattern) => pattern.test(line)));
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// PP-04: Helpers for N/A gating and broader instruction surfaces ---------------
|
|
95
|
+
|
|
96
|
+
function hasAiderConfig(ctx) {
|
|
97
|
+
// .yml is canonical, .yaml is also accepted by Aider itself
|
|
98
|
+
return Boolean(
|
|
99
|
+
(ctx.fileContent && (ctx.fileContent('.aider.conf.yml') || ctx.fileContent('.aider.conf.yaml')))
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function hasAiderModelSettings(ctx) {
|
|
104
|
+
return Boolean(
|
|
105
|
+
ctx.fileContent && (ctx.fileContent('.aider.model.settings.yml') || ctx.fileContent('.aider.model.settings.yaml'))
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasAiderignore(ctx) {
|
|
110
|
+
return Boolean(ctx.fileContent && ctx.fileContent('.aiderignore'));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function readmeContent(ctx) {
|
|
114
|
+
return (
|
|
115
|
+
(ctx.fileContent && (ctx.fileContent('README.md') || ctx.fileContent('readme.md') || ctx.fileContent('README.rst'))) || ''
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function contributingContent(ctx) {
|
|
120
|
+
return (
|
|
121
|
+
(ctx.fileContent && (ctx.fileContent('CONTRIBUTING.md') || ctx.fileContent('.github/CONTRIBUTING.md'))) || ''
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function aidermdContent(ctx) {
|
|
126
|
+
return (
|
|
127
|
+
(ctx.fileContent && (ctx.fileContent('AIDER.md') || ctx.fileContent('AGENTS.md') || ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md'))) || ''
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// PP-04: Effective Aider docs surface — Aider has no auto-discovered instructions
|
|
132
|
+
// surface like CLAUDE.md, but real Aider users document Aider workflow across
|
|
133
|
+
// README, CONTRIBUTING, CONVENTIONS, AGENTS.md, CLAUDE.md, .ai/instructions.md.
|
|
134
|
+
function docsBundle(ctx) {
|
|
135
|
+
const parts = [];
|
|
136
|
+
parts.push(readmeContent(ctx));
|
|
137
|
+
parts.push(contributingContent(ctx));
|
|
138
|
+
parts.push(conventionContent(ctx));
|
|
139
|
+
parts.push(aidermdContent(ctx));
|
|
140
|
+
if (ctx.fileContent) {
|
|
141
|
+
parts.push(ctx.fileContent('.ai/instructions.md') || '');
|
|
142
|
+
parts.push(ctx.fileContent('docs/AIDER.md') || '');
|
|
143
|
+
parts.push(ctx.fileContent('ARCHITECTURE.md') || '');
|
|
144
|
+
}
|
|
145
|
+
return parts.filter(Boolean).join('\n\n');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function hasAnyAiderSurface(ctx) {
|
|
149
|
+
if (hasAiderConfig(ctx)) return true;
|
|
150
|
+
if (hasAiderModelSettings(ctx)) return true;
|
|
151
|
+
if (hasAiderignore(ctx)) return true;
|
|
152
|
+
if (conventionFiles(ctx).length > 0) return true;
|
|
153
|
+
// README/CONTRIBUTING/AGENTS/CLAUDE explicitly mentioning aider counts
|
|
154
|
+
const docs = `${readmeContent(ctx)}\n${contributingContent(ctx)}\n${aidermdContent(ctx)}`;
|
|
155
|
+
return /\baider\b/i.test(docs);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function isPythonProject(ctx) {
|
|
159
|
+
if (!ctx.fileContent) return false;
|
|
160
|
+
return Boolean(
|
|
161
|
+
ctx.fileContent('requirements.txt') ||
|
|
162
|
+
ctx.fileContent('Pipfile') ||
|
|
163
|
+
ctx.fileContent('pyproject.toml') ||
|
|
164
|
+
ctx.fileContent('setup.py') ||
|
|
165
|
+
ctx.fileContent('setup.cfg')
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function hasArchitectMode(ctx) {
|
|
170
|
+
const config = configContent(ctx);
|
|
171
|
+
if (!config) return false;
|
|
172
|
+
return /\barchitect\s*:\s*true\b/i.test(config) || /\barchitect-mode\s*:\s*true\b/i.test(config);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function hasEnvExample(ctx) {
|
|
176
|
+
if (!ctx.fileContent) return false;
|
|
177
|
+
return Boolean(
|
|
178
|
+
ctx.fileContent('.env.example') ||
|
|
179
|
+
ctx.fileContent('.env.sample') ||
|
|
180
|
+
ctx.fileContent('.env.template') ||
|
|
181
|
+
ctx.fileContent('.env.dist') ||
|
|
182
|
+
ctx.fileContent('env.example')
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
94
186
|
function repoLooksRegulated(ctx) {
|
|
95
187
|
const filenames = ctx.files.join('\n');
|
|
96
188
|
const packageJson = ctx.fileContent('package.json') || '';
|
|
@@ -112,7 +204,14 @@ const AIDER_TECHNIQUES = {
|
|
|
112
204
|
aiderConfYmlExists: {
|
|
113
205
|
id: 'AD-A01',
|
|
114
206
|
name: '.aider.conf.yml config file exists',
|
|
115
|
-
|
|
207
|
+
// PP-04: Both .yml and .yaml are accepted by Aider. The config file is
|
|
208
|
+
// recommended but optional — many real Aider repos drive Aider entirely
|
|
209
|
+
// via CONVENTIONS.md + CLI flags. N/A when no Aider surface at all so
|
|
210
|
+
// arbitrary repos do not surface this as a top finding.
|
|
211
|
+
check: (ctx) => {
|
|
212
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
213
|
+
return hasAiderConfig(ctx);
|
|
214
|
+
},
|
|
116
215
|
impact: 'critical',
|
|
117
216
|
rating: 5,
|
|
118
217
|
category: 'config',
|
|
@@ -177,10 +276,14 @@ const AIDER_TECHNIQUES = {
|
|
|
177
276
|
aiderMapTokensConfigured: {
|
|
178
277
|
id: 'AD-A05',
|
|
179
278
|
name: 'Map tokens setting is configured',
|
|
279
|
+
// PP-04: Repo-map sizing is opt-in tuning — the default works for most
|
|
280
|
+
// repos. N/A when not explicitly set; only fail if explicitly set to a
|
|
281
|
+
// non-numeric or out-of-range value (caught by other checks).
|
|
180
282
|
check: (ctx) => {
|
|
181
283
|
const config = configContent(ctx);
|
|
182
284
|
if (!config) return null;
|
|
183
|
-
|
|
285
|
+
if (/\bmap-tokens\s*:/i.test(config)) return true;
|
|
286
|
+
return null;
|
|
184
287
|
},
|
|
185
288
|
impact: 'medium',
|
|
186
289
|
rating: 3,
|
|
@@ -228,10 +331,14 @@ const AIDER_TECHNIQUES = {
|
|
|
228
331
|
aiderEditFormatConfigured: {
|
|
229
332
|
id: 'AD-A08',
|
|
230
333
|
name: 'Edit format explicitly set',
|
|
334
|
+
// PP-04: Aider auto-selects edit-format per model; explicit override is
|
|
335
|
+
// only needed for unusual setups. Pass when set, N/A when relying on the
|
|
336
|
+
// sensible default.
|
|
231
337
|
check: (ctx) => {
|
|
232
338
|
const config = configContent(ctx);
|
|
233
339
|
if (!config) return null;
|
|
234
|
-
|
|
340
|
+
if (/\bedit-format\s*:/i.test(config)) return true;
|
|
341
|
+
return null;
|
|
235
342
|
},
|
|
236
343
|
impact: 'medium',
|
|
237
344
|
rating: 3,
|
|
@@ -350,10 +457,14 @@ const AIDER_TECHNIQUES = {
|
|
|
350
457
|
aiderCommitPrefixConfigured: {
|
|
351
458
|
id: 'AD-B07',
|
|
352
459
|
name: 'Commit prefix set for AI-authored commits',
|
|
460
|
+
// PP-04: Optional traceability nicety. Pass when set, N/A when not —
|
|
461
|
+
// attribute-author/committer (AD-B06) covers the same intent at higher
|
|
462
|
+
// confidence.
|
|
353
463
|
check: (ctx) => {
|
|
354
464
|
const config = configContent(ctx);
|
|
355
465
|
if (!config) return null;
|
|
356
|
-
|
|
466
|
+
if (/\baider-commit-prefix\s*:/i.test(config) || /\bcommit-prefix\s*:/i.test(config)) return true;
|
|
467
|
+
return null;
|
|
357
468
|
},
|
|
358
469
|
impact: 'low',
|
|
359
470
|
rating: 2,
|
|
@@ -368,9 +479,14 @@ const AIDER_TECHNIQUES = {
|
|
|
368
479
|
id: 'AD-B08',
|
|
369
480
|
name: '/undo command awareness documented',
|
|
370
481
|
check: (ctx) => {
|
|
371
|
-
|
|
482
|
+
// PP-04: Awareness check. N/A unless the repo has an .aider.conf.yml —
|
|
483
|
+
// /undo is an Aider-specific concept and only meaningful for users who
|
|
484
|
+
// have actually configured Aider.
|
|
485
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
486
|
+
const docs = docsBundle(ctx);
|
|
372
487
|
const config = configContent(ctx);
|
|
373
|
-
|
|
488
|
+
if (!docs && !config) return null;
|
|
489
|
+
return /\bundo\b/i.test(docs) || /\bundo\b/i.test(config);
|
|
374
490
|
},
|
|
375
491
|
impact: 'low',
|
|
376
492
|
rating: 2,
|
|
@@ -389,6 +505,9 @@ const AIDER_TECHNIQUES = {
|
|
|
389
505
|
id: 'AD-C01',
|
|
390
506
|
name: 'Editor model explicitly configured',
|
|
391
507
|
check: (ctx) => {
|
|
508
|
+
// PP-04: editor-model is an architect-mode optimisation. N/A when not opted in.
|
|
509
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
510
|
+
if (!hasArchitectMode(ctx)) return null;
|
|
392
511
|
const roles = modelRoles(ctx);
|
|
393
512
|
return roles.editor !== null;
|
|
394
513
|
},
|
|
@@ -405,6 +524,8 @@ const AIDER_TECHNIQUES = {
|
|
|
405
524
|
id: 'AD-C02',
|
|
406
525
|
name: 'Weak model configured for commit messages',
|
|
407
526
|
check: (ctx) => {
|
|
527
|
+
// PP-04: weak-model is a cost optimisation. N/A when no .aider.conf.yml.
|
|
528
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
408
529
|
const roles = modelRoles(ctx);
|
|
409
530
|
return roles.weak !== null;
|
|
410
531
|
},
|
|
@@ -420,10 +541,13 @@ const AIDER_TECHNIQUES = {
|
|
|
420
541
|
aiderArchitectModeAvailable: {
|
|
421
542
|
id: 'AD-C03',
|
|
422
543
|
name: 'Architect mode configured (2-model workflow)',
|
|
544
|
+
// PP-04: Architect mode is opt-in (~1.73x cost). Pass when on, N/A when
|
|
545
|
+
// not set — most teams correctly stick with the cheaper standard mode.
|
|
423
546
|
check: (ctx) => {
|
|
424
547
|
const config = configContent(ctx);
|
|
425
548
|
if (!config) return null;
|
|
426
|
-
|
|
549
|
+
if (/\barchitect\s*:\s*true\b/i.test(config)) return true;
|
|
550
|
+
return null;
|
|
427
551
|
},
|
|
428
552
|
impact: 'high',
|
|
429
553
|
rating: 4,
|
|
@@ -437,7 +561,12 @@ const AIDER_TECHNIQUES = {
|
|
|
437
561
|
aiderModelSettingsFileExists: {
|
|
438
562
|
id: 'AD-C04',
|
|
439
563
|
name: '.aider.model.settings.yml exists for model customization',
|
|
440
|
-
|
|
564
|
+
// PP-04: model settings file is opt-in advanced customization. N/A when no
|
|
565
|
+
// .aider.conf.yml — there's no signal the team is using Aider intentionally.
|
|
566
|
+
check: (ctx) => {
|
|
567
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
568
|
+
return hasAiderModelSettings(ctx);
|
|
569
|
+
},
|
|
441
570
|
impact: 'medium',
|
|
442
571
|
rating: 3,
|
|
443
572
|
category: 'model-config',
|
|
@@ -468,10 +597,13 @@ const AIDER_TECHNIQUES = {
|
|
|
468
597
|
aiderCachePromptsEnabled: {
|
|
469
598
|
id: 'AD-C06',
|
|
470
599
|
name: 'Prompt caching enabled for cost savings',
|
|
600
|
+
// PP-04: Cost optimisation. Pass when explicitly on, N/A when not — only
|
|
601
|
+
// some providers/models support prompt caching, so absence is not a defect.
|
|
471
602
|
check: (ctx) => {
|
|
472
603
|
const config = configContent(ctx);
|
|
473
604
|
if (!config) return null;
|
|
474
|
-
|
|
605
|
+
if (/\bcache-prompts\s*:\s*true\b/i.test(config)) return true;
|
|
606
|
+
return null;
|
|
475
607
|
},
|
|
476
608
|
impact: 'medium',
|
|
477
609
|
rating: 3,
|
|
@@ -526,7 +658,16 @@ const AIDER_TECHNIQUES = {
|
|
|
526
658
|
aiderConventionFileExists: {
|
|
527
659
|
id: 'AD-D01',
|
|
528
660
|
name: 'Convention file exists for Aider context',
|
|
529
|
-
check: (ctx) =>
|
|
661
|
+
check: (ctx) => {
|
|
662
|
+
// PP-04: AGENTS.md / CLAUDE.md / .ai/instructions.md / AIDER.md count as
|
|
663
|
+
// effective convention surfaces in real Aider repos — Aider users
|
|
664
|
+
// routinely use these files as their context bundle even though Aider
|
|
665
|
+
// itself does not auto-discover them. N/A when no Aider surface at all.
|
|
666
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
667
|
+
if (conventionFiles(ctx).length > 0) return true;
|
|
668
|
+
if (ctx.fileContent && (ctx.fileContent('AGENTS.md') || ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md') || ctx.fileContent('AIDER.md') || ctx.fileContent('.ai/instructions.md'))) return true;
|
|
669
|
+
return false;
|
|
670
|
+
},
|
|
530
671
|
impact: 'high',
|
|
531
672
|
rating: 4,
|
|
532
673
|
category: 'conventions',
|
|
@@ -556,11 +697,15 @@ const AIDER_TECHNIQUES = {
|
|
|
556
697
|
aiderConventionHasArchitecture: {
|
|
557
698
|
id: 'AD-D03',
|
|
558
699
|
name: 'Convention file includes architecture/structure section',
|
|
700
|
+
// PP-04: Architecture content commonly lives in ARCHITECTURE.md, README,
|
|
701
|
+
// AGENTS.md, or CLAUDE.md — not just CONVENTIONS.md. Widen source.
|
|
559
702
|
check: (ctx) => {
|
|
560
|
-
|
|
703
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
704
|
+
const content = docsBundle(ctx);
|
|
561
705
|
if (!content) return null;
|
|
562
|
-
return /##\s+(?:Architecture|Structure|Project Map|Directory)/i.test(content) ||
|
|
563
|
-
/```mermaid/i.test(content)
|
|
706
|
+
return /##\s+(?:Architecture|Structure|Project Map|Project Snapshot|Project Layout|Directory|Layout|Modules|Module Tiers|Components|Stack|Tech Stack|Overview|Tour)/i.test(content) ||
|
|
707
|
+
/```mermaid/i.test(content) ||
|
|
708
|
+
/\bproject\s+(?:layout|structure|snapshot)\b/i.test(content);
|
|
564
709
|
},
|
|
565
710
|
impact: 'high',
|
|
566
711
|
rating: 4,
|
|
@@ -574,10 +719,13 @@ const AIDER_TECHNIQUES = {
|
|
|
574
719
|
aiderConventionHasVerification: {
|
|
575
720
|
id: 'AD-D04',
|
|
576
721
|
name: 'Convention file includes verification commands',
|
|
722
|
+
// PP-04: Test/lint commands frequently live in README, CONTRIBUTING.md,
|
|
723
|
+
// AGENTS.md, or CLAUDE.md, not just CONVENTIONS.md. Widen source.
|
|
577
724
|
check: (ctx) => {
|
|
578
|
-
|
|
725
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
726
|
+
const content = docsBundle(ctx);
|
|
579
727
|
if (!content) return null;
|
|
580
|
-
return /\bnpm test\b|\bpnpm test\b|\byarn test\b|\bpytest\b|\bgo test\b|\bcargo test\b|\bmake test\b/i.test(content);
|
|
728
|
+
return /\bnpm (?:run )?test\b|\bpnpm test\b|\byarn test\b|\bpytest\b|\bgo test\b|\bcargo test\b|\bmake test\b|\bmvn test\b|\bgradle (?:test|check)\b|\brake test\b|\bdotnet test\b|\bswift test\b|\btox\b/i.test(content);
|
|
581
729
|
},
|
|
582
730
|
impact: 'high',
|
|
583
731
|
rating: 4,
|
|
@@ -666,7 +814,14 @@ const AIDER_TECHNIQUES = {
|
|
|
666
814
|
aiderAiderignoreExists: {
|
|
667
815
|
id: 'AD-E03',
|
|
668
816
|
name: '.aiderignore file exists for file filtering',
|
|
669
|
-
|
|
817
|
+
// PP-04: .aiderignore is a fully optional advanced filter. N/A unless the
|
|
818
|
+
// repo has an .aider.conf.yml (the strongest "we use Aider intentionally"
|
|
819
|
+
// signal). Most real Aider repos rely on .gitignore + repo-map and do not
|
|
820
|
+
// ship an .aiderignore.
|
|
821
|
+
check: (ctx) => {
|
|
822
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
823
|
+
return hasAiderignore(ctx);
|
|
824
|
+
},
|
|
670
825
|
impact: 'medium',
|
|
671
826
|
rating: 3,
|
|
672
827
|
category: 'architecture',
|
|
@@ -700,10 +855,13 @@ const AIDER_TECHNIQUES = {
|
|
|
700
855
|
aiderEnvInGitignore: {
|
|
701
856
|
id: 'AD-F01',
|
|
702
857
|
name: '.env file excluded from git',
|
|
858
|
+
// PP-04: Only meaningful when the team uses Aider (or any tool that loads
|
|
859
|
+
// .env). N/A when no Aider surface and no .env in the repo at all.
|
|
703
860
|
check: (ctx) => {
|
|
704
861
|
const gi = gitignoreContent(ctx);
|
|
862
|
+
if (!hasAnyAiderSurface(ctx) && !(ctx.fileContent && ctx.fileContent('.env'))) return null;
|
|
705
863
|
if (!gi) return false;
|
|
706
|
-
return /^\.env$/m.test(gi) || /^\.env\b/m.test(gi);
|
|
864
|
+
return /^\.env$/m.test(gi) || /^\.env\b/m.test(gi) || /^\*\.env$/m.test(gi);
|
|
707
865
|
},
|
|
708
866
|
impact: 'critical',
|
|
709
867
|
rating: 5,
|
|
@@ -868,11 +1026,25 @@ const AIDER_TECHNIQUES = {
|
|
|
868
1026
|
aiderGitHooksForPreCommit: {
|
|
869
1027
|
id: 'AD-G04',
|
|
870
1028
|
name: 'Git pre-commit hooks or CI gates for quality',
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1029
|
+
// PP-04: pre-commit hooks are opt-in. N/A when no Aider surface — and accept
|
|
1030
|
+
// CI-as-quality-gate (a workflow that runs lint/test on PR) as a valid
|
|
1031
|
+
// alternative to local pre-commit hooks.
|
|
1032
|
+
check: (ctx) => {
|
|
1033
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1034
|
+
if (
|
|
1035
|
+
Boolean(ctx.fileContent('.pre-commit-config.yaml')) ||
|
|
1036
|
+
Boolean(ctx.fileContent('.pre-commit-config.yml')) ||
|
|
874
1037
|
Boolean(ctx.fileContent('.husky/pre-commit')) ||
|
|
875
|
-
Boolean(ctx.fileContent('.lefthook.yml'))
|
|
1038
|
+
Boolean(ctx.fileContent('.lefthook.yml')) ||
|
|
1039
|
+
Boolean(ctx.fileContent('lefthook.yml'))
|
|
1040
|
+
) return true;
|
|
1041
|
+
// Accept CI-side quality gate as equivalent
|
|
1042
|
+
const workflows = ctx.workflowFiles ? ctx.workflowFiles() : [];
|
|
1043
|
+
for (const wf of workflows) {
|
|
1044
|
+
const content = ctx.fileContent(wf) || '';
|
|
1045
|
+
if (/\b(lint|test|check|format)\b/i.test(content) && /\bpull_request\b|\bon:\s*\[/i.test(content)) return true;
|
|
1046
|
+
}
|
|
1047
|
+
return false;
|
|
876
1048
|
},
|
|
877
1049
|
impact: 'high',
|
|
878
1050
|
rating: 4,
|
|
@@ -939,10 +1111,14 @@ const AIDER_TECHNIQUES = {
|
|
|
939
1111
|
aiderConventionHasCodingStandards: {
|
|
940
1112
|
id: 'AD-H01',
|
|
941
1113
|
name: 'Convention file has coding standards section',
|
|
1114
|
+
// PP-04: Widen source to docsBundle (AGENTS.md / CLAUDE.md / CONTRIBUTING
|
|
1115
|
+
// commonly host the coding-standards section).
|
|
942
1116
|
check: (ctx) => {
|
|
943
|
-
|
|
1117
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1118
|
+
const content = docsBundle(ctx);
|
|
944
1119
|
if (!content) return null;
|
|
945
|
-
return /##\s+(?:Coding|Style|Standards|Formatting|Conventions)/i.test(content)
|
|
1120
|
+
return /##\s+(?:Coding|Style|Standards|Formatting|Conventions|Guidelines|Code\s+Style|Hard constraints|Constraints|Platform conventions|Rules|Quick commands)/i.test(content) ||
|
|
1121
|
+
/\b(?:swift|rust|python|java|kotlin|go|typescript)\s+(?:and|\&)?\s*(?:platform\s+)?conventions?\b/i.test(content);
|
|
946
1122
|
},
|
|
947
1123
|
impact: 'high',
|
|
948
1124
|
rating: 4,
|
|
@@ -957,9 +1133,10 @@ const AIDER_TECHNIQUES = {
|
|
|
957
1133
|
id: 'AD-H02',
|
|
958
1134
|
name: 'Convention file covers error handling',
|
|
959
1135
|
check: (ctx) => {
|
|
960
|
-
|
|
1136
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1137
|
+
const content = docsBundle(ctx);
|
|
961
1138
|
if (!content) return null;
|
|
962
|
-
return /\berror\s+handling\b|\bexception\b|\btry[- ]catch\b|\bResult\s*<\b
|
|
1139
|
+
return /\berror\s+handling\b|\bexception\b|\btry[- ]catch\b|\bResult\s*<\b|\bpanic\b|\b\?\?\s+/i.test(content);
|
|
963
1140
|
},
|
|
964
1141
|
impact: 'medium',
|
|
965
1142
|
rating: 3,
|
|
@@ -974,9 +1151,11 @@ const AIDER_TECHNIQUES = {
|
|
|
974
1151
|
id: 'AD-H03',
|
|
975
1152
|
name: 'Convention file covers testing guidelines',
|
|
976
1153
|
check: (ctx) => {
|
|
977
|
-
|
|
1154
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1155
|
+
const content = docsBundle(ctx);
|
|
978
1156
|
if (!content) return null;
|
|
979
|
-
return /##\s+(?:Test|Testing)/i.test(content) ||
|
|
1157
|
+
return /##\s+(?:Test|Testing|Tests)/i.test(content) ||
|
|
1158
|
+
/\bunit test\b|\bintegration test\b|\btest coverage\b|\bend[- ]to[- ]end\b/i.test(content);
|
|
980
1159
|
},
|
|
981
1160
|
impact: 'high',
|
|
982
1161
|
rating: 4,
|
|
@@ -1047,7 +1226,16 @@ const AIDER_TECHNIQUES = {
|
|
|
1047
1226
|
aiderEnvFileExists: {
|
|
1048
1227
|
id: 'AD-M01',
|
|
1049
1228
|
name: '.env file exists with API configuration',
|
|
1050
|
-
|
|
1229
|
+
// PP-04: .env is conventionally gitignored — its absence in a public repo
|
|
1230
|
+
// is the secure default, not a finding. Accept .env.example/.sample/.template
|
|
1231
|
+
// as valid evidence the team documents their env-var contract. N/A unless
|
|
1232
|
+
// there is an actual .aider.conf.yml — without one we have no signal the
|
|
1233
|
+
// team is on Aider rather than just mentioning it in docs.
|
|
1234
|
+
check: (ctx) => {
|
|
1235
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1236
|
+
if (ctx.fileContent && ctx.fileContent('.env')) return true;
|
|
1237
|
+
return hasEnvExample(ctx);
|
|
1238
|
+
},
|
|
1051
1239
|
impact: 'high',
|
|
1052
1240
|
rating: 4,
|
|
1053
1241
|
category: 'advanced-config',
|
|
@@ -1060,10 +1248,20 @@ const AIDER_TECHNIQUES = {
|
|
|
1060
1248
|
aiderEnvHasApiKey: {
|
|
1061
1249
|
id: 'AD-M02',
|
|
1062
1250
|
name: '.env contains at least one API key',
|
|
1251
|
+
// PP-04: Already correctly N/A when no .env (committed). Also accept
|
|
1252
|
+
// .env.example/sample with placeholder keys as evidence the env contract
|
|
1253
|
+
// is documented (real .env is gitignored and won't be in the audit tree).
|
|
1063
1254
|
check: (ctx) => {
|
|
1064
1255
|
const env = envContent(ctx);
|
|
1065
|
-
if (
|
|
1066
|
-
|
|
1256
|
+
if (env) {
|
|
1257
|
+
return /\b(?:OPENAI_API_KEY|ANTHROPIC_API_KEY|OPENROUTER_API_KEY|DEEPSEEK_API_KEY|GEMINI_API_KEY|GROQ_API_KEY)\s*=/i.test(env);
|
|
1258
|
+
}
|
|
1259
|
+
// Fall back to an example file if no committed .env
|
|
1260
|
+
const example = (ctx.fileContent && (
|
|
1261
|
+
ctx.fileContent('.env.example') || ctx.fileContent('.env.sample') || ctx.fileContent('.env.template')
|
|
1262
|
+
)) || '';
|
|
1263
|
+
if (!example) return null;
|
|
1264
|
+
return /\b(?:OPENAI_API_KEY|ANTHROPIC_API_KEY|OPENROUTER_API_KEY|DEEPSEEK_API_KEY|GEMINI_API_KEY|GROQ_API_KEY)\s*=/i.test(example);
|
|
1067
1265
|
},
|
|
1068
1266
|
impact: 'high',
|
|
1069
1267
|
rating: 4,
|
|
@@ -1134,9 +1332,13 @@ const AIDER_TECHNIQUES = {
|
|
|
1134
1332
|
aiderBrowserModeForDocs: {
|
|
1135
1333
|
id: 'AD-N02',
|
|
1136
1334
|
name: 'Browser integration known (/web command)',
|
|
1335
|
+
// PP-04: low-impact awareness. N/A unless an .aider.conf.yml exists —
|
|
1336
|
+
// /web is an Aider-specific in-chat command, not a generic concern.
|
|
1137
1337
|
check: (ctx) => {
|
|
1138
|
-
|
|
1139
|
-
|
|
1338
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1339
|
+
const docs = docsBundle(ctx);
|
|
1340
|
+
if (!docs) return null;
|
|
1341
|
+
return /\b\/web\b|\bbrowser\s+(?:mode|docs)\b|\bbrowser\b.*\b\/web\b/i.test(docs);
|
|
1140
1342
|
},
|
|
1141
1343
|
impact: 'low',
|
|
1142
1344
|
rating: 2,
|
|
@@ -1150,11 +1352,13 @@ const AIDER_TECHNIQUES = {
|
|
|
1150
1352
|
aiderInChatCommandsDocumented: {
|
|
1151
1353
|
id: 'AD-N03',
|
|
1152
1354
|
name: 'Key in-chat commands documented in conventions',
|
|
1355
|
+
// PP-04: Aider-specific in-chat commands. N/A unless an .aider.conf.yml
|
|
1356
|
+
// exists. Widen content source to docsBundle.
|
|
1153
1357
|
check: (ctx) => {
|
|
1154
|
-
|
|
1358
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1359
|
+
const content = docsBundle(ctx);
|
|
1155
1360
|
if (!content) return null;
|
|
1156
|
-
|
|
1157
|
-
const commands = ['/add', '/drop', '/run', '/test', '/undo'];
|
|
1361
|
+
const commands = ['/add', '/drop', '/run', '/test', '/undo', '/web', '/ask', '/code'];
|
|
1158
1362
|
const found = commands.filter(cmd => content.includes(cmd));
|
|
1159
1363
|
return found.length >= 2;
|
|
1160
1364
|
},
|
|
@@ -1170,10 +1374,14 @@ const AIDER_TECHNIQUES = {
|
|
|
1170
1374
|
aiderVoiceModeAware: {
|
|
1171
1375
|
id: 'AD-N04',
|
|
1172
1376
|
name: 'Voice mode configuration known',
|
|
1377
|
+
// PP-04: Voice coding is a niche developer preference, not a project
|
|
1378
|
+
// requirement. Pass when documented, N/A otherwise (no team should be
|
|
1379
|
+
// penalised for not using voice coding).
|
|
1173
1380
|
check: (ctx) => {
|
|
1174
1381
|
const config = configContent(ctx);
|
|
1175
1382
|
if (!config) return null;
|
|
1176
|
-
|
|
1383
|
+
if (/\bvoice-language\s*:/i.test(config) || /\bvoice\b/i.test(docsBundle(ctx))) return true;
|
|
1384
|
+
return null;
|
|
1177
1385
|
},
|
|
1178
1386
|
impact: 'low',
|
|
1179
1387
|
rating: 2,
|
|
@@ -1187,11 +1395,13 @@ const AIDER_TECHNIQUES = {
|
|
|
1187
1395
|
aiderPlaywrightUrlScraping: {
|
|
1188
1396
|
id: 'AD-N05',
|
|
1189
1397
|
name: 'Playwright URL auto-scraping side effect is expected',
|
|
1398
|
+
// PP-04: Niche awareness advisory. N/A unless an .aider.conf.yml exists.
|
|
1190
1399
|
check: (ctx) => {
|
|
1191
|
-
|
|
1400
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1401
|
+
const docs = docsBundle(ctx);
|
|
1192
1402
|
const config = configContent(ctx);
|
|
1193
|
-
|
|
1194
|
-
return /playwright|url.*scrap|scrape.*url|auto.*fetch|web.*fetch/i.test(
|
|
1403
|
+
if (!docs && !config) return null;
|
|
1404
|
+
return /playwright|url.*scrap|scrape.*url|auto.*fetch|web.*fetch/i.test(docs) ||
|
|
1195
1405
|
/playwright|url.*scrap/i.test(config);
|
|
1196
1406
|
},
|
|
1197
1407
|
impact: 'medium',
|
|
@@ -1210,10 +1420,15 @@ const AIDER_TECHNIQUES = {
|
|
|
1210
1420
|
aiderEditorIntegrationDocumented: {
|
|
1211
1421
|
id: 'AD-O01',
|
|
1212
1422
|
name: 'Editor integration documented (VS Code, NeoVim, etc.)',
|
|
1423
|
+
// PP-04: Editor integration is a developer-local concern, not a project
|
|
1424
|
+
// requirement — it tells team members which editor plugins exist for
|
|
1425
|
+
// Aider, but absence is not a real defect. N/A unless the repo has a
|
|
1426
|
+
// .aider.conf.yml AND the docs already discuss tooling/setup.
|
|
1213
1427
|
check: (ctx) => {
|
|
1214
|
-
|
|
1428
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1429
|
+
const content = docsBundle(ctx);
|
|
1215
1430
|
if (!content) return null;
|
|
1216
|
-
return /\bvs\s*code\b|\bneovim\b|\bvim\b|\beditor\b/i.test(content);
|
|
1431
|
+
return /\bvs\s*code\b|\bneovim\b|\bvim\b|\bemacs\b|\bjetbrains\b|\bintellij\b|\bsublime\b|\beditor[- ]integration\b/i.test(content);
|
|
1217
1432
|
},
|
|
1218
1433
|
impact: 'low',
|
|
1219
1434
|
rating: 2,
|
|
@@ -1227,10 +1442,14 @@ const AIDER_TECHNIQUES = {
|
|
|
1227
1442
|
aiderWatchModeKnown: {
|
|
1228
1443
|
id: 'AD-O02',
|
|
1229
1444
|
name: 'Watch mode (--watch-files) documented or configured',
|
|
1445
|
+
// PP-04: Niche feature awareness. N/A when no Aider config — without
|
|
1446
|
+
// .aider.conf.yml there's no place watch-files would meaningfully live.
|
|
1230
1447
|
check: (ctx) => {
|
|
1448
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1231
1449
|
const config = configContent(ctx);
|
|
1232
|
-
if (
|
|
1233
|
-
|
|
1450
|
+
if (/\bwatch-files\s*:/i.test(config)) return true;
|
|
1451
|
+
const docs = docsBundle(ctx);
|
|
1452
|
+
return /\bwatch[- ]files\b|\b--watch\b/i.test(docs);
|
|
1234
1453
|
},
|
|
1235
1454
|
impact: 'medium',
|
|
1236
1455
|
rating: 3,
|
|
@@ -1244,11 +1463,11 @@ const AIDER_TECHNIQUES = {
|
|
|
1244
1463
|
aiderDarkModeConfigured: {
|
|
1245
1464
|
id: 'AD-O03',
|
|
1246
1465
|
name: 'Theme/dark mode configured for terminal',
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1466
|
+
// PP-04: Cosmetic preference; not meaningful as a project-level requirement.
|
|
1467
|
+
// Downgrade to N/A across the board (kept as a check so the catalog still
|
|
1468
|
+
// surfaces it, but it should not be a "fail" advisory on real repos —
|
|
1469
|
+
// theme is a developer-local preference, not a project artifact).
|
|
1470
|
+
check: () => null,
|
|
1252
1471
|
impact: 'low',
|
|
1253
1472
|
rating: 1,
|
|
1254
1473
|
category: 'editor-integration',
|
|
@@ -1282,11 +1501,18 @@ const AIDER_TECHNIQUES = {
|
|
|
1282
1501
|
aiderVersionPinned: {
|
|
1283
1502
|
id: 'AD-P01',
|
|
1284
1503
|
name: 'Aider version pinned in requirements or package manager',
|
|
1504
|
+
// PP-04: Aider is a Python package — pinning is only meaningful for Python
|
|
1505
|
+
// projects. Non-Python repos use Aider via a separate venv, not via their
|
|
1506
|
+
// own dependency manifest. N/A when the project isn't Python.
|
|
1285
1507
|
check: (ctx) => {
|
|
1508
|
+
if (!isPythonProject(ctx)) return null;
|
|
1509
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1286
1510
|
const req = ctx.fileContent('requirements.txt') || '';
|
|
1287
1511
|
const pipfile = ctx.fileContent('Pipfile') || '';
|
|
1288
1512
|
const pyproject = ctx.fileContent('pyproject.toml') || '';
|
|
1289
|
-
|
|
1513
|
+
const setupPy = ctx.fileContent('setup.py') || '';
|
|
1514
|
+
return /\baider-chat\b/i.test(req) || /\baider-chat\b/i.test(pipfile) ||
|
|
1515
|
+
/\baider-chat\b/i.test(pyproject) || /\baider-chat\b/i.test(setupPy);
|
|
1290
1516
|
},
|
|
1291
1517
|
impact: 'medium',
|
|
1292
1518
|
rating: 3,
|
|
@@ -1300,11 +1526,16 @@ const AIDER_TECHNIQUES = {
|
|
|
1300
1526
|
aiderAllConfigSurfacesPresent: {
|
|
1301
1527
|
id: 'AD-P02',
|
|
1302
1528
|
name: 'All essential Aider config surfaces present',
|
|
1529
|
+
// PP-04: .env is gitignored by convention; accept .env.example/sample as
|
|
1530
|
+
// evidence the env contract is documented. N/A unless an .aider.conf.yml
|
|
1531
|
+
// exists — otherwise this fails on every repo that mentions Aider in docs
|
|
1532
|
+
// but doesn't ship the full config triple.
|
|
1303
1533
|
check: (ctx) => {
|
|
1304
|
-
|
|
1305
|
-
const
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1534
|
+
if (!hasAiderConfig(ctx)) return null;
|
|
1535
|
+
const envFile = ctx.fileContent && ctx.fileContent('.env');
|
|
1536
|
+
const hasEnvSurface = Boolean(envFile) || hasEnvExample(ctx);
|
|
1537
|
+
const hasGitignore = Boolean(ctx.fileContent && ctx.fileContent('.gitignore'));
|
|
1538
|
+
return hasEnvSurface && hasGitignore;
|
|
1308
1539
|
},
|
|
1309
1540
|
impact: 'high',
|
|
1310
1541
|
rating: 4,
|
|
@@ -1318,10 +1549,13 @@ const AIDER_TECHNIQUES = {
|
|
|
1318
1549
|
aiderDocumentedWorkflow: {
|
|
1319
1550
|
id: 'AD-P03',
|
|
1320
1551
|
name: 'Aider workflow documented in README or conventions',
|
|
1552
|
+
// PP-04: Widen to the full docsBundle (README/CONTRIBUTING/CONVENTIONS/
|
|
1553
|
+
// AGENTS/CLAUDE/.ai/instructions). N/A when no Aider surface at all.
|
|
1321
1554
|
check: (ctx) => {
|
|
1322
|
-
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1555
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1556
|
+
const docs = docsBundle(ctx);
|
|
1557
|
+
if (!docs) return null;
|
|
1558
|
+
return /\baider\b/i.test(docs) || /\baider[- ]chat\b/i.test(docs);
|
|
1325
1559
|
},
|
|
1326
1560
|
impact: 'medium',
|
|
1327
1561
|
rating: 3,
|
|
@@ -1336,16 +1570,16 @@ const AIDER_TECHNIQUES = {
|
|
|
1336
1570
|
id: 'AD-P04',
|
|
1337
1571
|
name: 'No conflicting platform configs (CLAUDE.md, AGENTS.md) without awareness',
|
|
1338
1572
|
check: (ctx) => {
|
|
1339
|
-
|
|
1573
|
+
// PP-04: Multi-platform is the norm in 2026, not a defect. Widen the
|
|
1574
|
+
// awareness source to the full docsBundle (CLAUDE.md often mentions
|
|
1575
|
+
// Aider, AGENTS.md often mentions Claude, README often does both).
|
|
1576
|
+
const hasAider = hasAiderConfig(ctx);
|
|
1340
1577
|
const hasClaude = Boolean(ctx.fileContent('CLAUDE.md')) || Boolean(ctx.fileContent('.claude/CLAUDE.md'));
|
|
1341
1578
|
const hasCodex = Boolean(ctx.fileContent('AGENTS.md'));
|
|
1342
1579
|
if (!hasAider) return null;
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
return /\bmulti[- ]?platform\b|\bclaude\b|\bcodex\b/i.test(content);
|
|
1347
|
-
}
|
|
1348
|
-
return true;
|
|
1580
|
+
if (!hasClaude && !hasCodex) return true;
|
|
1581
|
+
const content = docsBundle(ctx);
|
|
1582
|
+
return /\bmulti[- ]?platform\b|\bclaude\b|\bcodex\b|\bagents?\.md\b|\baider\b/i.test(content);
|
|
1349
1583
|
},
|
|
1350
1584
|
impact: 'medium',
|
|
1351
1585
|
rating: 3,
|
|
@@ -1359,12 +1593,16 @@ const AIDER_TECHNIQUES = {
|
|
|
1359
1593
|
aiderModelCostAwareness: {
|
|
1360
1594
|
id: 'AD-P05',
|
|
1361
1595
|
name: 'Model cost awareness configured (cache-prompts or explicit model selection)',
|
|
1596
|
+
// PP-04: Cost optimisation. Pass when any cost-aware knob is set; N/A
|
|
1597
|
+
// when none are — the default is sensible for most teams.
|
|
1362
1598
|
check: (ctx) => {
|
|
1363
1599
|
const config = configContent(ctx);
|
|
1364
1600
|
if (!config) return null;
|
|
1365
|
-
|
|
1601
|
+
if (/\bcache-prompts\s*:\s*true\b/i.test(config) ||
|
|
1366
1602
|
/\bweak-model\s*:/i.test(config) ||
|
|
1367
|
-
/\beditor-model\s*:/i.test(config)
|
|
1603
|
+
/\beditor-model\s*:/i.test(config) ||
|
|
1604
|
+
/\bmodel\s*:/i.test(config)) return true;
|
|
1605
|
+
return null;
|
|
1368
1606
|
},
|
|
1369
1607
|
impact: 'medium',
|
|
1370
1608
|
rating: 3,
|
|
@@ -1378,10 +1616,17 @@ const AIDER_TECHNIQUES = {
|
|
|
1378
1616
|
aiderGitBranchStrategy: {
|
|
1379
1617
|
id: 'AD-P06',
|
|
1380
1618
|
name: 'Git branch strategy for Aider work',
|
|
1619
|
+
// PP-04: Branch strategy lives in CONTRIBUTING / README more often than
|
|
1620
|
+
// CONVENTIONS. Widen source. N/A unless any Aider surface exists — we
|
|
1621
|
+
// don't expect arbitrary repos to document Aider-specific branching.
|
|
1381
1622
|
check: (ctx) => {
|
|
1382
|
-
|
|
1623
|
+
if (!hasAnyAiderSurface(ctx)) return null;
|
|
1624
|
+
const content = docsBundle(ctx);
|
|
1383
1625
|
if (!content) return null;
|
|
1384
|
-
|
|
1626
|
+
// Either explicit aider+branch combo, or a documented branching workflow
|
|
1627
|
+
// (feature-branch / git-flow / trunk-based) is enough.
|
|
1628
|
+
if (/\baider\b/i.test(content) && /\bbranch\b/i.test(content)) return true;
|
|
1629
|
+
return /\bfeature[- ]branch\b|\bgit[- ]flow\b|\btrunk[- ]based\b|\bpull request\b.*\bbranch\b/i.test(content);
|
|
1385
1630
|
},
|
|
1386
1631
|
impact: 'medium',
|
|
1387
1632
|
rating: 3,
|