@nerviq/cli 1.12.0 → 1.13.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/README.md +224 -210
- package/bin/cli.js +2 -1
- package/package.json +3 -2
- package/src/aider/freshness.js +65 -20
- package/src/audit/instruction-files.js +180 -0
- package/src/audit/recommendations.js +531 -0
- package/src/audit.js +19 -722
- package/src/codex/freshness.js +84 -25
- package/src/copilot/freshness.js +57 -20
- package/src/cursor/freshness.js +65 -20
- package/src/freshness.js +74 -21
- package/src/gemini/freshness.js +66 -21
- package/src/mcp-server.js +95 -59
- package/src/opencode/freshness.js +66 -21
- package/src/setup/analysis.js +619 -0
- package/src/setup/runtime.js +172 -0
- package/src/setup.js +28 -748
- package/src/windsurf/freshness.js +36 -21
package/src/mcp-server.js
CHANGED
|
@@ -29,7 +29,78 @@
|
|
|
29
29
|
|
|
30
30
|
'use strict';
|
|
31
31
|
|
|
32
|
-
const { version } = require('../package.json');
|
|
32
|
+
const { version } = require('../package.json');
|
|
33
|
+
|
|
34
|
+
function buildMcpAuditPayload(result, options = {}) {
|
|
35
|
+
const verbose = Boolean(options.verbose);
|
|
36
|
+
const normalizedCheckCount = typeof result.checkCount === 'number'
|
|
37
|
+
? result.checkCount
|
|
38
|
+
: typeof result.total === 'number'
|
|
39
|
+
? result.total
|
|
40
|
+
: 0;
|
|
41
|
+
|
|
42
|
+
const payload = {
|
|
43
|
+
platform: result.platform,
|
|
44
|
+
score: result.score,
|
|
45
|
+
passed: result.passed,
|
|
46
|
+
failed: result.failed,
|
|
47
|
+
total: normalizedCheckCount,
|
|
48
|
+
checkCount: normalizedCheckCount,
|
|
49
|
+
scoreType: result.scoreType || 'live-audit-score',
|
|
50
|
+
grade: result.score >= 80 ? 'A' : result.score >= 60 ? 'B' : result.score >= 40 ? 'C' : 'D',
|
|
51
|
+
criticalFailures: (result.results || [])
|
|
52
|
+
.filter(r => r.passed === false && r.impact === 'critical')
|
|
53
|
+
.map(r => ({ key: r.key, id: r.id, name: r.name, fix: r.fix })),
|
|
54
|
+
highFailures: (result.results || [])
|
|
55
|
+
.filter(r => r.passed === false && r.impact === 'high')
|
|
56
|
+
.map(r => ({ key: r.key, id: r.id, name: r.name, fix: r.fix })),
|
|
57
|
+
topNextActions: (result.topNextActions || []).slice(0, 3).map((item) => ({
|
|
58
|
+
key: item.key,
|
|
59
|
+
name: item.name,
|
|
60
|
+
impact: item.impact,
|
|
61
|
+
fix: item.fix,
|
|
62
|
+
})),
|
|
63
|
+
suggestedNextCommand: result.suggestedNextCommand || null,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (verbose) {
|
|
67
|
+
payload.results = (result.results || []).map(r => ({
|
|
68
|
+
key: r.key,
|
|
69
|
+
id: r.id,
|
|
70
|
+
name: r.name,
|
|
71
|
+
passed: r.passed,
|
|
72
|
+
impact: r.impact,
|
|
73
|
+
fix: r.passed === false ? r.fix : undefined,
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return payload;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function buildMcpHarmonyPayload(result, options = {}) {
|
|
81
|
+
const verbose = Boolean(options.verbose);
|
|
82
|
+
const payload = {
|
|
83
|
+
harmonyScore: result.harmonyScore,
|
|
84
|
+
activePlatforms: result.activePlatforms || [],
|
|
85
|
+
platformScores: result.platformScores || {},
|
|
86
|
+
driftCount: result.driftCount || (result.drifts || []).length || 0,
|
|
87
|
+
criticalDrifts: (result.drifts || [])
|
|
88
|
+
.filter(d => d.severity === 'critical')
|
|
89
|
+
.map(d => ({ type: d.type, description: d.description, recommendation: d.recommendation })),
|
|
90
|
+
recommendations: (result.recommendations || []).slice(0, 5),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
if (verbose) {
|
|
94
|
+
payload.allDrifts = (result.drifts || []).map(d => ({
|
|
95
|
+
type: d.type,
|
|
96
|
+
severity: d.severity,
|
|
97
|
+
description: d.description,
|
|
98
|
+
recommendation: d.recommendation,
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return payload;
|
|
103
|
+
}
|
|
33
104
|
|
|
34
105
|
// ─── Tool definitions ────────────────────────────────────────────────────────
|
|
35
106
|
|
|
@@ -132,74 +203,26 @@ const TOOLS = [
|
|
|
132
203
|
|
|
133
204
|
// ─── Tool handlers ───────────────────────────────────────────────────────────
|
|
134
205
|
|
|
135
|
-
async function handleAudit(input) {
|
|
206
|
+
async function handleAudit(input) {
|
|
136
207
|
const { audit } = require('./audit');
|
|
137
208
|
const dir = input.dir || process.cwd();
|
|
138
209
|
const platform = input.platform || 'claude';
|
|
139
210
|
const verbose = Boolean(input.verbose);
|
|
140
211
|
|
|
141
|
-
const result = await audit({ dir, platform, silent: true, verbose });
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
platform: result.platform,
|
|
146
|
-
score: result.score,
|
|
147
|
-
passed: result.passed,
|
|
148
|
-
failed: result.failed,
|
|
149
|
-
total: result.total,
|
|
150
|
-
grade: result.score >= 80 ? 'A' : result.score >= 60 ? 'B' : result.score >= 40 ? 'C' : 'D',
|
|
151
|
-
criticalFailures: (result.results || [])
|
|
152
|
-
.filter(r => r.passed === false && r.impact === 'critical')
|
|
153
|
-
.map(r => ({ key: r.key, id: r.id, name: r.name, fix: r.fix })),
|
|
154
|
-
highFailures: (result.results || [])
|
|
155
|
-
.filter(r => r.passed === false && r.impact === 'high')
|
|
156
|
-
.map(r => ({ key: r.key, id: r.id, name: r.name, fix: r.fix })),
|
|
157
|
-
suggestedNextCommand: result.suggestedNextCommand || null,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
if (verbose) {
|
|
161
|
-
clean.allResults = (result.results || []).map(r => ({
|
|
162
|
-
key: r.key,
|
|
163
|
-
id: r.id,
|
|
164
|
-
name: r.name,
|
|
165
|
-
passed: r.passed,
|
|
166
|
-
impact: r.impact,
|
|
167
|
-
fix: r.passed === false ? r.fix : undefined,
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return { content: [{ type: 'text', text: JSON.stringify(clean, null, 2) }] };
|
|
172
|
-
}
|
|
212
|
+
const result = await audit({ dir, platform, silent: true, verbose });
|
|
213
|
+
const clean = buildMcpAuditPayload(result, { verbose });
|
|
214
|
+
return { content: [{ type: 'text', text: JSON.stringify(clean, null, 2) }] };
|
|
215
|
+
}
|
|
173
216
|
|
|
174
217
|
async function handleHarmony(input) {
|
|
175
218
|
const { harmonyAudit } = require('./harmony/audit');
|
|
176
219
|
const dir = input.dir || process.cwd();
|
|
177
220
|
const verbose = Boolean(input.verbose);
|
|
178
221
|
|
|
179
|
-
const result = await harmonyAudit({ dir, silent: true });
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
activePlatforms: result.activePlatforms || [],
|
|
184
|
-
platformScores: result.platformScores || {},
|
|
185
|
-
driftCount: result.driftCount || 0,
|
|
186
|
-
criticalDrifts: (result.drifts || [])
|
|
187
|
-
.filter(d => d.severity === 'critical')
|
|
188
|
-
.map(d => ({ type: d.type, description: d.description, recommendation: d.recommendation })),
|
|
189
|
-
recommendations: (result.recommendations || []).slice(0, 5),
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
if (verbose) {
|
|
193
|
-
clean.allDrifts = (result.drifts || []).map(d => ({
|
|
194
|
-
type: d.type,
|
|
195
|
-
severity: d.severity,
|
|
196
|
-
description: d.description,
|
|
197
|
-
recommendation: d.recommendation,
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return { content: [{ type: 'text', text: JSON.stringify(clean, null, 2) }] };
|
|
202
|
-
}
|
|
222
|
+
const result = await harmonyAudit({ dir, silent: true });
|
|
223
|
+
const clean = buildMcpHarmonyPayload(result, { verbose });
|
|
224
|
+
return { content: [{ type: 'text', text: JSON.stringify(clean, null, 2) }] };
|
|
225
|
+
}
|
|
203
226
|
|
|
204
227
|
async function handleSetup(input) {
|
|
205
228
|
const { setup } = require('./setup');
|
|
@@ -370,4 +393,17 @@ function main() {
|
|
|
370
393
|
});
|
|
371
394
|
}
|
|
372
395
|
|
|
373
|
-
main
|
|
396
|
+
if (require.main === module) {
|
|
397
|
+
main();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
module.exports = {
|
|
401
|
+
TOOLS,
|
|
402
|
+
buildMcpAuditPayload,
|
|
403
|
+
buildMcpHarmonyPayload,
|
|
404
|
+
handleAudit,
|
|
405
|
+
handleHarmony,
|
|
406
|
+
handleSetup,
|
|
407
|
+
handleDrift,
|
|
408
|
+
main,
|
|
409
|
+
};
|
|
@@ -29,18 +29,39 @@ const P0_SOURCES = [
|
|
|
29
29
|
stalenessThresholdDays: 14,
|
|
30
30
|
verifiedAt: '2026-04-07',
|
|
31
31
|
},
|
|
32
|
-
{
|
|
33
|
-
key: 'opencode-plugin-api',
|
|
34
|
-
label: 'OpenCode Plugin API',
|
|
35
|
-
url: 'https://opencode.ai/docs/plugins/',
|
|
36
|
-
stalenessThresholdDays: 30,
|
|
37
|
-
verifiedAt: '2026-04-07',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
key: 'opencode-
|
|
41
|
-
label: 'OpenCode
|
|
42
|
-
url: 'https://opencode.ai/docs/
|
|
43
|
-
stalenessThresholdDays:
|
|
32
|
+
{
|
|
33
|
+
key: 'opencode-plugin-api',
|
|
34
|
+
label: 'OpenCode Plugin API',
|
|
35
|
+
url: 'https://opencode.ai/docs/plugins/',
|
|
36
|
+
stalenessThresholdDays: 30,
|
|
37
|
+
verifiedAt: '2026-04-07',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: 'opencode-agents-docs',
|
|
41
|
+
label: 'OpenCode Agents',
|
|
42
|
+
url: 'https://opencode.ai/docs/agents/',
|
|
43
|
+
stalenessThresholdDays: 14,
|
|
44
|
+
verifiedAt: '2026-04-10',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'opencode-models-docs',
|
|
48
|
+
label: 'OpenCode Models',
|
|
49
|
+
url: 'https://opencode.ai/docs/models',
|
|
50
|
+
stalenessThresholdDays: 14,
|
|
51
|
+
verifiedAt: '2026-04-10',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
key: 'opencode-github-docs',
|
|
55
|
+
label: 'OpenCode GitHub Integration',
|
|
56
|
+
url: 'https://opencode.ai/docs/github/',
|
|
57
|
+
stalenessThresholdDays: 14,
|
|
58
|
+
verifiedAt: '2026-04-10',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'opencode-permissions-docs',
|
|
62
|
+
label: 'OpenCode Permissions Documentation',
|
|
63
|
+
url: 'https://opencode.ai/docs/permissions/',
|
|
64
|
+
stalenessThresholdDays: 30,
|
|
44
65
|
verifiedAt: '2026-04-07',
|
|
45
66
|
},
|
|
46
67
|
];
|
|
@@ -78,15 +99,39 @@ const PROPAGATION_CHECKLIST = [
|
|
|
78
99
|
'src/opencode/techniques.js — update MCP checks',
|
|
79
100
|
],
|
|
80
101
|
},
|
|
81
|
-
{
|
|
82
|
-
trigger: 'Known security bug fixed or new bug reported',
|
|
83
|
-
targets: [
|
|
84
|
-
'src/opencode/techniques.js — update security checks (E02, E03, D05)',
|
|
85
|
-
'src/opencode/governance.js — update platformCaveats',
|
|
86
|
-
'src/opencode/freshness.js — verify against latest release',
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
|
|
102
|
+
{
|
|
103
|
+
trigger: 'Known security bug fixed or new bug reported',
|
|
104
|
+
targets: [
|
|
105
|
+
'src/opencode/techniques.js — update security checks (E02, E03, D05)',
|
|
106
|
+
'src/opencode/governance.js — update platformCaveats',
|
|
107
|
+
'src/opencode/freshness.js — verify against latest release',
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
trigger: 'OpenCode agent or subagent behavior change',
|
|
112
|
+
targets: [
|
|
113
|
+
'src/opencode/techniques.js — update agent and multi-session checks',
|
|
114
|
+
'src/opencode/governance.js — update permission guidance for plan/build/agent surfaces',
|
|
115
|
+
'src/source-urls.js — refresh OpenCode agent source mappings',
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
trigger: 'OpenCode model catalog or provider-option change',
|
|
120
|
+
targets: [
|
|
121
|
+
'src/opencode/techniques.js — update model-awareness and provider-option assumptions',
|
|
122
|
+
'src/opencode/setup.js — update starter config guidance for model selection',
|
|
123
|
+
'src/source-urls.js — refresh OpenCode model source mappings',
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
trigger: 'OpenCode GitHub integration or workflow contract change',
|
|
128
|
+
targets: [
|
|
129
|
+
'src/opencode/techniques.js — update GitHub/workflow checks',
|
|
130
|
+
'src/opencode/setup.js — update GitHub starter guidance',
|
|
131
|
+
'src/source-urls.js — refresh OpenCode GitHub source mappings',
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
];
|
|
90
135
|
|
|
91
136
|
function checkReleaseGate(sourceVerifications = {}) {
|
|
92
137
|
const now = new Date();
|