@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/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
- // Return clean JSON without ANSI codes
144
- const clean = {
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
- const clean = {
182
- harmonyScore: result.harmonyScore,
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-permissions-docs',
41
- label: 'OpenCode Permissions Documentation',
42
- url: 'https://opencode.ai/docs/permissions/',
43
- stalenessThresholdDays: 30,
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();