@nerviq/cli 1.8.5 → 1.8.7
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/README.md +362 -362
- package/bin/cli.js +5 -5
- package/package.json +1 -1
- package/src/aider/activity.js +226 -226
- package/src/audit.js +1443 -1443
- package/src/benchmark.js +346 -346
- package/src/codex/activity.js +324 -324
- package/src/copilot/patch.js +238 -238
- package/src/cursor/patch.js +243 -243
- package/src/gemini/activity.js +402 -402
- package/src/gemini/patch.js +229 -229
- package/src/governance.js +583 -583
- package/src/harmony/audit.js +306 -306
- package/src/insights.js +119 -119
- package/src/{claudex-sync.json → nerviq-sync.json} +1 -1
- package/src/opencode/activity.js +286 -286
- package/src/source-urls.js +18 -1
- package/src/state-paths.js +85 -85
- package/src/techniques.js +5494 -5494
- package/src/windsurf/patch.js +231 -231
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { audit } = require('../src/
|
|
3
|
+
const { audit, detectPlatforms, getCatalog } = require('../src/public-api');
|
|
4
4
|
const { setup } = require('../src/setup');
|
|
5
5
|
const { analyzeProject, printAnalysis, exportMarkdown } = require('../src/analyze');
|
|
6
6
|
const { buildProposalBundle, printProposalBundle, writePlanFile, applyProposalBundle, printApplyResult } = require('../src/plans');
|
|
@@ -740,7 +740,7 @@ async function main() {
|
|
|
740
740
|
process.exit(0);
|
|
741
741
|
} else if (normalizedCommand === 'insights') {
|
|
742
742
|
const https = require('https');
|
|
743
|
-
const url = 'https://
|
|
743
|
+
const url = 'https://nerviq-insights.nerviq.workers.dev/v1/stats';
|
|
744
744
|
const req = https.get(url, (res) => {
|
|
745
745
|
let data = '';
|
|
746
746
|
res.on('data', chunk => data += chunk);
|
|
@@ -748,7 +748,7 @@ async function main() {
|
|
|
748
748
|
try {
|
|
749
749
|
const stats = JSON.parse(data);
|
|
750
750
|
console.log('');
|
|
751
|
-
console.log('\x1b[1m
|
|
751
|
+
console.log('\x1b[1m NERVIQ Community Insights\x1b[0m');
|
|
752
752
|
console.log('\x1b[2m ═══════════════════════════════════════\x1b[0m');
|
|
753
753
|
console.log(` Total audits run: \x1b[1m${stats.totalRuns}\x1b[0m`);
|
|
754
754
|
console.log(` Average score: \x1b[1m${stats.averageScore}/100\x1b[0m`);
|
|
@@ -998,7 +998,7 @@ async function main() {
|
|
|
998
998
|
const { watch } = require('../src/watch');
|
|
999
999
|
await watch(options);
|
|
1000
1000
|
} else if (normalizedCommand === 'catalog') {
|
|
1001
|
-
const {
|
|
1001
|
+
const { generateCatalogWithVersion, writeCatalogJson } = require('../src/catalog');
|
|
1002
1002
|
if (options.out) {
|
|
1003
1003
|
const result = writeCatalogJson(options.out);
|
|
1004
1004
|
if (options.json) {
|
|
@@ -1007,7 +1007,7 @@ async function main() {
|
|
|
1007
1007
|
console.log(`\n Catalog written to ${result.path} (${result.count} checks)\n`);
|
|
1008
1008
|
}
|
|
1009
1009
|
} else {
|
|
1010
|
-
const catalog =
|
|
1010
|
+
const catalog = getCatalog(); // dogfood: use SDK instead of internal import
|
|
1011
1011
|
if (options.json) {
|
|
1012
1012
|
const envelope = generateCatalogWithVersion();
|
|
1013
1013
|
if (options.checkVersion) envelope.requestedVersion = options.checkVersion;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerviq/cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.7",
|
|
4
4
|
"description": "The intelligent nervous system for AI coding agents — 2,431 checks (8 platforms × ~300 governance rules), 10 languages, 62 domain packs. Audit, align, and amplify.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/aider/activity.js
CHANGED
|
@@ -1,226 +1,226 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aider Repeat-Usage Surfaces — 6 activity surfaces
|
|
3
|
-
*
|
|
4
|
-
* Adapts the shared activity/snapshot backend for Aider platform.
|
|
5
|
-
* Provides: history, compare, trend, watch, feedback, insights.
|
|
6
|
-
*
|
|
7
|
-
* Aider snapshots stored in .nerviq/snapshots/ (legacy: .claude/
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const {
|
|
12
|
-
getHistory: getSharedHistory,
|
|
13
|
-
compareLatest: sharedCompareLatest,
|
|
14
|
-
readSnapshotIndex,
|
|
15
|
-
writeSnapshotArtifact,
|
|
16
|
-
exportTrendReport: sharedExportTrendReport,
|
|
17
|
-
recordRecommendationOutcome,
|
|
18
|
-
readOutcomeIndex,
|
|
19
|
-
summarizeOutcomeEntries,
|
|
20
|
-
} = require('../activity');
|
|
21
|
-
const { version } = require('../../package.json');
|
|
22
|
-
|
|
23
|
-
// --- History ---
|
|
24
|
-
|
|
25
|
-
function getAiderHistory(dir, limit = 20) {
|
|
26
|
-
const entries = readSnapshotIndex(dir);
|
|
27
|
-
return entries
|
|
28
|
-
.filter(e => e.snapshotKind === 'audit' && (e.platform === 'aider' || e.summary?.platform === 'aider'))
|
|
29
|
-
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
30
|
-
.slice(0, limit);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function formatAiderHistory(dir) {
|
|
34
|
-
const history = getAiderHistory(dir, 10);
|
|
35
|
-
if (history.length === 0) {
|
|
36
|
-
return 'No Aider snapshots found. Run `npx nerviq --platform aider --snapshot` to save one.';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const lines = ['Aider Score History (most recent first):', ''];
|
|
40
|
-
for (const entry of history) {
|
|
41
|
-
const date = entry.createdAt?.split('T')[0] || 'unknown';
|
|
42
|
-
const score = entry.summary?.score ?? '?';
|
|
43
|
-
const passed = entry.summary?.passed ?? '?';
|
|
44
|
-
const total = entry.summary?.checkCount ?? '?';
|
|
45
|
-
lines.push(` ${date} ${score}/100 (${passed}/${total} passing)`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const comparison = compareAiderLatest(dir);
|
|
49
|
-
if (comparison) {
|
|
50
|
-
lines.push('');
|
|
51
|
-
const sign = comparison.delta.score >= 0 ? '+' : '';
|
|
52
|
-
lines.push(` Trend: ${comparison.trend} (${sign}${comparison.delta.score} since previous)`);
|
|
53
|
-
if (comparison.improvements.length > 0) {
|
|
54
|
-
lines.push(` Fixed: ${comparison.improvements.join(', ')}`);
|
|
55
|
-
}
|
|
56
|
-
if (comparison.regressions.length > 0) {
|
|
57
|
-
lines.push(` New gaps: ${comparison.regressions.join(', ')}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return lines.join('\n');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// --- Compare ---
|
|
65
|
-
|
|
66
|
-
function compareAiderLatest(dir) {
|
|
67
|
-
const audits = getAiderHistory(dir, 2);
|
|
68
|
-
if (audits.length < 2) return null;
|
|
69
|
-
|
|
70
|
-
const current = audits[0];
|
|
71
|
-
const previous = audits[1];
|
|
72
|
-
|
|
73
|
-
const currentPassed = new Set(current.summary?.passedIds || []);
|
|
74
|
-
const previousPassed = new Set(previous.summary?.passedIds || []);
|
|
75
|
-
|
|
76
|
-
const improvements = [];
|
|
77
|
-
const regressions = [];
|
|
78
|
-
|
|
79
|
-
for (const id of currentPassed) {
|
|
80
|
-
if (!previousPassed.has(id)) improvements.push(id);
|
|
81
|
-
}
|
|
82
|
-
for (const id of previousPassed) {
|
|
83
|
-
if (!currentPassed.has(id)) regressions.push(id);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const scoreDelta = (current.summary?.score ?? 0) - (previous.summary?.score ?? 0);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
trend: scoreDelta > 0 ? 'improving' : scoreDelta < 0 ? 'regressing' : 'stable',
|
|
90
|
-
delta: { score: scoreDelta },
|
|
91
|
-
improvements,
|
|
92
|
-
regressions,
|
|
93
|
-
currentSnapshot: current,
|
|
94
|
-
previousSnapshot: previous,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// --- Trend Export ---
|
|
99
|
-
|
|
100
|
-
function exportAiderTrendReport(dir) {
|
|
101
|
-
const history = getAiderHistory(dir, 50);
|
|
102
|
-
if (history.length === 0) return null;
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
platform: 'aider',
|
|
106
|
-
generatedAt: new Date().toISOString(),
|
|
107
|
-
nerviqVersion: version,
|
|
108
|
-
snapshotCount: history.length,
|
|
109
|
-
dataPoints: history.map(entry => ({
|
|
110
|
-
date: entry.createdAt,
|
|
111
|
-
score: entry.summary?.score ?? null,
|
|
112
|
-
passed: entry.summary?.passed ?? null,
|
|
113
|
-
checkCount: entry.summary?.checkCount ?? null,
|
|
114
|
-
})),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// --- Feedback ---
|
|
119
|
-
|
|
120
|
-
function recordAiderFeedback(dir, recommendationId, outcome, notes = '') {
|
|
121
|
-
return recordRecommendationOutcome(dir, {
|
|
122
|
-
platform: 'aider',
|
|
123
|
-
recommendationId,
|
|
124
|
-
outcome,
|
|
125
|
-
notes,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getAiderFeedbackSummary(dir) {
|
|
130
|
-
const entries = readOutcomeIndex(dir);
|
|
131
|
-
const aiderEntries = entries.filter(e => e.platform === 'aider');
|
|
132
|
-
return summarizeOutcomeEntries(aiderEntries);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function formatAiderFeedback(dir) {
|
|
136
|
-
const summary = getAiderFeedbackSummary(dir);
|
|
137
|
-
if (summary.total === 0) {
|
|
138
|
-
return 'No Aider recommendation feedback recorded yet.';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const lines = [
|
|
142
|
-
'Aider Recommendation Feedback:',
|
|
143
|
-
'',
|
|
144
|
-
` Total: ${summary.total}`,
|
|
145
|
-
` Accepted: ${summary.accepted}`,
|
|
146
|
-
` Rejected: ${summary.rejected}`,
|
|
147
|
-
` Deferred: ${summary.deferred}`,
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
if (summary.acceptanceRate !== null) {
|
|
151
|
-
lines.push(` Acceptance rate: ${(summary.acceptanceRate * 100).toFixed(0)}%`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return lines.join('\n');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// --- Insights ---
|
|
158
|
-
|
|
159
|
-
function generateAiderInsights(dir) {
|
|
160
|
-
const history = getAiderHistory(dir, 10);
|
|
161
|
-
const feedback = getAiderFeedbackSummary(dir);
|
|
162
|
-
const insights = [];
|
|
163
|
-
|
|
164
|
-
if (history.length >= 3) {
|
|
165
|
-
const recent = history.slice(0, 3);
|
|
166
|
-
const avgScore = recent.reduce((sum, e) => sum + (e.summary?.score ?? 0), 0) / recent.length;
|
|
167
|
-
|
|
168
|
-
if (avgScore < 40) {
|
|
169
|
-
insights.push({
|
|
170
|
-
severity: 'high',
|
|
171
|
-
message: 'Aider setup score consistently low — prioritize .aider.conf.yml and CONVENTIONS.md.',
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const comparison = compareAiderLatest(dir);
|
|
176
|
-
if (comparison && comparison.regressions.length > 2) {
|
|
177
|
-
insights.push({
|
|
178
|
-
severity: 'medium',
|
|
179
|
-
message: `${comparison.regressions.length} checks regressed since last snapshot.`,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (feedback.total > 5 && feedback.acceptanceRate !== null && feedback.acceptanceRate < 0.5) {
|
|
185
|
-
insights.push({
|
|
186
|
-
severity: 'medium',
|
|
187
|
-
message: 'Low recommendation acceptance rate — review convention file relevance.',
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
platform: 'aider',
|
|
193
|
-
insights,
|
|
194
|
-
summary: insights.length === 0
|
|
195
|
-
? 'No actionable Aider insights at this time.'
|
|
196
|
-
: `${insights.length} Aider insight(s) found.`,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function formatAiderInsights(dir) {
|
|
201
|
-
const result = generateAiderInsights(dir);
|
|
202
|
-
if (result.insights.length === 0) {
|
|
203
|
-
return result.summary;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const lines = ['Aider Insights:', ''];
|
|
207
|
-
for (const insight of result.insights) {
|
|
208
|
-
const severity = insight.severity.toUpperCase();
|
|
209
|
-
lines.push(` [${severity}] ${insight.message}`);
|
|
210
|
-
}
|
|
211
|
-
lines.push('');
|
|
212
|
-
lines.push(result.summary);
|
|
213
|
-
return lines.join('\n');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
module.exports = {
|
|
217
|
-
getAiderHistory,
|
|
218
|
-
formatAiderHistory,
|
|
219
|
-
compareAiderLatest,
|
|
220
|
-
exportAiderTrendReport,
|
|
221
|
-
recordAiderFeedback,
|
|
222
|
-
getAiderFeedbackSummary,
|
|
223
|
-
formatAiderFeedback,
|
|
224
|
-
generateAiderInsights,
|
|
225
|
-
formatAiderInsights,
|
|
226
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Aider Repeat-Usage Surfaces — 6 activity surfaces
|
|
3
|
+
*
|
|
4
|
+
* Adapts the shared activity/snapshot backend for Aider platform.
|
|
5
|
+
* Provides: history, compare, trend, watch, feedback, insights.
|
|
6
|
+
*
|
|
7
|
+
* Aider snapshots stored in .nerviq/snapshots/ (legacy: .claude/nerviq-cli/snapshots/) filtered by platform='aider'.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const {
|
|
12
|
+
getHistory: getSharedHistory,
|
|
13
|
+
compareLatest: sharedCompareLatest,
|
|
14
|
+
readSnapshotIndex,
|
|
15
|
+
writeSnapshotArtifact,
|
|
16
|
+
exportTrendReport: sharedExportTrendReport,
|
|
17
|
+
recordRecommendationOutcome,
|
|
18
|
+
readOutcomeIndex,
|
|
19
|
+
summarizeOutcomeEntries,
|
|
20
|
+
} = require('../activity');
|
|
21
|
+
const { version } = require('../../package.json');
|
|
22
|
+
|
|
23
|
+
// --- History ---
|
|
24
|
+
|
|
25
|
+
function getAiderHistory(dir, limit = 20) {
|
|
26
|
+
const entries = readSnapshotIndex(dir);
|
|
27
|
+
return entries
|
|
28
|
+
.filter(e => e.snapshotKind === 'audit' && (e.platform === 'aider' || e.summary?.platform === 'aider'))
|
|
29
|
+
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
30
|
+
.slice(0, limit);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function formatAiderHistory(dir) {
|
|
34
|
+
const history = getAiderHistory(dir, 10);
|
|
35
|
+
if (history.length === 0) {
|
|
36
|
+
return 'No Aider snapshots found. Run `npx nerviq --platform aider --snapshot` to save one.';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const lines = ['Aider Score History (most recent first):', ''];
|
|
40
|
+
for (const entry of history) {
|
|
41
|
+
const date = entry.createdAt?.split('T')[0] || 'unknown';
|
|
42
|
+
const score = entry.summary?.score ?? '?';
|
|
43
|
+
const passed = entry.summary?.passed ?? '?';
|
|
44
|
+
const total = entry.summary?.checkCount ?? '?';
|
|
45
|
+
lines.push(` ${date} ${score}/100 (${passed}/${total} passing)`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const comparison = compareAiderLatest(dir);
|
|
49
|
+
if (comparison) {
|
|
50
|
+
lines.push('');
|
|
51
|
+
const sign = comparison.delta.score >= 0 ? '+' : '';
|
|
52
|
+
lines.push(` Trend: ${comparison.trend} (${sign}${comparison.delta.score} since previous)`);
|
|
53
|
+
if (comparison.improvements.length > 0) {
|
|
54
|
+
lines.push(` Fixed: ${comparison.improvements.join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
if (comparison.regressions.length > 0) {
|
|
57
|
+
lines.push(` New gaps: ${comparison.regressions.join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return lines.join('\n');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Compare ---
|
|
65
|
+
|
|
66
|
+
function compareAiderLatest(dir) {
|
|
67
|
+
const audits = getAiderHistory(dir, 2);
|
|
68
|
+
if (audits.length < 2) return null;
|
|
69
|
+
|
|
70
|
+
const current = audits[0];
|
|
71
|
+
const previous = audits[1];
|
|
72
|
+
|
|
73
|
+
const currentPassed = new Set(current.summary?.passedIds || []);
|
|
74
|
+
const previousPassed = new Set(previous.summary?.passedIds || []);
|
|
75
|
+
|
|
76
|
+
const improvements = [];
|
|
77
|
+
const regressions = [];
|
|
78
|
+
|
|
79
|
+
for (const id of currentPassed) {
|
|
80
|
+
if (!previousPassed.has(id)) improvements.push(id);
|
|
81
|
+
}
|
|
82
|
+
for (const id of previousPassed) {
|
|
83
|
+
if (!currentPassed.has(id)) regressions.push(id);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const scoreDelta = (current.summary?.score ?? 0) - (previous.summary?.score ?? 0);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
trend: scoreDelta > 0 ? 'improving' : scoreDelta < 0 ? 'regressing' : 'stable',
|
|
90
|
+
delta: { score: scoreDelta },
|
|
91
|
+
improvements,
|
|
92
|
+
regressions,
|
|
93
|
+
currentSnapshot: current,
|
|
94
|
+
previousSnapshot: previous,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// --- Trend Export ---
|
|
99
|
+
|
|
100
|
+
function exportAiderTrendReport(dir) {
|
|
101
|
+
const history = getAiderHistory(dir, 50);
|
|
102
|
+
if (history.length === 0) return null;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
platform: 'aider',
|
|
106
|
+
generatedAt: new Date().toISOString(),
|
|
107
|
+
nerviqVersion: version,
|
|
108
|
+
snapshotCount: history.length,
|
|
109
|
+
dataPoints: history.map(entry => ({
|
|
110
|
+
date: entry.createdAt,
|
|
111
|
+
score: entry.summary?.score ?? null,
|
|
112
|
+
passed: entry.summary?.passed ?? null,
|
|
113
|
+
checkCount: entry.summary?.checkCount ?? null,
|
|
114
|
+
})),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// --- Feedback ---
|
|
119
|
+
|
|
120
|
+
function recordAiderFeedback(dir, recommendationId, outcome, notes = '') {
|
|
121
|
+
return recordRecommendationOutcome(dir, {
|
|
122
|
+
platform: 'aider',
|
|
123
|
+
recommendationId,
|
|
124
|
+
outcome,
|
|
125
|
+
notes,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getAiderFeedbackSummary(dir) {
|
|
130
|
+
const entries = readOutcomeIndex(dir);
|
|
131
|
+
const aiderEntries = entries.filter(e => e.platform === 'aider');
|
|
132
|
+
return summarizeOutcomeEntries(aiderEntries);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function formatAiderFeedback(dir) {
|
|
136
|
+
const summary = getAiderFeedbackSummary(dir);
|
|
137
|
+
if (summary.total === 0) {
|
|
138
|
+
return 'No Aider recommendation feedback recorded yet.';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const lines = [
|
|
142
|
+
'Aider Recommendation Feedback:',
|
|
143
|
+
'',
|
|
144
|
+
` Total: ${summary.total}`,
|
|
145
|
+
` Accepted: ${summary.accepted}`,
|
|
146
|
+
` Rejected: ${summary.rejected}`,
|
|
147
|
+
` Deferred: ${summary.deferred}`,
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
if (summary.acceptanceRate !== null) {
|
|
151
|
+
lines.push(` Acceptance rate: ${(summary.acceptanceRate * 100).toFixed(0)}%`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return lines.join('\n');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// --- Insights ---
|
|
158
|
+
|
|
159
|
+
function generateAiderInsights(dir) {
|
|
160
|
+
const history = getAiderHistory(dir, 10);
|
|
161
|
+
const feedback = getAiderFeedbackSummary(dir);
|
|
162
|
+
const insights = [];
|
|
163
|
+
|
|
164
|
+
if (history.length >= 3) {
|
|
165
|
+
const recent = history.slice(0, 3);
|
|
166
|
+
const avgScore = recent.reduce((sum, e) => sum + (e.summary?.score ?? 0), 0) / recent.length;
|
|
167
|
+
|
|
168
|
+
if (avgScore < 40) {
|
|
169
|
+
insights.push({
|
|
170
|
+
severity: 'high',
|
|
171
|
+
message: 'Aider setup score consistently low — prioritize .aider.conf.yml and CONVENTIONS.md.',
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const comparison = compareAiderLatest(dir);
|
|
176
|
+
if (comparison && comparison.regressions.length > 2) {
|
|
177
|
+
insights.push({
|
|
178
|
+
severity: 'medium',
|
|
179
|
+
message: `${comparison.regressions.length} checks regressed since last snapshot.`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (feedback.total > 5 && feedback.acceptanceRate !== null && feedback.acceptanceRate < 0.5) {
|
|
185
|
+
insights.push({
|
|
186
|
+
severity: 'medium',
|
|
187
|
+
message: 'Low recommendation acceptance rate — review convention file relevance.',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
platform: 'aider',
|
|
193
|
+
insights,
|
|
194
|
+
summary: insights.length === 0
|
|
195
|
+
? 'No actionable Aider insights at this time.'
|
|
196
|
+
: `${insights.length} Aider insight(s) found.`,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function formatAiderInsights(dir) {
|
|
201
|
+
const result = generateAiderInsights(dir);
|
|
202
|
+
if (result.insights.length === 0) {
|
|
203
|
+
return result.summary;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const lines = ['Aider Insights:', ''];
|
|
207
|
+
for (const insight of result.insights) {
|
|
208
|
+
const severity = insight.severity.toUpperCase();
|
|
209
|
+
lines.push(` [${severity}] ${insight.message}`);
|
|
210
|
+
}
|
|
211
|
+
lines.push('');
|
|
212
|
+
lines.push(result.summary);
|
|
213
|
+
return lines.join('\n');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
getAiderHistory,
|
|
218
|
+
formatAiderHistory,
|
|
219
|
+
compareAiderLatest,
|
|
220
|
+
exportAiderTrendReport,
|
|
221
|
+
recordAiderFeedback,
|
|
222
|
+
getAiderFeedbackSummary,
|
|
223
|
+
formatAiderFeedback,
|
|
224
|
+
generateAiderInsights,
|
|
225
|
+
formatAiderInsights,
|
|
226
|
+
};
|