@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.
- package/CHANGELOG.md +181 -0
- package/LICENSE +21 -0
- package/README.md +447 -0
- package/bin/cli.js +749 -0
- package/content/case-study-template.md +91 -0
- package/content/claims-governance.md +37 -0
- package/content/claude-code/audit-repo/SKILL.md +20 -0
- package/content/claude-native-integration.md +60 -0
- package/content/devto-article.json +9 -0
- package/content/launch-posts.md +226 -0
- package/content/pilot-rollout-kit.md +30 -0
- package/content/release-checklist.md +31 -0
- package/package.json +53 -4
- package/src/activity.js +529 -0
- package/src/aider/activity.js +226 -0
- package/src/aider/config-parser.js +166 -0
- package/src/aider/context.js +158 -0
- package/src/aider/deep-review.js +316 -0
- package/src/aider/domain-packs.js +278 -0
- package/src/aider/freshness.js +168 -0
- package/src/aider/governance.js +253 -0
- package/src/aider/interactive.js +334 -0
- package/src/aider/mcp-packs.js +98 -0
- package/src/aider/patch.js +214 -0
- package/src/aider/plans.js +186 -0
- package/src/aider/premium.js +360 -0
- package/src/aider/setup.js +404 -0
- package/src/aider/techniques.js +1323 -0
- package/src/analyze.js +821 -0
- package/src/audit.js +1003 -0
- package/src/badge.js +13 -0
- package/src/benchmark.js +339 -0
- package/src/claudex-sync.json +7 -0
- package/src/codex/activity.js +324 -0
- package/src/codex/config-parser.js +183 -0
- package/src/codex/context.js +221 -0
- package/src/codex/deep-review.js +493 -0
- package/src/codex/domain-packs.js +372 -0
- package/src/codex/freshness.js +167 -0
- package/src/codex/governance.js +192 -0
- package/src/codex/interactive.js +618 -0
- package/src/codex/mcp-packs.js +660 -0
- package/src/codex/patch.js +209 -0
- package/src/codex/plans.js +251 -0
- package/src/codex/premium.js +614 -0
- package/src/codex/setup.js +603 -0
- package/src/codex/techniques.js +2649 -0
- package/src/context.js +272 -0
- package/src/copilot/activity.js +309 -0
- package/src/copilot/config-parser.js +226 -0
- package/src/copilot/context.js +197 -0
- package/src/copilot/deep-review.js +346 -0
- package/src/copilot/domain-packs.js +350 -0
- package/src/copilot/freshness.js +197 -0
- package/src/copilot/governance.js +222 -0
- package/src/copilot/interactive.js +406 -0
- package/src/copilot/mcp-packs.js +572 -0
- package/src/copilot/patch.js +238 -0
- package/src/copilot/plans.js +253 -0
- package/src/copilot/premium.js +450 -0
- package/src/copilot/setup.js +488 -0
- package/src/copilot/techniques.js +1822 -0
- package/src/cursor/activity.js +301 -0
- package/src/cursor/config-parser.js +265 -0
- package/src/cursor/context.js +236 -0
- package/src/cursor/deep-review.js +334 -0
- package/src/cursor/domain-packs.js +346 -0
- package/src/cursor/freshness.js +214 -0
- package/src/cursor/governance.js +229 -0
- package/src/cursor/interactive.js +391 -0
- package/src/cursor/mcp-packs.js +571 -0
- package/src/cursor/patch.js +243 -0
- package/src/cursor/plans.js +254 -0
- package/src/cursor/premium.js +468 -0
- package/src/cursor/setup.js +488 -0
- package/src/cursor/techniques.js +1786 -0
- package/src/deep-review.js +345 -0
- package/src/domain-packs.js +364 -0
- package/src/formatters/sarif.js +115 -0
- package/src/gemini/activity.js +402 -0
- package/src/gemini/config-parser.js +275 -0
- package/src/gemini/context.js +221 -0
- package/src/gemini/deep-review.js +559 -0
- package/src/gemini/domain-packs.js +371 -0
- package/src/gemini/freshness.js +204 -0
- package/src/gemini/governance.js +201 -0
- package/src/gemini/interactive.js +860 -0
- package/src/gemini/mcp-packs.js +658 -0
- package/src/gemini/patch.js +229 -0
- package/src/gemini/plans.js +269 -0
- package/src/gemini/premium.js +759 -0
- package/src/gemini/setup.js +692 -0
- package/src/gemini/techniques.js +2084 -0
- package/src/governance.js +523 -0
- package/src/harmony/advisor.js +383 -0
- package/src/harmony/audit.js +303 -0
- package/src/harmony/canon.js +444 -0
- package/src/harmony/cli.js +331 -0
- package/src/harmony/drift.js +401 -0
- package/src/harmony/governance.js +313 -0
- package/src/harmony/memory.js +238 -0
- package/src/harmony/sync.js +458 -0
- package/src/harmony/watch.js +336 -0
- package/src/index.js +256 -0
- package/src/insights.js +119 -0
- package/src/interactive.js +118 -0
- package/src/mcp-packs.js +597 -0
- package/src/opencode/activity.js +286 -0
- package/src/opencode/config-parser.js +109 -0
- package/src/opencode/context.js +247 -0
- package/src/opencode/deep-review.js +313 -0
- package/src/opencode/domain-packs.js +240 -0
- package/src/opencode/freshness.js +158 -0
- package/src/opencode/governance.js +159 -0
- package/src/opencode/interactive.js +392 -0
- package/src/opencode/mcp-packs.js +474 -0
- package/src/opencode/patch.js +184 -0
- package/src/opencode/plans.js +231 -0
- package/src/opencode/premium.js +413 -0
- package/src/opencode/setup.js +449 -0
- package/src/opencode/techniques.js +1713 -0
- package/src/plans.js +655 -0
- package/src/secret-patterns.js +30 -0
- package/src/setup.js +1274 -0
- package/src/synergy/adaptive.js +261 -0
- package/src/synergy/compensation.js +156 -0
- package/src/synergy/evidence.js +193 -0
- package/src/synergy/learning.js +184 -0
- package/src/synergy/patterns.js +227 -0
- package/src/synergy/ranking.js +83 -0
- package/src/synergy/report.js +163 -0
- package/src/synergy/routing.js +152 -0
- package/src/techniques.js +1354 -0
- package/src/watch.js +229 -0
- package/src/windsurf/activity.js +302 -0
- package/src/windsurf/config-parser.js +267 -0
- package/src/windsurf/context.js +249 -0
- package/src/windsurf/deep-review.js +337 -0
- package/src/windsurf/domain-packs.js +348 -0
- package/src/windsurf/freshness.js +215 -0
- package/src/windsurf/governance.js +231 -0
- package/src/windsurf/interactive.js +388 -0
- package/src/windsurf/mcp-packs.js +535 -0
- package/src/windsurf/patch.js +231 -0
- package/src/windsurf/plans.js +247 -0
- package/src/windsurf/premium.js +467 -0
- package/src/windsurf/setup.js +471 -0
- package/src/windsurf/techniques.js +1758 -0
|
@@ -0,0 +1,1323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aider Technique Database — 68 checks (AD-A01 through AD-P03)
|
|
3
|
+
*
|
|
4
|
+
* Aider is fundamentally different from IDE platforms:
|
|
5
|
+
* - Git-first CLI tool: git is the ONLY safety mechanism
|
|
6
|
+
* - No hooks, no MCP, no skills, no agents
|
|
7
|
+
* - Config: .aider.conf.yml (YAML), .aider.model.settings.yml, .env
|
|
8
|
+
* - 3 model roles: main (coding), editor (applying), weak (commit messages)
|
|
9
|
+
* - Architect mode (2-model workflow)
|
|
10
|
+
* - Convention files must be explicitly passed (no auto-discovery)
|
|
11
|
+
* - 4-level config precedence: env vars > CLI args > .aider.conf.yml > defaults
|
|
12
|
+
*
|
|
13
|
+
* Categories: Config(8), Git Safety(8), Model Config(8), Conventions(6),
|
|
14
|
+
* Architecture(4), Security(6), CI(4), Quality(6) + M/N/O/P expansion (18)
|
|
15
|
+
*
|
|
16
|
+
* Check ID prefix: AD-
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { containsEmbeddedSecret } = require('../secret-patterns');
|
|
20
|
+
|
|
21
|
+
const FILLER_PATTERNS = [
|
|
22
|
+
/\bbe helpful\b/i,
|
|
23
|
+
/\bbe accurate\b/i,
|
|
24
|
+
/\bbe concise\b/i,
|
|
25
|
+
/\balways do your best\b/i,
|
|
26
|
+
/\bmaintain high quality\b/i,
|
|
27
|
+
/\bwrite clean code\b/i,
|
|
28
|
+
/\bfollow best practices\b/i,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function configContent(ctx) {
|
|
32
|
+
return ctx.configContent ? (ctx.configContent() || '') : (ctx.fileContent('.aider.conf.yml') || '');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function envContent(ctx) {
|
|
36
|
+
return ctx.envContent ? (ctx.envContent() || '') : (ctx.fileContent('.env') || '');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function modelSettingsContent(ctx) {
|
|
40
|
+
return ctx.modelSettingsContent ? (ctx.modelSettingsContent() || '') : (ctx.fileContent('.aider.model.settings.yml') || '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function conventionFiles(ctx) {
|
|
44
|
+
return ctx.conventionFiles ? ctx.conventionFiles() : [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function conventionContent(ctx) {
|
|
48
|
+
const files = conventionFiles(ctx);
|
|
49
|
+
return files.map(f => ctx.fileContent(f) || '').join('\n');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function gitignoreContent(ctx) {
|
|
53
|
+
return ctx.gitignoreContent ? (ctx.gitignoreContent() || '') : (ctx.fileContent('.gitignore') || '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function hasGitRepo(ctx) {
|
|
57
|
+
return ctx.hasGitRepo ? ctx.hasGitRepo() : ctx.files.includes('.git/');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function modelRoles(ctx) {
|
|
61
|
+
if (ctx.modelRoles) return ctx.modelRoles();
|
|
62
|
+
const config = ctx.parsedConfig ? ctx.parsedConfig() : { ok: false, data: null };
|
|
63
|
+
const data = config.ok ? config.data : {};
|
|
64
|
+
return {
|
|
65
|
+
main: data.model || data['main-model'] || null,
|
|
66
|
+
editor: data['editor-model'] || null,
|
|
67
|
+
weak: data['weak-model'] || null,
|
|
68
|
+
architect: data.architect || false,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function firstLineMatching(text, matcher) {
|
|
73
|
+
const lines = text.split(/\r?\n/);
|
|
74
|
+
for (let index = 0; index < lines.length; index++) {
|
|
75
|
+
const line = lines[index];
|
|
76
|
+
if (typeof matcher === 'string' && line.includes(matcher)) return index + 1;
|
|
77
|
+
if (matcher instanceof RegExp && matcher.test(line)) { matcher.lastIndex = 0; return index + 1; }
|
|
78
|
+
if (typeof matcher === 'function' && matcher(line, index + 1)) return index + 1;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function findFillerLine(content) {
|
|
84
|
+
return firstLineMatching(content, (line) => FILLER_PATTERNS.some((pattern) => pattern.test(line)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function repoLooksRegulated(ctx) {
|
|
88
|
+
const filenames = ctx.files.join('\n');
|
|
89
|
+
const packageJson = ctx.fileContent('package.json') || '';
|
|
90
|
+
const readme = ctx.fileContent('README.md') || '';
|
|
91
|
+
const combined = `${filenames}\n${packageJson}\n${readme}`;
|
|
92
|
+
return /\bhipaa\b|\bphi\b|\bpci\b|\bsoc2\b|\biso[- ]?27001\b|\bcompliance\b|\bhealth(?:care)?\b|\bmedical\b|\bbank(?:ing)?\b|\bpayments?\b|\bfintech\b/i.test(combined);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// 68 AIDER TECHNIQUES
|
|
97
|
+
// ============================================================================
|
|
98
|
+
|
|
99
|
+
const AIDER_TECHNIQUES = {
|
|
100
|
+
|
|
101
|
+
// =========================================================================
|
|
102
|
+
// A — Config (8 checks: AD-A01 .. AD-A08)
|
|
103
|
+
// =========================================================================
|
|
104
|
+
|
|
105
|
+
aiderConfYmlExists: {
|
|
106
|
+
id: 'AD-A01',
|
|
107
|
+
name: '.aider.conf.yml config file exists',
|
|
108
|
+
check: (ctx) => Boolean(ctx.fileContent('.aider.conf.yml')),
|
|
109
|
+
impact: 'critical',
|
|
110
|
+
rating: 5,
|
|
111
|
+
category: 'config',
|
|
112
|
+
fix: 'Create .aider.conf.yml with project-specific Aider settings.',
|
|
113
|
+
template: 'aider-conf-yml',
|
|
114
|
+
file: () => '.aider.conf.yml',
|
|
115
|
+
line: () => null,
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
aiderConfYmlValid: {
|
|
119
|
+
id: 'AD-A02',
|
|
120
|
+
name: '.aider.conf.yml is valid YAML',
|
|
121
|
+
check: (ctx) => {
|
|
122
|
+
const content = configContent(ctx);
|
|
123
|
+
if (!content) return null;
|
|
124
|
+
const parsed = ctx.parsedConfig ? ctx.parsedConfig() : require('./config-parser').tryParseYaml(content);
|
|
125
|
+
return parsed.ok;
|
|
126
|
+
},
|
|
127
|
+
impact: 'critical',
|
|
128
|
+
rating: 5,
|
|
129
|
+
category: 'config',
|
|
130
|
+
fix: 'Fix YAML syntax errors in .aider.conf.yml.',
|
|
131
|
+
template: 'aider-conf-yml',
|
|
132
|
+
file: () => '.aider.conf.yml',
|
|
133
|
+
line: () => null,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
aiderModelSpecified: {
|
|
137
|
+
id: 'AD-A03',
|
|
138
|
+
name: 'Main model explicitly configured',
|
|
139
|
+
check: (ctx) => {
|
|
140
|
+
const config = configContent(ctx);
|
|
141
|
+
if (!config) return null;
|
|
142
|
+
return /\bmodel\s*:/i.test(config) || /\bmain-model\s*:/i.test(config);
|
|
143
|
+
},
|
|
144
|
+
impact: 'high',
|
|
145
|
+
rating: 4,
|
|
146
|
+
category: 'config',
|
|
147
|
+
fix: 'Set `model:` in .aider.conf.yml to pin the main coding model.',
|
|
148
|
+
template: 'aider-conf-yml',
|
|
149
|
+
file: () => '.aider.conf.yml',
|
|
150
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /\bmodel\s*:|main-model\s*:/i),
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
aiderAutoCommitsConfigured: {
|
|
154
|
+
id: 'AD-A04',
|
|
155
|
+
name: 'Auto-commits setting is explicit',
|
|
156
|
+
check: (ctx) => {
|
|
157
|
+
const config = configContent(ctx);
|
|
158
|
+
if (!config) return null;
|
|
159
|
+
return /\bauto-commits\s*:/i.test(config);
|
|
160
|
+
},
|
|
161
|
+
impact: 'high',
|
|
162
|
+
rating: 4,
|
|
163
|
+
category: 'config',
|
|
164
|
+
fix: 'Set `auto-commits: true` in .aider.conf.yml to ensure git safety.',
|
|
165
|
+
template: 'aider-conf-yml',
|
|
166
|
+
file: () => '.aider.conf.yml',
|
|
167
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /auto-commits\s*:/i),
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
aiderMapTokensConfigured: {
|
|
171
|
+
id: 'AD-A05',
|
|
172
|
+
name: 'Map tokens setting is configured',
|
|
173
|
+
check: (ctx) => {
|
|
174
|
+
const config = configContent(ctx);
|
|
175
|
+
if (!config) return null;
|
|
176
|
+
return /\bmap-tokens\s*:/i.test(config);
|
|
177
|
+
},
|
|
178
|
+
impact: 'medium',
|
|
179
|
+
rating: 3,
|
|
180
|
+
category: 'config',
|
|
181
|
+
fix: 'Set `map-tokens:` in .aider.conf.yml to control repo map size.',
|
|
182
|
+
template: 'aider-conf-yml',
|
|
183
|
+
file: () => '.aider.conf.yml',
|
|
184
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /map-tokens\s*:/i),
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
aiderLintCmdConfigured: {
|
|
188
|
+
id: 'AD-A06',
|
|
189
|
+
name: 'Lint command configured for auto-fix',
|
|
190
|
+
check: (ctx) => {
|
|
191
|
+
const config = configContent(ctx);
|
|
192
|
+
if (!config) return null;
|
|
193
|
+
return /\blint-cmd\s*:/i.test(config);
|
|
194
|
+
},
|
|
195
|
+
impact: 'high',
|
|
196
|
+
rating: 4,
|
|
197
|
+
category: 'config',
|
|
198
|
+
fix: 'Set `lint-cmd:` in .aider.conf.yml so Aider can auto-fix lint errors.',
|
|
199
|
+
template: 'aider-conf-yml',
|
|
200
|
+
file: () => '.aider.conf.yml',
|
|
201
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /lint-cmd\s*:/i),
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
aiderTestCmdConfigured: {
|
|
205
|
+
id: 'AD-A07',
|
|
206
|
+
name: 'Test command configured for auto-fix',
|
|
207
|
+
check: (ctx) => {
|
|
208
|
+
const config = configContent(ctx);
|
|
209
|
+
if (!config) return null;
|
|
210
|
+
return /\btest-cmd\s*:/i.test(config);
|
|
211
|
+
},
|
|
212
|
+
impact: 'high',
|
|
213
|
+
rating: 4,
|
|
214
|
+
category: 'config',
|
|
215
|
+
fix: 'Set `test-cmd:` in .aider.conf.yml so Aider can run and auto-fix tests.',
|
|
216
|
+
template: 'aider-conf-yml',
|
|
217
|
+
file: () => '.aider.conf.yml',
|
|
218
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /test-cmd\s*:/i),
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
aiderEditFormatConfigured: {
|
|
222
|
+
id: 'AD-A08',
|
|
223
|
+
name: 'Edit format explicitly set',
|
|
224
|
+
check: (ctx) => {
|
|
225
|
+
const config = configContent(ctx);
|
|
226
|
+
if (!config) return null;
|
|
227
|
+
return /\bedit-format\s*:/i.test(config);
|
|
228
|
+
},
|
|
229
|
+
impact: 'medium',
|
|
230
|
+
rating: 3,
|
|
231
|
+
category: 'config',
|
|
232
|
+
fix: 'Set `edit-format:` (diff, whole, udiff, diff-fenced) in .aider.conf.yml for predictable edits.',
|
|
233
|
+
template: 'aider-conf-yml',
|
|
234
|
+
file: () => '.aider.conf.yml',
|
|
235
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /edit-format\s*:/i),
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// =========================================================================
|
|
239
|
+
// B — Git Safety (8 checks: AD-B01 .. AD-B08)
|
|
240
|
+
// =========================================================================
|
|
241
|
+
|
|
242
|
+
aiderGitRepoExists: {
|
|
243
|
+
id: 'AD-B01',
|
|
244
|
+
name: 'Project is a git repository',
|
|
245
|
+
check: (ctx) => hasGitRepo(ctx),
|
|
246
|
+
impact: 'critical',
|
|
247
|
+
rating: 5,
|
|
248
|
+
category: 'git-safety',
|
|
249
|
+
fix: 'Initialize a git repo with `git init`. Aider requires git as its ONLY safety mechanism.',
|
|
250
|
+
template: null,
|
|
251
|
+
file: () => '.git',
|
|
252
|
+
line: () => null,
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
aiderAutoCommitsEnabled: {
|
|
256
|
+
id: 'AD-B02',
|
|
257
|
+
name: 'Auto-commits not disabled (git safety)',
|
|
258
|
+
check: (ctx) => {
|
|
259
|
+
const config = configContent(ctx);
|
|
260
|
+
if (!config) return null;
|
|
261
|
+
// Failing = auto-commits explicitly set to false
|
|
262
|
+
if (/\bauto-commits\s*:\s*false\b/i.test(config)) return false;
|
|
263
|
+
return true;
|
|
264
|
+
},
|
|
265
|
+
impact: 'critical',
|
|
266
|
+
rating: 5,
|
|
267
|
+
category: 'git-safety',
|
|
268
|
+
fix: 'Do not set `auto-commits: false` — git commits are Aider\'s primary safety mechanism.',
|
|
269
|
+
template: 'aider-conf-yml',
|
|
270
|
+
file: () => '.aider.conf.yml',
|
|
271
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /auto-commits\s*:\s*false/i),
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
aiderGitignoreCoversArtifacts: {
|
|
275
|
+
id: 'AD-B03',
|
|
276
|
+
name: '.gitignore includes .aider* artifacts',
|
|
277
|
+
check: (ctx) => {
|
|
278
|
+
const gi = gitignoreContent(ctx);
|
|
279
|
+
if (!gi) return false;
|
|
280
|
+
return /\.aider/i.test(gi);
|
|
281
|
+
},
|
|
282
|
+
impact: 'high',
|
|
283
|
+
rating: 4,
|
|
284
|
+
category: 'git-safety',
|
|
285
|
+
fix: 'Add `.aider*` to .gitignore to exclude chat history and cache files.',
|
|
286
|
+
template: 'gitignore',
|
|
287
|
+
file: () => '.gitignore',
|
|
288
|
+
line: (ctx) => firstLineMatching(gitignoreContent(ctx), /\.aider/i),
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
aiderDirtyTreeCheck: {
|
|
292
|
+
id: 'AD-B04',
|
|
293
|
+
name: 'No uncommitted changes when starting Aider (advisory)',
|
|
294
|
+
check: (ctx) => {
|
|
295
|
+
const status = ctx.gitStatus ? ctx.gitStatus() : null;
|
|
296
|
+
if (status === null) return null; // Can't check
|
|
297
|
+
return status === '';
|
|
298
|
+
},
|
|
299
|
+
impact: 'medium',
|
|
300
|
+
rating: 3,
|
|
301
|
+
category: 'git-safety',
|
|
302
|
+
fix: 'Commit or stash changes before running Aider so its auto-commits stay clean.',
|
|
303
|
+
template: null,
|
|
304
|
+
file: () => null,
|
|
305
|
+
line: () => null,
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
aiderDirtyCommitsNotDisabled: {
|
|
309
|
+
id: 'AD-B05',
|
|
310
|
+
name: 'Dirty-commits not disabled',
|
|
311
|
+
check: (ctx) => {
|
|
312
|
+
const config = configContent(ctx);
|
|
313
|
+
if (!config) return null;
|
|
314
|
+
if (/\bdirty-commits\s*:\s*false\b/i.test(config)) return false;
|
|
315
|
+
return true;
|
|
316
|
+
},
|
|
317
|
+
impact: 'medium',
|
|
318
|
+
rating: 3,
|
|
319
|
+
category: 'git-safety',
|
|
320
|
+
fix: 'Keep `dirty-commits` enabled (default) so Aider can commit even with dirty working tree.',
|
|
321
|
+
template: 'aider-conf-yml',
|
|
322
|
+
file: () => '.aider.conf.yml',
|
|
323
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /dirty-commits\s*:\s*false/i),
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
aiderAttributeAuthorConfigured: {
|
|
327
|
+
id: 'AD-B06',
|
|
328
|
+
name: 'Attribute author/committer set for traceability',
|
|
329
|
+
check: (ctx) => {
|
|
330
|
+
const config = configContent(ctx);
|
|
331
|
+
if (!config) return null;
|
|
332
|
+
return /\battribute-author\s*:/i.test(config) || /\battribute-committer\s*:/i.test(config);
|
|
333
|
+
},
|
|
334
|
+
impact: 'medium',
|
|
335
|
+
rating: 3,
|
|
336
|
+
category: 'git-safety',
|
|
337
|
+
fix: 'Set `attribute-author: true` or `attribute-committer: true` for AI-change traceability.',
|
|
338
|
+
template: 'aider-conf-yml',
|
|
339
|
+
file: () => '.aider.conf.yml',
|
|
340
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /attribute-(?:author|committer)\s*:/i),
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
aiderCommitPrefixConfigured: {
|
|
344
|
+
id: 'AD-B07',
|
|
345
|
+
name: 'Commit prefix set for AI-authored commits',
|
|
346
|
+
check: (ctx) => {
|
|
347
|
+
const config = configContent(ctx);
|
|
348
|
+
if (!config) return null;
|
|
349
|
+
return /\baider-commit-prefix\s*:/i.test(config) || /\bcommit-prefix\s*:/i.test(config);
|
|
350
|
+
},
|
|
351
|
+
impact: 'low',
|
|
352
|
+
rating: 2,
|
|
353
|
+
category: 'git-safety',
|
|
354
|
+
fix: 'Set `aider-commit-prefix:` to tag AI-authored commits (e.g., "aider: ").',
|
|
355
|
+
template: 'aider-conf-yml',
|
|
356
|
+
file: () => '.aider.conf.yml',
|
|
357
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /commit-prefix\s*:/i),
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
aiderUndoSafetyAware: {
|
|
361
|
+
id: 'AD-B08',
|
|
362
|
+
name: '/undo command awareness documented',
|
|
363
|
+
check: (ctx) => {
|
|
364
|
+
const conventions = conventionContent(ctx);
|
|
365
|
+
const config = configContent(ctx);
|
|
366
|
+
return /\bundo\b/i.test(conventions) || /\bundo\b/i.test(config);
|
|
367
|
+
},
|
|
368
|
+
impact: 'low',
|
|
369
|
+
rating: 2,
|
|
370
|
+
category: 'git-safety',
|
|
371
|
+
fix: 'Document the /undo command in conventions for reverting Aider changes.',
|
|
372
|
+
template: 'aider-conventions',
|
|
373
|
+
file: () => null,
|
|
374
|
+
line: () => null,
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
// =========================================================================
|
|
378
|
+
// C — Model Config (8 checks: AD-C01 .. AD-C08)
|
|
379
|
+
// =========================================================================
|
|
380
|
+
|
|
381
|
+
aiderEditorModelConfigured: {
|
|
382
|
+
id: 'AD-C01',
|
|
383
|
+
name: 'Editor model explicitly configured',
|
|
384
|
+
check: (ctx) => {
|
|
385
|
+
const roles = modelRoles(ctx);
|
|
386
|
+
return roles.editor !== null;
|
|
387
|
+
},
|
|
388
|
+
impact: 'high',
|
|
389
|
+
rating: 4,
|
|
390
|
+
category: 'model-config',
|
|
391
|
+
fix: 'Set `editor-model:` in .aider.conf.yml for the model that applies edits.',
|
|
392
|
+
template: 'aider-conf-yml',
|
|
393
|
+
file: () => '.aider.conf.yml',
|
|
394
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /editor-model\s*:/i),
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
aiderWeakModelConfigured: {
|
|
398
|
+
id: 'AD-C02',
|
|
399
|
+
name: 'Weak model configured for commit messages',
|
|
400
|
+
check: (ctx) => {
|
|
401
|
+
const roles = modelRoles(ctx);
|
|
402
|
+
return roles.weak !== null;
|
|
403
|
+
},
|
|
404
|
+
impact: 'medium',
|
|
405
|
+
rating: 3,
|
|
406
|
+
category: 'model-config',
|
|
407
|
+
fix: 'Set `weak-model:` in .aider.conf.yml for cheap commit message generation.',
|
|
408
|
+
template: 'aider-conf-yml',
|
|
409
|
+
file: () => '.aider.conf.yml',
|
|
410
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /weak-model\s*:/i),
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
aiderArchitectModeAvailable: {
|
|
414
|
+
id: 'AD-C03',
|
|
415
|
+
name: 'Architect mode configured (2-model workflow)',
|
|
416
|
+
check: (ctx) => {
|
|
417
|
+
const config = configContent(ctx);
|
|
418
|
+
if (!config) return null;
|
|
419
|
+
return /\barchitect\s*:\s*true\b/i.test(config);
|
|
420
|
+
},
|
|
421
|
+
impact: 'high',
|
|
422
|
+
rating: 4,
|
|
423
|
+
category: 'model-config',
|
|
424
|
+
fix: 'Set `architect: true` to use a 2-model workflow (architect plans, editor applies).',
|
|
425
|
+
template: 'aider-conf-yml',
|
|
426
|
+
file: () => '.aider.conf.yml',
|
|
427
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /architect\s*:/i),
|
|
428
|
+
},
|
|
429
|
+
|
|
430
|
+
aiderModelSettingsFileExists: {
|
|
431
|
+
id: 'AD-C04',
|
|
432
|
+
name: '.aider.model.settings.yml exists for model customization',
|
|
433
|
+
check: (ctx) => Boolean(ctx.fileContent('.aider.model.settings.yml')),
|
|
434
|
+
impact: 'medium',
|
|
435
|
+
rating: 3,
|
|
436
|
+
category: 'model-config',
|
|
437
|
+
fix: 'Create .aider.model.settings.yml for custom model definitions and aliases.',
|
|
438
|
+
template: 'aider-model-settings',
|
|
439
|
+
file: () => '.aider.model.settings.yml',
|
|
440
|
+
line: () => null,
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
aiderApiKeyInEnvNotConfig: {
|
|
444
|
+
id: 'AD-C05',
|
|
445
|
+
name: 'API keys in .env, not in .aider.conf.yml',
|
|
446
|
+
check: (ctx) => {
|
|
447
|
+
const config = configContent(ctx);
|
|
448
|
+
if (!config) return null;
|
|
449
|
+
// Fail if API keys are in the YAML config instead of .env
|
|
450
|
+
return !/\b(?:api[_-]?key|openai[_-]?api[_-]?key|anthropic[_-]?api[_-]?key)\s*:/i.test(config);
|
|
451
|
+
},
|
|
452
|
+
impact: 'critical',
|
|
453
|
+
rating: 5,
|
|
454
|
+
category: 'model-config',
|
|
455
|
+
fix: 'Move API keys to .env file, not .aider.conf.yml which may be committed.',
|
|
456
|
+
template: 'aider-env',
|
|
457
|
+
file: () => '.aider.conf.yml',
|
|
458
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /api[_-]?key\s*:/i),
|
|
459
|
+
},
|
|
460
|
+
|
|
461
|
+
aiderCachePromptsEnabled: {
|
|
462
|
+
id: 'AD-C06',
|
|
463
|
+
name: 'Prompt caching enabled for cost savings',
|
|
464
|
+
check: (ctx) => {
|
|
465
|
+
const config = configContent(ctx);
|
|
466
|
+
if (!config) return null;
|
|
467
|
+
return /\bcache-prompts\s*:\s*true\b/i.test(config);
|
|
468
|
+
},
|
|
469
|
+
impact: 'medium',
|
|
470
|
+
rating: 3,
|
|
471
|
+
category: 'model-config',
|
|
472
|
+
fix: 'Set `cache-prompts: true` in .aider.conf.yml to reduce API costs.',
|
|
473
|
+
template: 'aider-conf-yml',
|
|
474
|
+
file: () => '.aider.conf.yml',
|
|
475
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /cache-prompts\s*:/i),
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
aiderMaxChatHistoryReasonable: {
|
|
479
|
+
id: 'AD-C07',
|
|
480
|
+
name: 'Max chat history tokens is bounded',
|
|
481
|
+
check: (ctx) => {
|
|
482
|
+
const config = configContent(ctx);
|
|
483
|
+
if (!config) return null;
|
|
484
|
+
const match = config.match(/\bmax-chat-history-tokens\s*:\s*(\d+)/i);
|
|
485
|
+
if (!match) return null; // Not set, using default
|
|
486
|
+
return Number.parseInt(match[1], 10) <= 32768;
|
|
487
|
+
},
|
|
488
|
+
impact: 'low',
|
|
489
|
+
rating: 2,
|
|
490
|
+
category: 'model-config',
|
|
491
|
+
fix: 'Set `max-chat-history-tokens` to a reasonable limit (e.g., 16384) to control costs.',
|
|
492
|
+
template: 'aider-conf-yml',
|
|
493
|
+
file: () => '.aider.conf.yml',
|
|
494
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /max-chat-history-tokens\s*:/i),
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
aiderStreamEnabled: {
|
|
498
|
+
id: 'AD-C08',
|
|
499
|
+
name: 'Streaming not disabled',
|
|
500
|
+
check: (ctx) => {
|
|
501
|
+
const config = configContent(ctx);
|
|
502
|
+
if (!config) return null;
|
|
503
|
+
if (/\bno-stream\s*:\s*true\b/i.test(config) || /\bstream\s*:\s*false\b/i.test(config)) return false;
|
|
504
|
+
return true;
|
|
505
|
+
},
|
|
506
|
+
impact: 'low',
|
|
507
|
+
rating: 2,
|
|
508
|
+
category: 'model-config',
|
|
509
|
+
fix: 'Keep streaming enabled for better developer experience.',
|
|
510
|
+
template: 'aider-conf-yml',
|
|
511
|
+
file: () => '.aider.conf.yml',
|
|
512
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /no-stream\s*:\s*true|stream\s*:\s*false/i),
|
|
513
|
+
},
|
|
514
|
+
|
|
515
|
+
// =========================================================================
|
|
516
|
+
// D — Conventions (6 checks: AD-D01 .. AD-D06)
|
|
517
|
+
// =========================================================================
|
|
518
|
+
|
|
519
|
+
aiderConventionFileExists: {
|
|
520
|
+
id: 'AD-D01',
|
|
521
|
+
name: 'Convention file exists for Aider context',
|
|
522
|
+
check: (ctx) => conventionFiles(ctx).length > 0,
|
|
523
|
+
impact: 'high',
|
|
524
|
+
rating: 4,
|
|
525
|
+
category: 'conventions',
|
|
526
|
+
fix: 'Create CONVENTIONS.md with project coding standards and pass via `read:` in .aider.conf.yml.',
|
|
527
|
+
template: 'aider-conventions',
|
|
528
|
+
file: () => 'CONVENTIONS.md',
|
|
529
|
+
line: () => null,
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
aiderConventionLinkedInConfig: {
|
|
533
|
+
id: 'AD-D02',
|
|
534
|
+
name: 'Convention file referenced in .aider.conf.yml read list',
|
|
535
|
+
check: (ctx) => {
|
|
536
|
+
const config = configContent(ctx);
|
|
537
|
+
if (!config) return null;
|
|
538
|
+
return /\bread\s*:/i.test(config);
|
|
539
|
+
},
|
|
540
|
+
impact: 'high',
|
|
541
|
+
rating: 4,
|
|
542
|
+
category: 'conventions',
|
|
543
|
+
fix: 'Add `read: [CONVENTIONS.md]` to .aider.conf.yml — Aider has NO auto-discovery.',
|
|
544
|
+
template: 'aider-conf-yml',
|
|
545
|
+
file: () => '.aider.conf.yml',
|
|
546
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /read\s*:/i),
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
aiderConventionHasArchitecture: {
|
|
550
|
+
id: 'AD-D03',
|
|
551
|
+
name: 'Convention file includes architecture/structure section',
|
|
552
|
+
check: (ctx) => {
|
|
553
|
+
const content = conventionContent(ctx);
|
|
554
|
+
if (!content) return null;
|
|
555
|
+
return /##\s+(?:Architecture|Structure|Project Map|Directory)/i.test(content) ||
|
|
556
|
+
/```mermaid/i.test(content);
|
|
557
|
+
},
|
|
558
|
+
impact: 'high',
|
|
559
|
+
rating: 4,
|
|
560
|
+
category: 'conventions',
|
|
561
|
+
fix: 'Add a ## Architecture section with project structure to your convention file.',
|
|
562
|
+
template: 'aider-conventions',
|
|
563
|
+
file: () => 'CONVENTIONS.md',
|
|
564
|
+
line: () => null,
|
|
565
|
+
},
|
|
566
|
+
|
|
567
|
+
aiderConventionHasVerification: {
|
|
568
|
+
id: 'AD-D04',
|
|
569
|
+
name: 'Convention file includes verification commands',
|
|
570
|
+
check: (ctx) => {
|
|
571
|
+
const content = conventionContent(ctx);
|
|
572
|
+
if (!content) return null;
|
|
573
|
+
return /\bnpm test\b|\bpnpm test\b|\byarn test\b|\bpytest\b|\bgo test\b|\bcargo test\b|\bmake test\b/i.test(content);
|
|
574
|
+
},
|
|
575
|
+
impact: 'high',
|
|
576
|
+
rating: 4,
|
|
577
|
+
category: 'conventions',
|
|
578
|
+
fix: 'Add test/lint/build commands to your convention file for Aider to use.',
|
|
579
|
+
template: 'aider-conventions',
|
|
580
|
+
file: () => 'CONVENTIONS.md',
|
|
581
|
+
line: () => null,
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
aiderConventionNoFiller: {
|
|
585
|
+
id: 'AD-D05',
|
|
586
|
+
name: 'Convention file has no filler/platitude lines',
|
|
587
|
+
check: (ctx) => {
|
|
588
|
+
const content = conventionContent(ctx);
|
|
589
|
+
if (!content) return null;
|
|
590
|
+
return !findFillerLine(content);
|
|
591
|
+
},
|
|
592
|
+
impact: 'medium',
|
|
593
|
+
rating: 3,
|
|
594
|
+
category: 'conventions',
|
|
595
|
+
fix: 'Remove generic filler like "be helpful" — use specific, actionable instructions.',
|
|
596
|
+
template: 'aider-conventions',
|
|
597
|
+
file: () => 'CONVENTIONS.md',
|
|
598
|
+
line: (ctx) => findFillerLine(conventionContent(ctx)),
|
|
599
|
+
},
|
|
600
|
+
|
|
601
|
+
aiderConventionReasonableSize: {
|
|
602
|
+
id: 'AD-D06',
|
|
603
|
+
name: 'Convention file not excessively large',
|
|
604
|
+
check: (ctx) => {
|
|
605
|
+
const content = conventionContent(ctx);
|
|
606
|
+
if (!content) return null;
|
|
607
|
+
return content.length < 32768;
|
|
608
|
+
},
|
|
609
|
+
impact: 'medium',
|
|
610
|
+
rating: 3,
|
|
611
|
+
category: 'conventions',
|
|
612
|
+
fix: 'Keep convention files under 32KB — large files consume context tokens.',
|
|
613
|
+
template: 'aider-conventions',
|
|
614
|
+
file: () => 'CONVENTIONS.md',
|
|
615
|
+
line: () => null,
|
|
616
|
+
},
|
|
617
|
+
|
|
618
|
+
// =========================================================================
|
|
619
|
+
// E — Architecture (4 checks: AD-E01 .. AD-E04)
|
|
620
|
+
// =========================================================================
|
|
621
|
+
|
|
622
|
+
aiderRepoMapEnabled: {
|
|
623
|
+
id: 'AD-E01',
|
|
624
|
+
name: 'Repo map not disabled',
|
|
625
|
+
check: (ctx) => {
|
|
626
|
+
const config = configContent(ctx);
|
|
627
|
+
if (!config) return null;
|
|
628
|
+
if (/\bmap-tokens\s*:\s*0\b/i.test(config) || /\bno-repo-map\s*:\s*true\b/i.test(config)) return false;
|
|
629
|
+
return true;
|
|
630
|
+
},
|
|
631
|
+
impact: 'high',
|
|
632
|
+
rating: 4,
|
|
633
|
+
category: 'architecture',
|
|
634
|
+
fix: 'Do not disable repo map — it gives Aider critical project structure awareness.',
|
|
635
|
+
template: 'aider-conf-yml',
|
|
636
|
+
file: () => '.aider.conf.yml',
|
|
637
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /map-tokens\s*:\s*0|no-repo-map\s*:\s*true/i),
|
|
638
|
+
},
|
|
639
|
+
|
|
640
|
+
aiderSubtreeUsedForLargeRepos: {
|
|
641
|
+
id: 'AD-E02',
|
|
642
|
+
name: 'Subtree-only or file filtering for large repos',
|
|
643
|
+
check: (ctx) => {
|
|
644
|
+
// Only relevant for large repos
|
|
645
|
+
if (ctx.files.length < 100) return null;
|
|
646
|
+
const config = configContent(ctx);
|
|
647
|
+
if (!config) return null;
|
|
648
|
+
return /\bsubtree-only\s*:\s*true\b/i.test(config) || /\bmap-tokens\s*:/i.test(config);
|
|
649
|
+
},
|
|
650
|
+
impact: 'medium',
|
|
651
|
+
rating: 3,
|
|
652
|
+
category: 'architecture',
|
|
653
|
+
fix: 'Use `subtree-only: true` or limit `map-tokens` for large repositories.',
|
|
654
|
+
template: 'aider-conf-yml',
|
|
655
|
+
file: () => '.aider.conf.yml',
|
|
656
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /subtree-only\s*:|map-tokens\s*:/i),
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
aiderAiderignoreExists: {
|
|
660
|
+
id: 'AD-E03',
|
|
661
|
+
name: '.aiderignore file exists for file filtering',
|
|
662
|
+
check: (ctx) => Boolean(ctx.fileContent('.aiderignore')),
|
|
663
|
+
impact: 'medium',
|
|
664
|
+
rating: 3,
|
|
665
|
+
category: 'architecture',
|
|
666
|
+
fix: 'Create .aiderignore to exclude files Aider should not edit (similar to .gitignore syntax).',
|
|
667
|
+
template: 'aiderignore',
|
|
668
|
+
file: () => '.aiderignore',
|
|
669
|
+
line: () => null,
|
|
670
|
+
},
|
|
671
|
+
|
|
672
|
+
aiderAutoTestEnabled: {
|
|
673
|
+
id: 'AD-E04',
|
|
674
|
+
name: 'Auto-test enabled for verification loop',
|
|
675
|
+
check: (ctx) => {
|
|
676
|
+
const config = configContent(ctx);
|
|
677
|
+
if (!config) return null;
|
|
678
|
+
return /\bauto-test\s*:\s*true\b/i.test(config);
|
|
679
|
+
},
|
|
680
|
+
impact: 'high',
|
|
681
|
+
rating: 4,
|
|
682
|
+
category: 'architecture',
|
|
683
|
+
fix: 'Set `auto-test: true` with `test-cmd` to enable automatic test verification.',
|
|
684
|
+
template: 'aider-conf-yml',
|
|
685
|
+
file: () => '.aider.conf.yml',
|
|
686
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /auto-test\s*:/i),
|
|
687
|
+
},
|
|
688
|
+
|
|
689
|
+
// =========================================================================
|
|
690
|
+
// F — Security (6 checks: AD-F01 .. AD-F06)
|
|
691
|
+
// =========================================================================
|
|
692
|
+
|
|
693
|
+
aiderEnvInGitignore: {
|
|
694
|
+
id: 'AD-F01',
|
|
695
|
+
name: '.env file excluded from git',
|
|
696
|
+
check: (ctx) => {
|
|
697
|
+
const gi = gitignoreContent(ctx);
|
|
698
|
+
if (!gi) return false;
|
|
699
|
+
return /^\.env$/m.test(gi) || /^\.env\b/m.test(gi);
|
|
700
|
+
},
|
|
701
|
+
impact: 'critical',
|
|
702
|
+
rating: 5,
|
|
703
|
+
category: 'security',
|
|
704
|
+
fix: 'Add `.env` to .gitignore to prevent API key leaks.',
|
|
705
|
+
template: 'gitignore',
|
|
706
|
+
file: () => '.gitignore',
|
|
707
|
+
line: (ctx) => firstLineMatching(gitignoreContent(ctx), /^\.env/m),
|
|
708
|
+
},
|
|
709
|
+
|
|
710
|
+
aiderNoSecretsInConfig: {
|
|
711
|
+
id: 'AD-F02',
|
|
712
|
+
name: 'No embedded secrets in .aider.conf.yml',
|
|
713
|
+
check: (ctx) => {
|
|
714
|
+
const config = configContent(ctx);
|
|
715
|
+
if (!config) return null;
|
|
716
|
+
return !containsEmbeddedSecret(config);
|
|
717
|
+
},
|
|
718
|
+
impact: 'critical',
|
|
719
|
+
rating: 5,
|
|
720
|
+
category: 'security',
|
|
721
|
+
fix: 'Remove secrets from .aider.conf.yml — use .env or environment variables instead.',
|
|
722
|
+
template: 'aider-conf-yml',
|
|
723
|
+
file: () => '.aider.conf.yml',
|
|
724
|
+
line: () => null,
|
|
725
|
+
},
|
|
726
|
+
|
|
727
|
+
aiderNoSecretsInConventions: {
|
|
728
|
+
id: 'AD-F03',
|
|
729
|
+
name: 'No embedded secrets in convention files',
|
|
730
|
+
check: (ctx) => {
|
|
731
|
+
const content = conventionContent(ctx);
|
|
732
|
+
if (!content) return null;
|
|
733
|
+
return !containsEmbeddedSecret(content);
|
|
734
|
+
},
|
|
735
|
+
impact: 'critical',
|
|
736
|
+
rating: 5,
|
|
737
|
+
category: 'security',
|
|
738
|
+
fix: 'Remove secrets from convention files.',
|
|
739
|
+
template: 'aider-conventions',
|
|
740
|
+
file: () => 'CONVENTIONS.md',
|
|
741
|
+
line: () => null,
|
|
742
|
+
},
|
|
743
|
+
|
|
744
|
+
aiderChatHistoryExcluded: {
|
|
745
|
+
id: 'AD-F04',
|
|
746
|
+
name: 'Chat history files excluded from git',
|
|
747
|
+
check: (ctx) => {
|
|
748
|
+
const gi = gitignoreContent(ctx);
|
|
749
|
+
if (!gi) return false;
|
|
750
|
+
return /\.aider\.chat\.history/i.test(gi) || /\.aider\*/i.test(gi) || /\.aider/i.test(gi);
|
|
751
|
+
},
|
|
752
|
+
impact: 'high',
|
|
753
|
+
rating: 4,
|
|
754
|
+
category: 'security',
|
|
755
|
+
fix: 'Ensure .aider.chat.history.md is gitignored — it may contain sensitive context.',
|
|
756
|
+
template: 'gitignore',
|
|
757
|
+
file: () => '.gitignore',
|
|
758
|
+
line: (ctx) => firstLineMatching(gitignoreContent(ctx), /\.aider/i),
|
|
759
|
+
},
|
|
760
|
+
|
|
761
|
+
aiderRegulatedRepoHasGuardrails: {
|
|
762
|
+
id: 'AD-F05',
|
|
763
|
+
name: 'Regulated repo has explicit guardrails in conventions',
|
|
764
|
+
check: (ctx) => {
|
|
765
|
+
if (!repoLooksRegulated(ctx)) return null;
|
|
766
|
+
const content = conventionContent(ctx);
|
|
767
|
+
if (!content) return false;
|
|
768
|
+
return /\bsecurity\b|\bcompliance\b|\breview\b|\bapproval\b/i.test(content);
|
|
769
|
+
},
|
|
770
|
+
impact: 'high',
|
|
771
|
+
rating: 4,
|
|
772
|
+
category: 'security',
|
|
773
|
+
fix: 'Add security and compliance guardrails to convention files for regulated repos.',
|
|
774
|
+
template: 'aider-conventions',
|
|
775
|
+
file: () => 'CONVENTIONS.md',
|
|
776
|
+
line: () => null,
|
|
777
|
+
},
|
|
778
|
+
|
|
779
|
+
aiderNoAutoRunInUntrusted: {
|
|
780
|
+
id: 'AD-F06',
|
|
781
|
+
name: 'Auto-run commands not enabled in untrusted context',
|
|
782
|
+
check: (ctx) => {
|
|
783
|
+
const config = configContent(ctx);
|
|
784
|
+
if (!config) return null;
|
|
785
|
+
// suggest-shell-commands with auto-run is risky
|
|
786
|
+
if (/\bauto-lint\s*:\s*true\b/i.test(config) && /\bauto-test\s*:\s*true\b/i.test(config)) {
|
|
787
|
+
// Both auto-lint and auto-test — check if commands are explicit
|
|
788
|
+
return /\blint-cmd\s*:/i.test(config) && /\btest-cmd\s*:/i.test(config);
|
|
789
|
+
}
|
|
790
|
+
return true;
|
|
791
|
+
},
|
|
792
|
+
impact: 'medium',
|
|
793
|
+
rating: 3,
|
|
794
|
+
category: 'security',
|
|
795
|
+
fix: 'When using auto-lint/auto-test, always specify explicit commands.',
|
|
796
|
+
template: 'aider-conf-yml',
|
|
797
|
+
file: () => '.aider.conf.yml',
|
|
798
|
+
line: () => null,
|
|
799
|
+
},
|
|
800
|
+
|
|
801
|
+
// =========================================================================
|
|
802
|
+
// G — CI (4 checks: AD-G01 .. AD-G04)
|
|
803
|
+
// =========================================================================
|
|
804
|
+
|
|
805
|
+
aiderCiWorkflowExists: {
|
|
806
|
+
id: 'AD-G01',
|
|
807
|
+
name: 'CI workflow exists',
|
|
808
|
+
check: (ctx) => {
|
|
809
|
+
const workflows = ctx.workflowFiles ? ctx.workflowFiles() : [];
|
|
810
|
+
return workflows.length > 0;
|
|
811
|
+
},
|
|
812
|
+
impact: 'high',
|
|
813
|
+
rating: 4,
|
|
814
|
+
category: 'ci',
|
|
815
|
+
fix: 'Add a CI workflow (.github/workflows/) to verify Aider-generated changes.',
|
|
816
|
+
template: 'aider-ci',
|
|
817
|
+
file: () => '.github/workflows/',
|
|
818
|
+
line: () => null,
|
|
819
|
+
},
|
|
820
|
+
|
|
821
|
+
aiderCiRunsTests: {
|
|
822
|
+
id: 'AD-G02',
|
|
823
|
+
name: 'CI runs tests on Aider PRs',
|
|
824
|
+
check: (ctx) => {
|
|
825
|
+
const workflows = ctx.workflowFiles ? ctx.workflowFiles() : [];
|
|
826
|
+
for (const wf of workflows) {
|
|
827
|
+
const content = ctx.fileContent(wf) || '';
|
|
828
|
+
if (/\btest\b/i.test(content) && /\bpull_request\b/i.test(content)) return true;
|
|
829
|
+
}
|
|
830
|
+
return workflows.length > 0 ? false : null;
|
|
831
|
+
},
|
|
832
|
+
impact: 'high',
|
|
833
|
+
rating: 4,
|
|
834
|
+
category: 'ci',
|
|
835
|
+
fix: 'Ensure CI runs tests on pull requests — Aider changes should be verified.',
|
|
836
|
+
template: 'aider-ci',
|
|
837
|
+
file: () => '.github/workflows/',
|
|
838
|
+
line: () => null,
|
|
839
|
+
},
|
|
840
|
+
|
|
841
|
+
aiderCiRunsLint: {
|
|
842
|
+
id: 'AD-G03',
|
|
843
|
+
name: 'CI runs linting',
|
|
844
|
+
check: (ctx) => {
|
|
845
|
+
const workflows = ctx.workflowFiles ? ctx.workflowFiles() : [];
|
|
846
|
+
for (const wf of workflows) {
|
|
847
|
+
const content = ctx.fileContent(wf) || '';
|
|
848
|
+
if (/\blint\b/i.test(content)) return true;
|
|
849
|
+
}
|
|
850
|
+
return workflows.length > 0 ? false : null;
|
|
851
|
+
},
|
|
852
|
+
impact: 'medium',
|
|
853
|
+
rating: 3,
|
|
854
|
+
category: 'ci',
|
|
855
|
+
fix: 'Add linting to CI to catch style issues in Aider-generated code.',
|
|
856
|
+
template: 'aider-ci',
|
|
857
|
+
file: () => '.github/workflows/',
|
|
858
|
+
line: () => null,
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
aiderGitHooksForPreCommit: {
|
|
862
|
+
id: 'AD-G04',
|
|
863
|
+
name: 'Git pre-commit hooks or CI gates for quality',
|
|
864
|
+
check: (ctx) => {
|
|
865
|
+
// Check for pre-commit config or husky
|
|
866
|
+
return Boolean(ctx.fileContent('.pre-commit-config.yaml')) ||
|
|
867
|
+
Boolean(ctx.fileContent('.husky/pre-commit')) ||
|
|
868
|
+
Boolean(ctx.fileContent('.lefthook.yml'));
|
|
869
|
+
},
|
|
870
|
+
impact: 'medium',
|
|
871
|
+
rating: 3,
|
|
872
|
+
category: 'ci',
|
|
873
|
+
fix: 'Add pre-commit hooks (pre-commit, husky, lefthook) to validate Aider changes.',
|
|
874
|
+
template: null,
|
|
875
|
+
file: () => null,
|
|
876
|
+
line: () => null,
|
|
877
|
+
},
|
|
878
|
+
|
|
879
|
+
// =========================================================================
|
|
880
|
+
// H — Quality (6 checks: AD-H01 .. AD-H06)
|
|
881
|
+
// =========================================================================
|
|
882
|
+
|
|
883
|
+
aiderConventionHasCodingStandards: {
|
|
884
|
+
id: 'AD-H01',
|
|
885
|
+
name: 'Convention file has coding standards section',
|
|
886
|
+
check: (ctx) => {
|
|
887
|
+
const content = conventionContent(ctx);
|
|
888
|
+
if (!content) return null;
|
|
889
|
+
return /##\s+(?:Coding|Style|Standards|Formatting|Conventions)/i.test(content);
|
|
890
|
+
},
|
|
891
|
+
impact: 'high',
|
|
892
|
+
rating: 4,
|
|
893
|
+
category: 'quality',
|
|
894
|
+
fix: 'Add a ## Coding Standards section to your convention file.',
|
|
895
|
+
template: 'aider-conventions',
|
|
896
|
+
file: () => 'CONVENTIONS.md',
|
|
897
|
+
line: () => null,
|
|
898
|
+
},
|
|
899
|
+
|
|
900
|
+
aiderConventionHasErrorHandling: {
|
|
901
|
+
id: 'AD-H02',
|
|
902
|
+
name: 'Convention file covers error handling',
|
|
903
|
+
check: (ctx) => {
|
|
904
|
+
const content = conventionContent(ctx);
|
|
905
|
+
if (!content) return null;
|
|
906
|
+
return /\berror\s+handling\b|\bexception\b|\btry[- ]catch\b|\bResult\s*<\b/i.test(content);
|
|
907
|
+
},
|
|
908
|
+
impact: 'medium',
|
|
909
|
+
rating: 3,
|
|
910
|
+
category: 'quality',
|
|
911
|
+
fix: 'Document error handling patterns in your convention file.',
|
|
912
|
+
template: 'aider-conventions',
|
|
913
|
+
file: () => 'CONVENTIONS.md',
|
|
914
|
+
line: () => null,
|
|
915
|
+
},
|
|
916
|
+
|
|
917
|
+
aiderConventionHasTestingGuidelines: {
|
|
918
|
+
id: 'AD-H03',
|
|
919
|
+
name: 'Convention file covers testing guidelines',
|
|
920
|
+
check: (ctx) => {
|
|
921
|
+
const content = conventionContent(ctx);
|
|
922
|
+
if (!content) return null;
|
|
923
|
+
return /##\s+(?:Test|Testing)/i.test(content) || /\bunit test\b|\bintegration test\b|\btest coverage\b/i.test(content);
|
|
924
|
+
},
|
|
925
|
+
impact: 'high',
|
|
926
|
+
rating: 4,
|
|
927
|
+
category: 'quality',
|
|
928
|
+
fix: 'Add testing guidelines to your convention file.',
|
|
929
|
+
template: 'aider-conventions',
|
|
930
|
+
file: () => 'CONVENTIONS.md',
|
|
931
|
+
line: () => null,
|
|
932
|
+
},
|
|
933
|
+
|
|
934
|
+
aiderAutoLintEnabled: {
|
|
935
|
+
id: 'AD-H04',
|
|
936
|
+
name: 'Auto-lint enabled for code quality',
|
|
937
|
+
check: (ctx) => {
|
|
938
|
+
const config = configContent(ctx);
|
|
939
|
+
if (!config) return null;
|
|
940
|
+
return /\bauto-lint\s*:\s*true\b/i.test(config);
|
|
941
|
+
},
|
|
942
|
+
impact: 'high',
|
|
943
|
+
rating: 4,
|
|
944
|
+
category: 'quality',
|
|
945
|
+
fix: 'Set `auto-lint: true` with `lint-cmd` to auto-fix lint errors after edits.',
|
|
946
|
+
template: 'aider-conf-yml',
|
|
947
|
+
file: () => '.aider.conf.yml',
|
|
948
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /auto-lint\s*:/i),
|
|
949
|
+
},
|
|
950
|
+
|
|
951
|
+
aiderShowDiffsEnabled: {
|
|
952
|
+
id: 'AD-H05',
|
|
953
|
+
name: 'Show-diffs enabled for review',
|
|
954
|
+
check: (ctx) => {
|
|
955
|
+
const config = configContent(ctx);
|
|
956
|
+
if (!config) return null;
|
|
957
|
+
if (/\bshow-diffs\s*:\s*false\b/i.test(config)) return false;
|
|
958
|
+
return true; // Default is true
|
|
959
|
+
},
|
|
960
|
+
impact: 'medium',
|
|
961
|
+
rating: 3,
|
|
962
|
+
category: 'quality',
|
|
963
|
+
fix: 'Keep `show-diffs` enabled so you can review changes before accepting.',
|
|
964
|
+
template: 'aider-conf-yml',
|
|
965
|
+
file: () => '.aider.conf.yml',
|
|
966
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /show-diffs\s*:\s*false/i),
|
|
967
|
+
},
|
|
968
|
+
|
|
969
|
+
aiderPrettyOutput: {
|
|
970
|
+
id: 'AD-H06',
|
|
971
|
+
name: 'Pretty output not disabled',
|
|
972
|
+
check: (ctx) => {
|
|
973
|
+
const config = configContent(ctx);
|
|
974
|
+
if (!config) return null;
|
|
975
|
+
if (/\bno-pretty\s*:\s*true\b/i.test(config) || /\bpretty\s*:\s*false\b/i.test(config)) return false;
|
|
976
|
+
return true;
|
|
977
|
+
},
|
|
978
|
+
impact: 'low',
|
|
979
|
+
rating: 2,
|
|
980
|
+
category: 'quality',
|
|
981
|
+
fix: 'Keep pretty output enabled for better readability.',
|
|
982
|
+
template: 'aider-conf-yml',
|
|
983
|
+
file: () => '.aider.conf.yml',
|
|
984
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /no-pretty\s*:\s*true|pretty\s*:\s*false/i),
|
|
985
|
+
},
|
|
986
|
+
|
|
987
|
+
// =========================================================================
|
|
988
|
+
// M — Advanced Config (4 checks: AD-M01 .. AD-M04)
|
|
989
|
+
// =========================================================================
|
|
990
|
+
|
|
991
|
+
aiderEnvFileExists: {
|
|
992
|
+
id: 'AD-M01',
|
|
993
|
+
name: '.env file exists with API configuration',
|
|
994
|
+
check: (ctx) => Boolean(ctx.fileContent('.env')),
|
|
995
|
+
impact: 'high',
|
|
996
|
+
rating: 4,
|
|
997
|
+
category: 'advanced-config',
|
|
998
|
+
fix: 'Create .env with OPENAI_API_KEY or ANTHROPIC_API_KEY for Aider.',
|
|
999
|
+
template: 'aider-env',
|
|
1000
|
+
file: () => '.env',
|
|
1001
|
+
line: () => null,
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
aiderEnvHasApiKey: {
|
|
1005
|
+
id: 'AD-M02',
|
|
1006
|
+
name: '.env contains at least one API key',
|
|
1007
|
+
check: (ctx) => {
|
|
1008
|
+
const env = envContent(ctx);
|
|
1009
|
+
if (!env) return null;
|
|
1010
|
+
return /\b(?:OPENAI_API_KEY|ANTHROPIC_API_KEY|OPENROUTER_API_KEY|DEEPSEEK_API_KEY)\s*=/i.test(env);
|
|
1011
|
+
},
|
|
1012
|
+
impact: 'high',
|
|
1013
|
+
rating: 4,
|
|
1014
|
+
category: 'advanced-config',
|
|
1015
|
+
fix: 'Add an API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) to .env.',
|
|
1016
|
+
template: 'aider-env',
|
|
1017
|
+
file: () => '.env',
|
|
1018
|
+
line: () => null,
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1021
|
+
aiderYesAlwaysNotSet: {
|
|
1022
|
+
id: 'AD-M03',
|
|
1023
|
+
name: '--yes-always not set as default (safety)',
|
|
1024
|
+
check: (ctx) => {
|
|
1025
|
+
const config = configContent(ctx);
|
|
1026
|
+
if (!config) return null;
|
|
1027
|
+
return !/\byes-always\s*:\s*true\b/i.test(config);
|
|
1028
|
+
},
|
|
1029
|
+
impact: 'high',
|
|
1030
|
+
rating: 4,
|
|
1031
|
+
category: 'advanced-config',
|
|
1032
|
+
fix: 'Do not set `yes-always: true` in config — it bypasses all confirmation prompts.',
|
|
1033
|
+
template: 'aider-conf-yml',
|
|
1034
|
+
file: () => '.aider.conf.yml',
|
|
1035
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /yes-always\s*:\s*true/i),
|
|
1036
|
+
},
|
|
1037
|
+
|
|
1038
|
+
aiderVerboseNotDefault: {
|
|
1039
|
+
id: 'AD-M04',
|
|
1040
|
+
name: 'Verbose mode not enabled by default',
|
|
1041
|
+
check: (ctx) => {
|
|
1042
|
+
const config = configContent(ctx);
|
|
1043
|
+
if (!config) return null;
|
|
1044
|
+
return !/\bverbose\s*:\s*true\b/i.test(config);
|
|
1045
|
+
},
|
|
1046
|
+
impact: 'low',
|
|
1047
|
+
rating: 2,
|
|
1048
|
+
category: 'advanced-config',
|
|
1049
|
+
fix: 'Do not default `verbose: true` in config — use --verbose as a CLI flag when needed.',
|
|
1050
|
+
template: 'aider-conf-yml',
|
|
1051
|
+
file: () => '.aider.conf.yml',
|
|
1052
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /verbose\s*:\s*true/i),
|
|
1053
|
+
},
|
|
1054
|
+
|
|
1055
|
+
// =========================================================================
|
|
1056
|
+
// N — Workflow Patterns (4 checks: AD-N01 .. AD-N04)
|
|
1057
|
+
// =========================================================================
|
|
1058
|
+
|
|
1059
|
+
aiderLintAndTestLoop: {
|
|
1060
|
+
id: 'AD-N01',
|
|
1061
|
+
name: 'Lint-and-test loop configured (lint-cmd + test-cmd + auto-lint + auto-test)',
|
|
1062
|
+
check: (ctx) => {
|
|
1063
|
+
const config = configContent(ctx);
|
|
1064
|
+
if (!config) return null;
|
|
1065
|
+
const hasLint = /\blint-cmd\s*:/i.test(config) && /\bauto-lint\s*:\s*true\b/i.test(config);
|
|
1066
|
+
const hasTest = /\btest-cmd\s*:/i.test(config) && /\bauto-test\s*:\s*true\b/i.test(config);
|
|
1067
|
+
return hasLint && hasTest;
|
|
1068
|
+
},
|
|
1069
|
+
impact: 'high',
|
|
1070
|
+
rating: 4,
|
|
1071
|
+
category: 'workflow-patterns',
|
|
1072
|
+
fix: 'Configure the full lint-and-test loop: lint-cmd + auto-lint + test-cmd + auto-test.',
|
|
1073
|
+
template: 'aider-conf-yml',
|
|
1074
|
+
file: () => '.aider.conf.yml',
|
|
1075
|
+
line: () => null,
|
|
1076
|
+
},
|
|
1077
|
+
|
|
1078
|
+
aiderBrowserModeForDocs: {
|
|
1079
|
+
id: 'AD-N02',
|
|
1080
|
+
name: 'Browser integration known (/web command)',
|
|
1081
|
+
check: (ctx) => {
|
|
1082
|
+
const content = conventionContent(ctx);
|
|
1083
|
+
return /\b\/web\b|\bbrowser\b/i.test(content);
|
|
1084
|
+
},
|
|
1085
|
+
impact: 'low',
|
|
1086
|
+
rating: 2,
|
|
1087
|
+
category: 'workflow-patterns',
|
|
1088
|
+
fix: 'Document the /web command in conventions for pulling in documentation.',
|
|
1089
|
+
template: 'aider-conventions',
|
|
1090
|
+
file: () => 'CONVENTIONS.md',
|
|
1091
|
+
line: () => null,
|
|
1092
|
+
},
|
|
1093
|
+
|
|
1094
|
+
aiderInChatCommandsDocumented: {
|
|
1095
|
+
id: 'AD-N03',
|
|
1096
|
+
name: 'Key in-chat commands documented in conventions',
|
|
1097
|
+
check: (ctx) => {
|
|
1098
|
+
const content = conventionContent(ctx);
|
|
1099
|
+
if (!content) return null;
|
|
1100
|
+
// Check for documentation of key commands
|
|
1101
|
+
const commands = ['/add', '/drop', '/run', '/test', '/undo'];
|
|
1102
|
+
const found = commands.filter(cmd => content.includes(cmd));
|
|
1103
|
+
return found.length >= 2;
|
|
1104
|
+
},
|
|
1105
|
+
impact: 'medium',
|
|
1106
|
+
rating: 3,
|
|
1107
|
+
category: 'workflow-patterns',
|
|
1108
|
+
fix: 'Document key Aider commands (/add, /drop, /run, /test, /undo) in conventions.',
|
|
1109
|
+
template: 'aider-conventions',
|
|
1110
|
+
file: () => 'CONVENTIONS.md',
|
|
1111
|
+
line: () => null,
|
|
1112
|
+
},
|
|
1113
|
+
|
|
1114
|
+
aiderVoiceModeAware: {
|
|
1115
|
+
id: 'AD-N04',
|
|
1116
|
+
name: 'Voice mode configuration known',
|
|
1117
|
+
check: (ctx) => {
|
|
1118
|
+
const config = configContent(ctx);
|
|
1119
|
+
if (!config) return null;
|
|
1120
|
+
return /\bvoice-language\s*:/i.test(config) || /\bvoice\b/i.test(conventionContent(ctx));
|
|
1121
|
+
},
|
|
1122
|
+
impact: 'low',
|
|
1123
|
+
rating: 2,
|
|
1124
|
+
category: 'workflow-patterns',
|
|
1125
|
+
fix: 'Optionally configure `voice-language:` for voice coding sessions.',
|
|
1126
|
+
template: 'aider-conf-yml',
|
|
1127
|
+
file: () => '.aider.conf.yml',
|
|
1128
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /voice-language\s*:/i),
|
|
1129
|
+
},
|
|
1130
|
+
|
|
1131
|
+
// =========================================================================
|
|
1132
|
+
// O — Editor Integration (4 checks: AD-O01 .. AD-O04)
|
|
1133
|
+
// =========================================================================
|
|
1134
|
+
|
|
1135
|
+
aiderEditorIntegrationDocumented: {
|
|
1136
|
+
id: 'AD-O01',
|
|
1137
|
+
name: 'Editor integration documented (VS Code, NeoVim, etc.)',
|
|
1138
|
+
check: (ctx) => {
|
|
1139
|
+
const content = conventionContent(ctx);
|
|
1140
|
+
if (!content) return null;
|
|
1141
|
+
return /\bvs\s*code\b|\bneovim\b|\bvim\b|\beditor\b/i.test(content);
|
|
1142
|
+
},
|
|
1143
|
+
impact: 'low',
|
|
1144
|
+
rating: 2,
|
|
1145
|
+
category: 'editor-integration',
|
|
1146
|
+
fix: 'Document editor integration (VS Code extension, NeoVim plugin) in conventions.',
|
|
1147
|
+
template: 'aider-conventions',
|
|
1148
|
+
file: () => 'CONVENTIONS.md',
|
|
1149
|
+
line: () => null,
|
|
1150
|
+
},
|
|
1151
|
+
|
|
1152
|
+
aiderWatchModeKnown: {
|
|
1153
|
+
id: 'AD-O02',
|
|
1154
|
+
name: 'Watch mode (--watch-files) documented or configured',
|
|
1155
|
+
check: (ctx) => {
|
|
1156
|
+
const config = configContent(ctx);
|
|
1157
|
+
if (!config) return null;
|
|
1158
|
+
return /\bwatch-files\s*:/i.test(config) || /\bwatch\b/i.test(conventionContent(ctx));
|
|
1159
|
+
},
|
|
1160
|
+
impact: 'medium',
|
|
1161
|
+
rating: 3,
|
|
1162
|
+
category: 'editor-integration',
|
|
1163
|
+
fix: 'Consider `watch-files: true` for automatic file change detection.',
|
|
1164
|
+
template: 'aider-conf-yml',
|
|
1165
|
+
file: () => '.aider.conf.yml',
|
|
1166
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /watch-files\s*:/i),
|
|
1167
|
+
},
|
|
1168
|
+
|
|
1169
|
+
aiderDarkModeConfigured: {
|
|
1170
|
+
id: 'AD-O03',
|
|
1171
|
+
name: 'Theme/dark mode configured for terminal',
|
|
1172
|
+
check: (ctx) => {
|
|
1173
|
+
const config = configContent(ctx);
|
|
1174
|
+
if (!config) return null;
|
|
1175
|
+
return /\bdark-mode\s*:/i.test(config) || /\blight-mode\s*:/i.test(config);
|
|
1176
|
+
},
|
|
1177
|
+
impact: 'low',
|
|
1178
|
+
rating: 1,
|
|
1179
|
+
category: 'editor-integration',
|
|
1180
|
+
fix: 'Set `dark-mode: true` or `light-mode: true` for terminal readability.',
|
|
1181
|
+
template: 'aider-conf-yml',
|
|
1182
|
+
file: () => '.aider.conf.yml',
|
|
1183
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /dark-mode\s*:|light-mode\s*:/i),
|
|
1184
|
+
},
|
|
1185
|
+
|
|
1186
|
+
aiderInputHistoryExcluded: {
|
|
1187
|
+
id: 'AD-O04',
|
|
1188
|
+
name: 'Input history file excluded from git',
|
|
1189
|
+
check: (ctx) => {
|
|
1190
|
+
const gi = gitignoreContent(ctx);
|
|
1191
|
+
if (!gi) return false;
|
|
1192
|
+
return /\.aider\.input\.history/i.test(gi) || /\.aider\*/i.test(gi) || /\.aider/i.test(gi);
|
|
1193
|
+
},
|
|
1194
|
+
impact: 'medium',
|
|
1195
|
+
rating: 3,
|
|
1196
|
+
category: 'editor-integration',
|
|
1197
|
+
fix: 'Ensure .aider.input.history is gitignored.',
|
|
1198
|
+
template: 'gitignore',
|
|
1199
|
+
file: () => '.gitignore',
|
|
1200
|
+
line: (ctx) => firstLineMatching(gitignoreContent(ctx), /\.aider/i),
|
|
1201
|
+
},
|
|
1202
|
+
|
|
1203
|
+
// =========================================================================
|
|
1204
|
+
// P — Release Readiness (3 checks: AD-P01 .. AD-P03)
|
|
1205
|
+
// =========================================================================
|
|
1206
|
+
|
|
1207
|
+
aiderVersionPinned: {
|
|
1208
|
+
id: 'AD-P01',
|
|
1209
|
+
name: 'Aider version pinned in requirements or package manager',
|
|
1210
|
+
check: (ctx) => {
|
|
1211
|
+
const req = ctx.fileContent('requirements.txt') || '';
|
|
1212
|
+
const pipfile = ctx.fileContent('Pipfile') || '';
|
|
1213
|
+
const pyproject = ctx.fileContent('pyproject.toml') || '';
|
|
1214
|
+
return /\baider-chat\b/i.test(req) || /\baider-chat\b/i.test(pipfile) || /\baider-chat\b/i.test(pyproject);
|
|
1215
|
+
},
|
|
1216
|
+
impact: 'medium',
|
|
1217
|
+
rating: 3,
|
|
1218
|
+
category: 'release-readiness',
|
|
1219
|
+
fix: 'Pin `aider-chat` version in requirements.txt or pyproject.toml.',
|
|
1220
|
+
template: null,
|
|
1221
|
+
file: () => null,
|
|
1222
|
+
line: () => null,
|
|
1223
|
+
},
|
|
1224
|
+
|
|
1225
|
+
aiderAllConfigSurfacesPresent: {
|
|
1226
|
+
id: 'AD-P02',
|
|
1227
|
+
name: 'All essential Aider config surfaces present',
|
|
1228
|
+
check: (ctx) => {
|
|
1229
|
+
const hasConf = Boolean(ctx.fileContent('.aider.conf.yml'));
|
|
1230
|
+
const hasEnv = Boolean(ctx.fileContent('.env'));
|
|
1231
|
+
const hasGitignore = Boolean(ctx.fileContent('.gitignore'));
|
|
1232
|
+
return hasConf && hasEnv && hasGitignore;
|
|
1233
|
+
},
|
|
1234
|
+
impact: 'high',
|
|
1235
|
+
rating: 4,
|
|
1236
|
+
category: 'release-readiness',
|
|
1237
|
+
fix: 'Ensure .aider.conf.yml, .env, and .gitignore all exist.',
|
|
1238
|
+
template: null,
|
|
1239
|
+
file: () => null,
|
|
1240
|
+
line: () => null,
|
|
1241
|
+
},
|
|
1242
|
+
|
|
1243
|
+
aiderDocumentedWorkflow: {
|
|
1244
|
+
id: 'AD-P03',
|
|
1245
|
+
name: 'Aider workflow documented in README or conventions',
|
|
1246
|
+
check: (ctx) => {
|
|
1247
|
+
const readme = ctx.fileContent('README.md') || '';
|
|
1248
|
+
const content = conventionContent(ctx);
|
|
1249
|
+
return /\baider\b/i.test(readme) || /\bworkflow\b/i.test(content);
|
|
1250
|
+
},
|
|
1251
|
+
impact: 'medium',
|
|
1252
|
+
rating: 3,
|
|
1253
|
+
category: 'release-readiness',
|
|
1254
|
+
fix: 'Document Aider workflow in README.md or convention files.',
|
|
1255
|
+
template: 'aider-conventions',
|
|
1256
|
+
file: () => 'README.md',
|
|
1257
|
+
line: () => null,
|
|
1258
|
+
},
|
|
1259
|
+
|
|
1260
|
+
aiderNoConflictingPlatformConfigs: {
|
|
1261
|
+
id: 'AD-P04',
|
|
1262
|
+
name: 'No conflicting platform configs (CLAUDE.md, AGENTS.md) without awareness',
|
|
1263
|
+
check: (ctx) => {
|
|
1264
|
+
const hasAider = Boolean(ctx.fileContent('.aider.conf.yml'));
|
|
1265
|
+
const hasClaude = Boolean(ctx.fileContent('CLAUDE.md')) || Boolean(ctx.fileContent('.claude/CLAUDE.md'));
|
|
1266
|
+
const hasCodex = Boolean(ctx.fileContent('AGENTS.md'));
|
|
1267
|
+
if (!hasAider) return null;
|
|
1268
|
+
// Multi-platform is fine — just check conventions mention it
|
|
1269
|
+
if (hasClaude || hasCodex) {
|
|
1270
|
+
const content = conventionContent(ctx);
|
|
1271
|
+
return /\bmulti[- ]?platform\b|\bclaude\b|\bcodex\b/i.test(content);
|
|
1272
|
+
}
|
|
1273
|
+
return true;
|
|
1274
|
+
},
|
|
1275
|
+
impact: 'medium',
|
|
1276
|
+
rating: 3,
|
|
1277
|
+
category: 'release-readiness',
|
|
1278
|
+
fix: 'If using multiple AI platforms, document the multi-platform strategy in conventions.',
|
|
1279
|
+
template: 'aider-conventions',
|
|
1280
|
+
file: () => 'CONVENTIONS.md',
|
|
1281
|
+
line: () => null,
|
|
1282
|
+
},
|
|
1283
|
+
|
|
1284
|
+
aiderModelCostAwareness: {
|
|
1285
|
+
id: 'AD-P05',
|
|
1286
|
+
name: 'Model cost awareness configured (cache-prompts or explicit model selection)',
|
|
1287
|
+
check: (ctx) => {
|
|
1288
|
+
const config = configContent(ctx);
|
|
1289
|
+
if (!config) return null;
|
|
1290
|
+
return /\bcache-prompts\s*:\s*true\b/i.test(config) ||
|
|
1291
|
+
/\bweak-model\s*:/i.test(config) ||
|
|
1292
|
+
/\beditor-model\s*:/i.test(config);
|
|
1293
|
+
},
|
|
1294
|
+
impact: 'medium',
|
|
1295
|
+
rating: 3,
|
|
1296
|
+
category: 'release-readiness',
|
|
1297
|
+
fix: 'Enable prompt caching or configure separate weak/editor models for cost optimization.',
|
|
1298
|
+
template: 'aider-conf-yml',
|
|
1299
|
+
file: () => '.aider.conf.yml',
|
|
1300
|
+
line: (ctx) => firstLineMatching(configContent(ctx), /cache-prompts\s*:|weak-model\s*:|editor-model\s*:/i),
|
|
1301
|
+
},
|
|
1302
|
+
|
|
1303
|
+
aiderGitBranchStrategy: {
|
|
1304
|
+
id: 'AD-P06',
|
|
1305
|
+
name: 'Git branch strategy for Aider work',
|
|
1306
|
+
check: (ctx) => {
|
|
1307
|
+
const content = conventionContent(ctx);
|
|
1308
|
+
if (!content) return null;
|
|
1309
|
+
return /\bbranch\b/i.test(content) && /\baider\b/i.test(content);
|
|
1310
|
+
},
|
|
1311
|
+
impact: 'medium',
|
|
1312
|
+
rating: 3,
|
|
1313
|
+
category: 'release-readiness',
|
|
1314
|
+
fix: 'Document a branch strategy for Aider work (e.g., feature branches, PR workflow).',
|
|
1315
|
+
template: 'aider-conventions',
|
|
1316
|
+
file: () => 'CONVENTIONS.md',
|
|
1317
|
+
line: () => null,
|
|
1318
|
+
},
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
module.exports = {
|
|
1322
|
+
AIDER_TECHNIQUES,
|
|
1323
|
+
};
|