@nerviq/cli 0.9.6 → 1.0.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/README.md +154 -14
- package/bin/cli.js +119 -101
- package/package.json +4 -6
- package/src/audit.js +33 -7
- package/src/certification.js +100 -0
- package/CHANGELOG.md +0 -181
- package/content/case-study-template.md +0 -91
- package/content/claims-governance.md +0 -37
- package/content/claude-code/audit-repo/SKILL.md +0 -20
- package/content/claude-native-integration.md +0 -60
- package/content/devto-article.json +0 -9
- package/content/launch-posts.md +0 -226
- package/content/pilot-rollout-kit.md +0 -30
- package/content/release-checklist.md +0 -31
package/README.md
CHANGED
|
@@ -4,23 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@nerviq/cli)
|
|
6
6
|
[](LICENSE)
|
|
7
|
+
[](https://github.com/nerviq/nerviq)
|
|
7
8
|
|
|
8
9
|
---
|
|
9
10
|
|
|
10
|
-
###
|
|
11
|
+
### 8 Platforms Supported
|
|
11
12
|
|
|
12
|
-
Nerviq
|
|
13
|
+
Nerviq v1.0 ships with full audit, setup, governance, and benchmark support for **8 AI coding platforms**:
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
| Platform | Checks | Status |
|
|
16
|
+
|----------|--------|--------|
|
|
17
|
+
| Claude Code | 90 | Full |
|
|
18
|
+
| Codex (OpenAI) | 83 | Full |
|
|
19
|
+
| Gemini CLI (Google) | 83 | Full |
|
|
20
|
+
| GitHub Copilot | 83 | Full |
|
|
21
|
+
| Cursor | 83 | Full |
|
|
22
|
+
| Windsurf | 83 | Full |
|
|
23
|
+
| Aider | 85 | Full |
|
|
24
|
+
| OpenCode | 83 | Full |
|
|
24
25
|
|
|
25
26
|
---
|
|
26
27
|
|
|
@@ -61,7 +62,7 @@ npx @nerviq/cli benchmark # Before/after in isolated copy
|
|
|
61
62
|
|
|
62
63
|
No install required. Zero dependencies.
|
|
63
64
|
|
|
64
|
-
##
|
|
65
|
+
## 673 Checks Across 14 Categories
|
|
65
66
|
|
|
66
67
|
| Category | Checks | Examples |
|
|
67
68
|
|----------|--------|---------|
|
|
@@ -79,11 +80,126 @@ No install required. Zero dependencies.
|
|
|
79
80
|
| Features | 2 | channels, worktrees |
|
|
80
81
|
| Quality Deep | 9 | freshness, contradictions, deprecated patterns |
|
|
81
82
|
|
|
83
|
+
## Harmony — Cross-Platform Alignment
|
|
84
|
+
|
|
85
|
+
Harmony detects drift between your AI coding platforms and keeps them in sync.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx @nerviq/cli harmony-audit # Cross-platform DX audit (0-100 harmony score)
|
|
89
|
+
npx @nerviq/cli harmony-sync # Sync shared config across platforms
|
|
90
|
+
npx @nerviq/cli harmony-drift # Detect drift between platform configs
|
|
91
|
+
npx @nerviq/cli harmony-advise # Cross-platform improvement advice
|
|
92
|
+
npx @nerviq/cli harmony-watch # Live monitoring for config drift
|
|
93
|
+
npx @nerviq/cli harmony-governance # Unified governance across platforms
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Synergy — Multi-Agent Amplification
|
|
97
|
+
|
|
98
|
+
Synergy analyzes how your platforms work together and finds amplification opportunities.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx @nerviq/cli synergy-report # Multi-agent synergy analysis
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Synergy evaluates compound audit results, discovers compensation patterns (where one platform covers another's gaps), and ranks recommendations by cross-platform impact.
|
|
105
|
+
|
|
106
|
+
## SDK — `@nerviq/sdk`
|
|
107
|
+
|
|
108
|
+
Programmatic access to all Nerviq capabilities:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
const { audit, harmonyAudit, synergyReport, detectPlatforms } = require('@nerviq/sdk');
|
|
112
|
+
|
|
113
|
+
const result = await audit('.', 'claude');
|
|
114
|
+
console.log(`Score: ${result.score}/100`);
|
|
115
|
+
|
|
116
|
+
const platforms = detectPlatforms('.');
|
|
117
|
+
console.log(`Active platforms: ${platforms.join(', ')}`);
|
|
118
|
+
|
|
119
|
+
const harmony = await harmonyAudit('.');
|
|
120
|
+
console.log(`Harmony score: ${harmony.harmonyScore}/100`);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## MCP Server — `nerviq serve`
|
|
124
|
+
|
|
125
|
+
Nerviq ships with a built-in MCP-compatible HTTP server for integration with AI agents:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx @nerviq/cli serve --port 3000
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Endpoints:
|
|
132
|
+
- `GET /api/health` — Server health check
|
|
133
|
+
- `GET /api/catalog` — Full check catalog
|
|
134
|
+
- `POST /api/audit` — Run audit on a directory
|
|
135
|
+
- `GET /api/harmony` — Cross-platform harmony data
|
|
136
|
+
|
|
137
|
+
## Plugin System — `nerviq.config.js`
|
|
138
|
+
|
|
139
|
+
Extend Nerviq with custom checks via a config file in your project root:
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
// nerviq.config.js
|
|
143
|
+
module.exports = {
|
|
144
|
+
plugins: [
|
|
145
|
+
{
|
|
146
|
+
name: 'my-company-checks',
|
|
147
|
+
checks: {
|
|
148
|
+
internalDocs: {
|
|
149
|
+
id: 'internalDocs',
|
|
150
|
+
name: 'Internal docs present',
|
|
151
|
+
check: (dir) => require('fs').existsSync(`${dir}/docs/internal.md`),
|
|
152
|
+
impact: 'medium',
|
|
153
|
+
category: 'Quality',
|
|
154
|
+
fix: 'Add docs/internal.md with team-specific guidelines',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
See [docs/plugins.md](docs/plugins.md) for full plugin API reference.
|
|
163
|
+
|
|
164
|
+
## GitHub Action
|
|
165
|
+
|
|
166
|
+
Add Nerviq to your CI pipeline:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
# .github/workflows/nerviq.yml
|
|
170
|
+
name: Nerviq Audit
|
|
171
|
+
on: [push, pull_request]
|
|
172
|
+
|
|
173
|
+
jobs:
|
|
174
|
+
audit:
|
|
175
|
+
runs-on: ubuntu-latest
|
|
176
|
+
steps:
|
|
177
|
+
- uses: actions/checkout@v4
|
|
178
|
+
- uses: nerviq/nerviq@v1
|
|
179
|
+
with:
|
|
180
|
+
threshold: 60
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The action outputs `score`, `passed`, and `total` for use in downstream steps. Fails the workflow if the score is below the configured threshold.
|
|
184
|
+
|
|
185
|
+
## Certification
|
|
186
|
+
|
|
187
|
+
Earn a Nerviq certification badge for your project:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npx @nerviq/cli certify # Run certification and display badge
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Levels:
|
|
194
|
+
- **Gold** — Harmony score >= 80, all platforms >= 70
|
|
195
|
+
- **Silver** — Harmony score >= 60, all platforms >= 50
|
|
196
|
+
- **Bronze** — Any platform >= 40
|
|
197
|
+
|
|
82
198
|
## All Commands
|
|
83
199
|
|
|
84
200
|
| Command | What it does |
|
|
85
201
|
|---------|-------------|
|
|
86
|
-
| `nerviq audit` | Score 0-100 against
|
|
202
|
+
| `nerviq audit` | Score 0-100 against 673 checks |
|
|
87
203
|
| `nerviq audit --lite` | Quick top-3 scan |
|
|
88
204
|
| `nerviq setup` | Generate starter-safe CLAUDE.md + hooks + commands |
|
|
89
205
|
| `nerviq augment` | Repo-aware improvement plan (no writes) |
|
|
@@ -100,7 +216,20 @@ No install required. Zero dependencies.
|
|
|
100
216
|
| `nerviq trend` | Export trend report |
|
|
101
217
|
| `nerviq feedback` | Record recommendation outcomes |
|
|
102
218
|
| `nerviq badge` | shields.io badge for README |
|
|
219
|
+
| `nerviq certify` | Certification level + badge |
|
|
103
220
|
| `nerviq scan dir1 dir2` | Compare multiple repos |
|
|
221
|
+
| `nerviq harmony-audit` | Cross-platform DX audit |
|
|
222
|
+
| `nerviq harmony-sync` | Sync config across platforms |
|
|
223
|
+
| `nerviq harmony-drift` | Detect platform drift |
|
|
224
|
+
| `nerviq harmony-advise` | Cross-platform advice |
|
|
225
|
+
| `nerviq harmony-watch` | Live drift monitoring |
|
|
226
|
+
| `nerviq harmony-governance` | Unified platform governance |
|
|
227
|
+
| `nerviq synergy-report` | Multi-agent synergy analysis |
|
|
228
|
+
| `nerviq catalog` | Show check catalog for all 8 platforms |
|
|
229
|
+
| `nerviq doctor` | Self-diagnostics |
|
|
230
|
+
| `nerviq convert` | Convert config between platforms |
|
|
231
|
+
| `nerviq migrate` | Migrate platform config versions |
|
|
232
|
+
| `nerviq serve` | Start local MCP-compatible HTTP API |
|
|
104
233
|
|
|
105
234
|
## Options
|
|
106
235
|
|
|
@@ -115,6 +244,17 @@ No install required. Zero dependencies.
|
|
|
115
244
|
| `--auto` | Apply without prompts |
|
|
116
245
|
| `--verbose` | Show all recommendations |
|
|
117
246
|
| `--format sarif` | SARIF output for code scanning |
|
|
247
|
+
| `--platform NAME` | Target platform (claude, codex, gemini, copilot, cursor, windsurf, aider, opencode) |
|
|
248
|
+
|
|
249
|
+
## Backed by Research
|
|
250
|
+
|
|
251
|
+
Nerviq is built on the CLAUDEX knowledge engine — the largest verified catalog of AI coding agent techniques:
|
|
252
|
+
|
|
253
|
+
- **315 research documents** covering all 8 platforms
|
|
254
|
+
- **100+ experiments** with tested, rated results
|
|
255
|
+
- **673 checks** each with `sourceUrl` and `confidence` level (0.0-1.0)
|
|
256
|
+
- Every check is traceable to primary documentation or verified experiment
|
|
257
|
+
- 90-day freshness cycle: stale findings are re-verified or pruned
|
|
118
258
|
|
|
119
259
|
## Privacy
|
|
120
260
|
|
package/bin/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ const COMMAND_ALIASES = {
|
|
|
22
22
|
gov: 'governance',
|
|
23
23
|
outcome: 'feedback',
|
|
24
24
|
};
|
|
25
|
-
const KNOWN_COMMANDS = ['audit', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'history', 'compare', 'trend', 'scan', 'feedback', 'doctor', 'convert', 'migrate', 'catalog', 'serve', 'help', 'version'];
|
|
25
|
+
const KNOWN_COMMANDS = ['audit', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'history', 'compare', 'trend', 'scan', 'feedback', 'doctor', 'convert', 'migrate', 'catalog', 'certify', 'serve', 'help', 'version'];
|
|
26
26
|
|
|
27
27
|
function levenshtein(a, b) {
|
|
28
28
|
const matrix = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
|
|
@@ -211,109 +211,99 @@ function parseArgs(rawArgs) {
|
|
|
211
211
|
|
|
212
212
|
const HELP = `
|
|
213
213
|
nerviq v${version}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
--
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
--
|
|
268
|
-
--
|
|
269
|
-
--
|
|
270
|
-
--
|
|
271
|
-
--
|
|
272
|
-
--
|
|
273
|
-
--
|
|
274
|
-
--
|
|
275
|
-
--
|
|
276
|
-
--
|
|
277
|
-
--snapshot
|
|
278
|
-
--lite
|
|
279
|
-
--dry-run
|
|
280
|
-
--verbose
|
|
281
|
-
--json
|
|
282
|
-
--auto
|
|
283
|
-
--
|
|
284
|
-
--
|
|
285
|
-
--
|
|
286
|
-
|
|
287
|
-
|
|
214
|
+
The intelligent nervous system for AI coding agents.
|
|
215
|
+
Audit, align, and amplify every platform on every project.
|
|
216
|
+
|
|
217
|
+
DISCOVER
|
|
218
|
+
nerviq audit Score your project (0-100)
|
|
219
|
+
nerviq audit --platform X Audit specific platform (claude|codex|cursor|copilot|gemini|windsurf|aider|opencode)
|
|
220
|
+
nerviq audit --lite Quick scan: top 3 gaps + next command
|
|
221
|
+
nerviq audit --json Machine-readable JSON output (for CI)
|
|
222
|
+
nerviq scan dir1 dir2 Compare multiple repos side-by-side
|
|
223
|
+
nerviq catalog Full check catalog (all 8 platforms)
|
|
224
|
+
nerviq catalog --json Export full check catalog as JSON
|
|
225
|
+
|
|
226
|
+
SETUP
|
|
227
|
+
nerviq setup Generate starter-safe baseline config files
|
|
228
|
+
nerviq setup --auto Apply all generated files without prompts
|
|
229
|
+
nerviq interactive Step-by-step guided wizard
|
|
230
|
+
nerviq doctor Self-diagnostics: Node, deps, freshness, platform detection
|
|
231
|
+
|
|
232
|
+
IMPROVE
|
|
233
|
+
nerviq augment Improvement plan (no writes)
|
|
234
|
+
nerviq suggest-only Structured report for sharing (no writes)
|
|
235
|
+
nerviq plan Export proposal bundles with diffs
|
|
236
|
+
nerviq plan --out plan.json Save plan to file
|
|
237
|
+
nerviq apply Apply proposals selectively with rollback
|
|
238
|
+
nerviq apply --dry-run Preview changes without writing
|
|
239
|
+
|
|
240
|
+
GOVERN
|
|
241
|
+
nerviq governance Permission profiles + hooks + policy packs
|
|
242
|
+
nerviq governance --json Machine-readable governance summary
|
|
243
|
+
nerviq benchmark Before/after score in isolated temp copy
|
|
244
|
+
nerviq certify Generate certification badge for your project
|
|
245
|
+
|
|
246
|
+
CROSS-PLATFORM
|
|
247
|
+
nerviq harmony-audit Drift detection across all active platforms
|
|
248
|
+
nerviq synergy-report Multi-agent amplification opportunities
|
|
249
|
+
nerviq convert --from X --to Y Convert configs between platforms
|
|
250
|
+
nerviq migrate --platform X Platform version migration helper
|
|
251
|
+
nerviq migrate --platform cursor --from v2 --to v3
|
|
252
|
+
|
|
253
|
+
MONITOR
|
|
254
|
+
nerviq watch Live config monitoring (re-audits on file change)
|
|
255
|
+
nerviq history Score history from saved snapshots
|
|
256
|
+
nerviq compare Latest vs previous snapshot diff
|
|
257
|
+
nerviq trend Score trend over time
|
|
258
|
+
nerviq trend --out report.md Export trend report as markdown
|
|
259
|
+
nerviq feedback Record recommendation outcomes
|
|
260
|
+
|
|
261
|
+
ADVANCED
|
|
262
|
+
nerviq deep-review AI-powered config review (opt-in, uses API key)
|
|
263
|
+
nerviq serve --port 3000 Start local Nerviq REST API server
|
|
264
|
+
nerviq badge Generate shields.io badge markdown
|
|
265
|
+
|
|
266
|
+
OPTIONS
|
|
267
|
+
--platform NAME Platform: claude (default), codex, cursor, copilot, gemini, windsurf, aider, opencode
|
|
268
|
+
--threshold N Exit code 1 if score < N (CI gate)
|
|
269
|
+
--require A,B Exit code 1 if named checks fail
|
|
270
|
+
--out FILE Write output to file (JSON or markdown)
|
|
271
|
+
--plan FILE Load previously exported plan file
|
|
272
|
+
--only A,B Limit plan/apply to selected proposal IDs
|
|
273
|
+
--profile NAME Permission profile: read-only | suggest-only | safe-write | power-user
|
|
274
|
+
--mcp-pack A,B Merge MCP packs into setup (e.g. context7-docs,next-devtools)
|
|
275
|
+
--format NAME Output format: json | sarif
|
|
276
|
+
--port N Port for \`serve\` (default: 3000)
|
|
277
|
+
--snapshot Save snapshot artifact under .claude/nerviq/snapshots/
|
|
278
|
+
--lite Short top-3 scan with one clear next step
|
|
279
|
+
--dry-run Preview changes without writing files
|
|
280
|
+
--verbose Show all checks (not just critical/high)
|
|
281
|
+
--json Output as JSON
|
|
282
|
+
--auto Apply all generated files without prompting
|
|
283
|
+
--key NAME Feedback: recommendation key (e.g. permissionDeny)
|
|
284
|
+
--status VALUE Feedback: accepted | rejected | deferred
|
|
285
|
+
--effect VALUE Feedback: positive | neutral | negative
|
|
286
|
+
--score-delta N Feedback: observed score delta
|
|
287
|
+
--help Show this help
|
|
288
|
+
--version Show version
|
|
289
|
+
|
|
290
|
+
EXAMPLES
|
|
288
291
|
npx nerviq
|
|
289
292
|
npx nerviq --lite
|
|
290
|
-
npx nerviq --platform
|
|
293
|
+
npx nerviq --platform cursor
|
|
291
294
|
npx nerviq --platform codex augment
|
|
292
|
-
npx nerviq
|
|
293
|
-
npx nerviq
|
|
294
|
-
npx nerviq --
|
|
295
|
-
npx nerviq --platform
|
|
296
|
-
npx nerviq --snapshot
|
|
297
|
-
npx nerviq augment
|
|
298
|
-
npx nerviq augment --snapshot
|
|
299
|
-
npx nerviq suggest-only --json
|
|
300
|
-
npx nerviq governance --snapshot
|
|
301
|
-
npx nerviq plan --out claudex-plan.json
|
|
302
|
-
npx nerviq plan --profile safe-write
|
|
295
|
+
npx nerviq scan ./app ./api ./infra
|
|
296
|
+
npx nerviq harmony-audit
|
|
297
|
+
npx nerviq convert --from claude --to codex
|
|
298
|
+
npx nerviq migrate --platform cursor --from v2 --to v3
|
|
303
299
|
npx nerviq setup --mcp-pack context7-docs
|
|
304
|
-
npx nerviq apply --plan
|
|
305
|
-
npx nerviq
|
|
306
|
-
npx nerviq
|
|
307
|
-
npx nerviq
|
|
308
|
-
npx nerviq
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
npx nerviq serve --port 3000
|
|
312
|
-
npx nerviq --json --threshold 60
|
|
313
|
-
npx nerviq setup --auto
|
|
314
|
-
npx nerviq interactive
|
|
315
|
-
|
|
316
|
-
Exit codes:
|
|
300
|
+
npx nerviq apply --plan plan.json --only hooks,commands
|
|
301
|
+
npx nerviq serve --port 4000
|
|
302
|
+
npx nerviq --json --threshold 70
|
|
303
|
+
npx nerviq catalog --json --out catalog.json
|
|
304
|
+
npx nerviq feedback --key permissionDeny --status accepted --effect positive
|
|
305
|
+
|
|
306
|
+
EXIT CODES
|
|
317
307
|
0 Success
|
|
318
308
|
1 Error, unknown command, or score below --threshold
|
|
319
309
|
`;
|
|
@@ -413,7 +403,7 @@ async function main() {
|
|
|
413
403
|
const FULL_COMMAND_SET = new Set([
|
|
414
404
|
'audit', 'scan', 'badge', 'augment', 'suggest-only', 'setup', 'plan', 'apply',
|
|
415
405
|
'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'insights',
|
|
416
|
-
'history', 'compare', 'trend', 'feedback', 'catalog', 'serve', 'help', 'version',
|
|
406
|
+
'history', 'compare', 'trend', 'feedback', 'catalog', 'certify', 'serve', 'help', 'version',
|
|
417
407
|
// Harmony + Synergy (cross-platform)
|
|
418
408
|
'harmony-audit', 'harmony-sync', 'harmony-drift', 'harmony-advise',
|
|
419
409
|
'harmony-watch', 'harmony-governance', 'synergy-report',
|
|
@@ -768,6 +758,34 @@ async function main() {
|
|
|
768
758
|
}
|
|
769
759
|
}
|
|
770
760
|
process.exit(0);
|
|
761
|
+
} else if (normalizedCommand === 'certify') {
|
|
762
|
+
const { certifyProject, generateCertBadge } = require('../src/certification');
|
|
763
|
+
const certResult = await certifyProject(options.dir);
|
|
764
|
+
if (options.json) {
|
|
765
|
+
console.log(JSON.stringify(certResult, null, 2));
|
|
766
|
+
} else {
|
|
767
|
+
console.log('');
|
|
768
|
+
console.log('\x1b[1m nerviq certification\x1b[0m');
|
|
769
|
+
console.log('\x1b[2m ═══════════════════════════════════════\x1b[0m');
|
|
770
|
+
console.log('');
|
|
771
|
+
console.log(` Level: \x1b[1m${certResult.level}\x1b[0m`);
|
|
772
|
+
console.log(` Harmony Score: ${certResult.harmonyScore}/100`);
|
|
773
|
+
console.log('');
|
|
774
|
+
if (Object.keys(certResult.platformScores).length > 0) {
|
|
775
|
+
console.log(' Platform Scores:');
|
|
776
|
+
for (const [plat, score] of Object.entries(certResult.platformScores)) {
|
|
777
|
+
const scoreColor = score >= 70 ? '\x1b[32m' : score >= 40 ? '\x1b[33m' : '\x1b[31m';
|
|
778
|
+
console.log(` ${plat.padEnd(12)} ${scoreColor}${score}/100\x1b[0m`);
|
|
779
|
+
}
|
|
780
|
+
console.log('');
|
|
781
|
+
}
|
|
782
|
+
console.log(' Badge:');
|
|
783
|
+
console.log(` ${certResult.badge}`);
|
|
784
|
+
console.log('');
|
|
785
|
+
console.log(' Add the badge to your README.md');
|
|
786
|
+
console.log('');
|
|
787
|
+
}
|
|
788
|
+
process.exit(0);
|
|
771
789
|
} else if (normalizedCommand === 'serve') {
|
|
772
790
|
const server = await startServer({
|
|
773
791
|
port: options.port == null ? 3000 : options.port,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerviq/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The intelligent nervous system for AI coding agents —
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "The intelligent nervous system for AI coding agents — 673 checks across 8 platforms. Audit, align, and amplify.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"nerviq": "bin/cli.js",
|
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"bin",
|
|
12
|
-
"content",
|
|
13
12
|
"src",
|
|
14
|
-
"README.md"
|
|
15
|
-
"CHANGELOG.md"
|
|
13
|
+
"README.md"
|
|
16
14
|
],
|
|
17
15
|
"scripts": {
|
|
18
16
|
"start": "node bin/cli.js",
|
|
@@ -20,7 +18,7 @@
|
|
|
20
18
|
"test": "node test/run.js",
|
|
21
19
|
"test:jest": "jest",
|
|
22
20
|
"test:coverage": "jest --coverage",
|
|
23
|
-
"test:all": "
|
|
21
|
+
"test:all": "npm test && npx jest && node test/check-matrix.js && node test/codex-check-matrix.js && node test/gemini-check-matrix.js && node test/copilot-check-matrix.js && node test/cursor-check-matrix.js && node test/golden-matrix.js && node test/codex-golden-matrix.js && node test/gemini-golden-matrix.js && node test/copilot-golden-matrix.js && node test/cursor-golden-matrix.js",
|
|
24
22
|
"benchmark:perf": "node tools/benchmark.js",
|
|
25
23
|
"catalog": "node -e \"const {generateCatalog}=require('./src/catalog');console.log(JSON.stringify(generateCatalog(),null,2))\""
|
|
26
24
|
},
|
package/src/audit.js
CHANGED
|
@@ -25,6 +25,7 @@ const { OpenCodeProjectContext } = require('./opencode/context');
|
|
|
25
25
|
const { getBadgeMarkdown } = require('./badge');
|
|
26
26
|
const { sendInsights, getLocalInsights } = require('./insights');
|
|
27
27
|
const { getRecommendationOutcomeSummary, getRecommendationAdjustment } = require('./activity');
|
|
28
|
+
const { getFeedbackSummary } = require('./feedback');
|
|
28
29
|
const { formatSarif } = require('./formatters/sarif');
|
|
29
30
|
const { loadPlugins, mergePluginChecks } = require('./plugins');
|
|
30
31
|
|
|
@@ -441,24 +442,48 @@ function getQuickWins(failed, options = {}) {
|
|
|
441
442
|
.slice(0, 3);
|
|
442
443
|
}
|
|
443
444
|
|
|
444
|
-
|
|
445
|
+
/**
|
|
446
|
+
* Compute a multiplier based on FP (helpful/not-helpful) feedback for a check key.
|
|
447
|
+
* - >50% "not helpful" feedback: lower priority by 30% (multiplier 0.7)
|
|
448
|
+
* - >80% "helpful" feedback: boost priority by 20% (multiplier 1.2)
|
|
449
|
+
* - Otherwise: no change (multiplier 1.0)
|
|
450
|
+
* @param {Object} fpFeedbackByKey - Keyed feedback summary from getFeedbackSummary().byKey
|
|
451
|
+
* @param {string} key - The check key to look up
|
|
452
|
+
* @returns {number} Multiplier to apply to priority score
|
|
453
|
+
*/
|
|
454
|
+
function getFpFeedbackMultiplier(fpFeedbackByKey, key) {
|
|
455
|
+
if (!fpFeedbackByKey) return 1.0;
|
|
456
|
+
const bucket = fpFeedbackByKey[key];
|
|
457
|
+
if (!bucket || bucket.total === 0) return 1.0;
|
|
458
|
+
|
|
459
|
+
const unhelpfulRate = bucket.unhelpful / bucket.total;
|
|
460
|
+
const helpfulRate = bucket.helpful / bucket.total;
|
|
461
|
+
|
|
462
|
+
if (unhelpfulRate > 0.5) return 0.7;
|
|
463
|
+
if (helpfulRate > 0.8) return 1.2;
|
|
464
|
+
return 1.0;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function getRecommendationPriorityScore(item, outcomeSummaryByKey = {}, fpFeedbackByKey = null) {
|
|
445
468
|
const impactScore = (IMPACT_ORDER[item.impact] ?? 0) * 100;
|
|
446
469
|
const feedbackAdjustment = getRecommendationAdjustment(outcomeSummaryByKey, item.key);
|
|
447
470
|
const brevityPenalty = Math.min((item.fix || '').length, 240) / 20;
|
|
448
|
-
|
|
471
|
+
const raw = impactScore + (feedbackAdjustment * 10) - brevityPenalty;
|
|
472
|
+
return raw * getFpFeedbackMultiplier(fpFeedbackByKey, item.key);
|
|
449
473
|
}
|
|
450
474
|
|
|
451
475
|
function buildTopNextActions(failed, limit = 5, outcomeSummaryByKey = {}, options = {}) {
|
|
452
476
|
const pool = getPrioritizedFailed(failed);
|
|
477
|
+
const fpByKey = options.fpFeedbackByKey || null;
|
|
453
478
|
|
|
454
479
|
return [...pool]
|
|
455
480
|
.sort((a, b) => {
|
|
456
481
|
const scoreB = options.platform === 'codex'
|
|
457
482
|
? codexPriorityScore(b, outcomeSummaryByKey)
|
|
458
|
-
: getRecommendationPriorityScore(b, outcomeSummaryByKey);
|
|
483
|
+
: getRecommendationPriorityScore(b, outcomeSummaryByKey, fpByKey);
|
|
459
484
|
const scoreA = options.platform === 'codex'
|
|
460
485
|
? codexPriorityScore(a, outcomeSummaryByKey)
|
|
461
|
-
: getRecommendationPriorityScore(a, outcomeSummaryByKey);
|
|
486
|
+
: getRecommendationPriorityScore(a, outcomeSummaryByKey, fpByKey);
|
|
462
487
|
return scoreB - scoreA;
|
|
463
488
|
})
|
|
464
489
|
.slice(0, limit)
|
|
@@ -479,7 +504,7 @@ function buildTopNextActions(failed, limit = 5, outcomeSummaryByKey = {}, option
|
|
|
479
504
|
const evidenceClass = options.platform === 'codex' ? codexEvidenceClass(fullItem) : (feedback ? 'measured' : 'estimated');
|
|
480
505
|
const priorityScore = options.platform === 'codex'
|
|
481
506
|
? codexPriorityScore(fullItem, outcomeSummaryByKey)
|
|
482
|
-
: Math.max(0, Math.min(100, Math.round(getRecommendationPriorityScore(fullItem, outcomeSummaryByKey) / 3)));
|
|
507
|
+
: Math.max(0, Math.min(100, Math.round(getRecommendationPriorityScore(fullItem, outcomeSummaryByKey, fpByKey) / 3)));
|
|
483
508
|
|
|
484
509
|
signals.push(`evidence:${evidenceClass}`);
|
|
485
510
|
if (options.platform === 'codex' && CODEX_HARD_FAIL_KEYS.has(key)) {
|
|
@@ -728,6 +753,7 @@ async function audit(options) {
|
|
|
728
753
|
const stacks = ctx.detectStacks(STACKS);
|
|
729
754
|
const results = [];
|
|
730
755
|
const outcomeSummary = getRecommendationOutcomeSummary(options.dir);
|
|
756
|
+
const fpFeedback = getFeedbackSummary(options.dir);
|
|
731
757
|
|
|
732
758
|
// Load and merge plugin checks
|
|
733
759
|
const plugins = loadPlugins(options.dir);
|
|
@@ -795,7 +821,7 @@ async function audit(options) {
|
|
|
795
821
|
const organicEarned = organicPassed.reduce((sum, r) => sum + (WEIGHTS[r.impact] || 5), 0);
|
|
796
822
|
const organicScore = maxScore > 0 ? Math.round((organicEarned / maxScore) * 100) : 0;
|
|
797
823
|
const quickWins = getQuickWins(failed, { platform: spec.platform });
|
|
798
|
-
const topNextActions = buildTopNextActions(failed, 5, outcomeSummary.byKey, { platform: spec.platform });
|
|
824
|
+
const topNextActions = buildTopNextActions(failed, 5, outcomeSummary.byKey, { platform: spec.platform, fpFeedbackByKey: fpFeedback.byKey });
|
|
799
825
|
const categoryScores = computeCategoryScores(applicable, passed);
|
|
800
826
|
const platformScopeNote = getPlatformScopeNote(spec, ctx);
|
|
801
827
|
const platformCaveats = getPlatformCaveats(spec, ctx);
|
|
@@ -1008,4 +1034,4 @@ async function audit(options) {
|
|
|
1008
1034
|
return result;
|
|
1009
1035
|
}
|
|
1010
1036
|
|
|
1011
|
-
module.exports = { audit, buildTopNextActions };
|
|
1037
|
+
module.exports = { audit, buildTopNextActions, getFpFeedbackMultiplier, getRecommendationPriorityScore };
|