@nerviq/cli 1.5.1 → 1.5.2
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 +19 -2
- package/bin/cli.js +123 -6
- package/package.json +1 -1
- package/src/analyze.js +1 -1
- package/src/audit.js +29 -6
package/README.md
CHANGED
|
@@ -67,8 +67,8 @@ Nerviq scores your AI coding agent setup from 0 to 100, finds what's missing, an
|
|
|
67
67
|
## Quick Start
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
npx @nerviq/cli audit #
|
|
71
|
-
npx @nerviq/cli audit --
|
|
70
|
+
npx @nerviq/cli audit # Quick scan: score + top 3 actions
|
|
71
|
+
npx @nerviq/cli audit --full # Full audit with all checks + badge
|
|
72
72
|
npx @nerviq/cli setup # Generate starter-safe baseline
|
|
73
73
|
npx @nerviq/cli augment # Improvement plan, no writes
|
|
74
74
|
npx @nerviq/cli governance # Permission profiles + policy packs
|
|
@@ -226,6 +226,8 @@ Levels:
|
|
|
226
226
|
|---------|-------------|
|
|
227
227
|
| `nerviq audit` | Score 0-100 against 2,431 checks |
|
|
228
228
|
| `nerviq audit --lite` | Quick top-3 scan |
|
|
229
|
+
| `nerviq fix <key>` | Auto-fix a specific check (shows score impact) |
|
|
230
|
+
| `nerviq fix --all-critical` | Fix all critical issues at once |
|
|
229
231
|
| `nerviq setup` | Generate starter-safe CLAUDE.md + hooks + commands |
|
|
230
232
|
| `nerviq augment` | Repo-aware improvement plan (no writes) |
|
|
231
233
|
| `nerviq suggest-only` | Structured report for sharing |
|
|
@@ -281,6 +283,21 @@ Nerviq is built on the CLAUDEX knowledge engine — the largest verified catalog
|
|
|
281
283
|
- Every check is traceable to primary documentation or verified experiment
|
|
282
284
|
- 90-day freshness cycle: stale findings are re-verified or pruned
|
|
283
285
|
|
|
286
|
+
## Safety Modes
|
|
287
|
+
|
|
288
|
+
Nerviq provides explicit safety controls so you decide what it can touch:
|
|
289
|
+
|
|
290
|
+
| Mode | Flag | What it does |
|
|
291
|
+
|------|------|-------------|
|
|
292
|
+
| **Read-only** | `nerviq audit` | Reads files, writes nothing. Default command. |
|
|
293
|
+
| **Suggest-only** | `nerviq suggest-only` | Generates markdown report, no file writes. |
|
|
294
|
+
| **Dry-run** | `--dry-run` | Previews setup/fix/apply changes without writing. |
|
|
295
|
+
| **Config-only** | `--config-only` | Only writes config files (.claude/, rules, hooks). Never touches source code. |
|
|
296
|
+
| **Safe-write** | `--profile safe-write` | Default write profile. Creates new files, never overwrites existing ones. |
|
|
297
|
+
| **Power-user** | `--profile power-user` | Overwrites existing files (use with `--snapshot` for rollback). |
|
|
298
|
+
|
|
299
|
+
Every write command supports `--snapshot` for automatic backup before changes.
|
|
300
|
+
|
|
284
301
|
## Privacy
|
|
285
302
|
|
|
286
303
|
- **Zero dependencies** — nothing to audit
|
package/bin/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ const COMMAND_ALIASES = {
|
|
|
26
26
|
gov: 'governance',
|
|
27
27
|
outcome: 'feedback',
|
|
28
28
|
};
|
|
29
|
-
const KNOWN_COMMANDS = ['audit', 'org', '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', 'harmony-audit', 'harmony-sync', 'harmony-drift', 'harmony-advise', 'harmony-watch', 'harmony-governance', 'harmony-add', 'synergy-report', 'anti-patterns', 'rules-export', 'freshness', 'help', 'version'];
|
|
29
|
+
const KNOWN_COMMANDS = ['audit', 'org', 'setup', 'augment', 'suggest-only', 'plan', 'apply', 'fix', 'governance', 'benchmark', 'deep-review', 'interactive', 'watch', 'badge', 'insights', 'history', 'compare', 'trend', 'scan', 'feedback', 'doctor', 'convert', 'migrate', 'catalog', 'certify', 'serve', 'harmony-audit', 'harmony-sync', 'harmony-drift', 'harmony-advise', 'harmony-watch', 'harmony-governance', 'harmony-add', 'synergy-report', 'anti-patterns', 'rules-export', 'freshness', 'help', 'version'];
|
|
30
30
|
|
|
31
31
|
function levenshtein(a, b) {
|
|
32
32
|
const matrix = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
|
|
@@ -289,9 +289,9 @@ const HELP = `
|
|
|
289
289
|
Audit, align, and amplify every platform on every project.
|
|
290
290
|
|
|
291
291
|
DISCOVER
|
|
292
|
-
nerviq audit
|
|
292
|
+
nerviq audit Quick scan: score + top 3 gaps (default)
|
|
293
|
+
nerviq audit --full Full audit with all checks, weakest areas, badge
|
|
293
294
|
nerviq audit --platform X Audit specific platform (claude|codex|cursor|copilot|gemini|windsurf|aider|opencode)
|
|
294
|
-
nerviq audit --lite Quick scan: top 3 gaps + next command
|
|
295
295
|
nerviq audit --json Machine-readable JSON output (for CI)
|
|
296
296
|
nerviq audit --workspace packages/* Audit each workspace in a monorepo
|
|
297
297
|
nerviq scan dir1 dir2 Compare multiple repos side-by-side
|
|
@@ -307,6 +307,12 @@ const HELP = `
|
|
|
307
307
|
nerviq interactive Step-by-step guided wizard
|
|
308
308
|
nerviq doctor Self-diagnostics: Node, deps, freshness, platform detection
|
|
309
309
|
|
|
310
|
+
FIX
|
|
311
|
+
nerviq fix Show fixable checks and manual-fix guidance
|
|
312
|
+
nerviq fix <key> Auto-fix a specific check (with score impact)
|
|
313
|
+
nerviq fix --all-critical Fix all critical issues at once
|
|
314
|
+
nerviq fix --dry-run Preview fixes without writing
|
|
315
|
+
|
|
310
316
|
IMPROVE
|
|
311
317
|
nerviq augment Improvement plan (no writes)
|
|
312
318
|
nerviq suggest-only Structured report for sharing (no writes)
|
|
@@ -365,9 +371,11 @@ const HELP = `
|
|
|
365
371
|
--port N Port for \`serve\` (default: 3000)
|
|
366
372
|
--workspace GLOBS Audit workspaces separately (e.g. packages/* or apps/web,apps/api)
|
|
367
373
|
--snapshot Save snapshot artifact under .claude/nerviq/snapshots/
|
|
368
|
-
--
|
|
374
|
+
--full Show full audit output (all checks, weakest areas, badge)
|
|
375
|
+
--lite Short top-3 scan (default behavior since v1.5.2)
|
|
369
376
|
--dry-run Preview changes without writing files
|
|
370
|
-
--
|
|
377
|
+
--config-only Only write config files (.claude/, rules, hooks) — never source code
|
|
378
|
+
--verbose Full audit + medium-priority recommendations
|
|
371
379
|
--json Output as JSON
|
|
372
380
|
--auto Apply all generated files without prompting
|
|
373
381
|
--key NAME Feedback: recommendation key (e.g. permissionDeny)
|
|
@@ -425,12 +433,14 @@ async function main() {
|
|
|
425
433
|
verbose: flags.includes('--verbose'),
|
|
426
434
|
json: flags.includes('--json'),
|
|
427
435
|
auto: flags.includes('--auto'),
|
|
428
|
-
lite: flags.includes('--
|
|
436
|
+
lite: flags.includes('--full') || flags.includes('--verbose') ? false : true,
|
|
437
|
+
full: flags.includes('--full'),
|
|
429
438
|
snapshot: flags.includes('--snapshot'),
|
|
430
439
|
feedback: flags.includes('--feedback'),
|
|
431
440
|
fix: flags.includes('--fix'),
|
|
432
441
|
autoSync: flags.includes('--auto-sync'),
|
|
433
442
|
dryRun: flags.includes('--dry-run'),
|
|
443
|
+
configOnly: flags.includes('--config-only'),
|
|
434
444
|
threshold: parsed.threshold !== null ? Number(parsed.threshold) : null,
|
|
435
445
|
out: parsed.out,
|
|
436
446
|
planFile: parsed.planFile,
|
|
@@ -1101,6 +1111,113 @@ async function main() {
|
|
|
1101
1111
|
});
|
|
1102
1112
|
console.log(output);
|
|
1103
1113
|
process.exit(0);
|
|
1114
|
+
} else if (normalizedCommand === 'fix') {
|
|
1115
|
+
// nerviq fix [key] [--all-critical] [--dry-run]
|
|
1116
|
+
const fixKey = parsed.extraArgs[0] || null;
|
|
1117
|
+
const allCritical = flags.includes('--all-critical');
|
|
1118
|
+
|
|
1119
|
+
// Step 1: Run silent audit to find failed checks
|
|
1120
|
+
const auditResult = await audit({ dir: options.dir, silent: true, platform: options.platform });
|
|
1121
|
+
const failedResults = (auditResult.results || []).filter(r => !r.passed);
|
|
1122
|
+
|
|
1123
|
+
if (failedResults.length === 0) {
|
|
1124
|
+
console.log('\n ✅ All checks passing — nothing to fix.\n');
|
|
1125
|
+
process.exit(0);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// Step 2: Determine which checks to fix
|
|
1129
|
+
const { TECHNIQUES } = require('../src/techniques');
|
|
1130
|
+
let targetKeys = [];
|
|
1131
|
+
|
|
1132
|
+
if (fixKey) {
|
|
1133
|
+
// Fix a specific check
|
|
1134
|
+
if (!failedResults.find(r => r.key === fixKey)) {
|
|
1135
|
+
const passed = (auditResult.results || []).find(r => r.key === fixKey && r.passed);
|
|
1136
|
+
if (passed) {
|
|
1137
|
+
console.log(`\n ✅ '${fixKey}' is already passing.\n`);
|
|
1138
|
+
} else {
|
|
1139
|
+
console.log(`\n Error: Unknown check key '${fixKey}'.`);
|
|
1140
|
+
console.log(` Fix: Run 'nerviq audit --full' to see all check keys.\n`);
|
|
1141
|
+
}
|
|
1142
|
+
process.exit(1);
|
|
1143
|
+
}
|
|
1144
|
+
targetKeys = [fixKey];
|
|
1145
|
+
} else if (allCritical) {
|
|
1146
|
+
targetKeys = failedResults.filter(r => r.impact === 'critical').map(r => r.key);
|
|
1147
|
+
if (targetKeys.length === 0) {
|
|
1148
|
+
console.log('\n ✅ No critical issues found.\n');
|
|
1149
|
+
process.exit(0);
|
|
1150
|
+
}
|
|
1151
|
+
} else {
|
|
1152
|
+
// No key specified — show fixable checks and exit
|
|
1153
|
+
const fixable = failedResults.filter(r => TECHNIQUES[r.key] && TECHNIQUES[r.key].template);
|
|
1154
|
+
const nonFixable = failedResults.filter(r => !TECHNIQUES[r.key] || !TECHNIQUES[r.key].template);
|
|
1155
|
+
console.log('');
|
|
1156
|
+
console.log(` nerviq fix — ${failedResults.length} failed checks\n`);
|
|
1157
|
+
if (fixable.length > 0) {
|
|
1158
|
+
console.log(` Auto-fixable (${fixable.length}):`);
|
|
1159
|
+
for (const r of fixable) {
|
|
1160
|
+
const tier = r.impact === 'critical' ? '🔴' : r.impact === 'high' ? '🟡' : '🔵';
|
|
1161
|
+
console.log(` ${tier} nerviq fix ${r.key}`);
|
|
1162
|
+
}
|
|
1163
|
+
console.log('');
|
|
1164
|
+
}
|
|
1165
|
+
if (nonFixable.length > 0) {
|
|
1166
|
+
console.log(` Manual fix needed (${nonFixable.length}):`);
|
|
1167
|
+
for (const r of nonFixable.slice(0, 5)) {
|
|
1168
|
+
const tier = r.impact === 'critical' ? '🔴' : r.impact === 'high' ? '🟡' : '🔵';
|
|
1169
|
+
console.log(` ${tier} ${r.key}: ${r.fix}`);
|
|
1170
|
+
}
|
|
1171
|
+
if (nonFixable.length > 5) {
|
|
1172
|
+
console.log(` ... and ${nonFixable.length - 5} more (use --full to see all)`);
|
|
1173
|
+
}
|
|
1174
|
+
console.log('');
|
|
1175
|
+
}
|
|
1176
|
+
if (fixable.length > 0) {
|
|
1177
|
+
console.log(` Quick actions:`);
|
|
1178
|
+
console.log(` nerviq fix ${fixable[0].key} Fix the first auto-fixable check`);
|
|
1179
|
+
console.log(` nerviq fix --all-critical Fix all critical issues at once`);
|
|
1180
|
+
}
|
|
1181
|
+
console.log('');
|
|
1182
|
+
process.exit(0);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Step 3: For each target, either use template or show manual instructions
|
|
1186
|
+
const preScore = auditResult.score;
|
|
1187
|
+
let fixed = 0;
|
|
1188
|
+
let manual = 0;
|
|
1189
|
+
|
|
1190
|
+
for (const key of targetKeys) {
|
|
1191
|
+
const technique = TECHNIQUES[key];
|
|
1192
|
+
const failedCheck = failedResults.find(r => r.key === key);
|
|
1193
|
+
|
|
1194
|
+
if (technique && technique.template) {
|
|
1195
|
+
if (options.dryRun) {
|
|
1196
|
+
console.log(`\n [dry-run] Would fix: ${failedCheck.name} (${key})`);
|
|
1197
|
+
fixed++;
|
|
1198
|
+
} else {
|
|
1199
|
+
// Use setup with only this key
|
|
1200
|
+
await setup({ ...options, only: [key], silent: true });
|
|
1201
|
+
console.log(` ✅ Fixed: ${failedCheck.name}`);
|
|
1202
|
+
fixed++;
|
|
1203
|
+
}
|
|
1204
|
+
} else {
|
|
1205
|
+
console.log(` 📋 ${failedCheck.name} (manual fix needed)`);
|
|
1206
|
+
console.log(` ${failedCheck.fix}`);
|
|
1207
|
+
manual++;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// Step 4: Show score impact
|
|
1212
|
+
if (fixed > 0 && !options.dryRun) {
|
|
1213
|
+
const postResult = await audit({ dir: options.dir, silent: true, platform: options.platform });
|
|
1214
|
+
const delta = postResult.score - preScore;
|
|
1215
|
+
console.log('');
|
|
1216
|
+
console.log(` Score: ${preScore} → ${postResult.score} (${delta >= 0 ? '+' : ''}${delta})`);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
console.log(`\n ${fixed} fixed, ${manual} need manual action.\n`);
|
|
1220
|
+
|
|
1104
1221
|
} else if (normalizedCommand === 'setup') {
|
|
1105
1222
|
await setup(options);
|
|
1106
1223
|
if (options.snapshot) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerviq/cli",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "The intelligent nervous system for AI coding agents — 2,431 checks across 8 platforms, 10 languages, and 62 domain packs. Audit, align, and amplify.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/analyze.js
CHANGED
|
@@ -697,7 +697,7 @@ function printAnalysis(report, options = {}) {
|
|
|
697
697
|
*/
|
|
698
698
|
function exportMarkdown(report) {
|
|
699
699
|
const lines = [];
|
|
700
|
-
lines.push(`#
|
|
700
|
+
lines.push(`# Nerviq Analysis Report`);
|
|
701
701
|
lines.push(`## ${report.platformLabel} ${report.mode === 'suggest-only' ? 'Suggest-Only' : 'Augment'} Mode`);
|
|
702
702
|
lines.push('');
|
|
703
703
|
lines.push(`**Project:** ${report.projectSummary.name}${report.projectSummary.description ? ` — ${report.projectSummary.description}` : ''}`);
|
package/src/audit.js
CHANGED
|
@@ -532,6 +532,12 @@ function confidenceFromImpact(impact) {
|
|
|
532
532
|
return impact === 'critical' || impact === 'high' ? 'high' : 'medium';
|
|
533
533
|
}
|
|
534
534
|
|
|
535
|
+
function confidenceLabel(confidence) {
|
|
536
|
+
if (confidence >= 0.8) return 'HIGH';
|
|
537
|
+
if (confidence >= 0.5) return 'MEDIUM';
|
|
538
|
+
return 'HEURISTIC';
|
|
539
|
+
}
|
|
540
|
+
|
|
535
541
|
function getPrioritizedFailed(failed) {
|
|
536
542
|
const prioritized = failed.filter(r => !(r.category === 'hygiene' && r.impact === 'low'));
|
|
537
543
|
return prioritized.length > 0 ? prioritized : failed;
|
|
@@ -901,18 +907,32 @@ function printLiteAudit(result, dir) {
|
|
|
901
907
|
return;
|
|
902
908
|
}
|
|
903
909
|
|
|
910
|
+
// Urgency summary line
|
|
911
|
+
const criticalCount = (result.results || []).filter(r => !r.passed && r.impact === 'critical').length;
|
|
912
|
+
const highCount = (result.results || []).filter(r => !r.passed && r.impact === 'high').length;
|
|
913
|
+
const mediumCount = result.failed - criticalCount - highCount;
|
|
914
|
+
const urgencyParts = [];
|
|
915
|
+
if (criticalCount > 0) urgencyParts.push(colorize(`🔴 ${criticalCount} critical`, 'red'));
|
|
916
|
+
if (highCount > 0) urgencyParts.push(colorize(`🟡 ${highCount} high`, 'yellow'));
|
|
917
|
+
if (mediumCount > 0) urgencyParts.push(colorize(`🔵 ${mediumCount} recommended`, 'blue'));
|
|
918
|
+
if (urgencyParts.length > 0) {
|
|
919
|
+
console.log(` ${urgencyParts.join(' ')}`);
|
|
920
|
+
console.log('');
|
|
921
|
+
}
|
|
922
|
+
|
|
904
923
|
console.log(colorize(' Top 3 things to fix right now:', 'magenta'));
|
|
905
924
|
console.log('');
|
|
906
925
|
result.liteSummary.topNextActions.forEach((item, index) => {
|
|
907
|
-
|
|
908
|
-
console.log(
|
|
909
|
-
console.log(colorize(`
|
|
926
|
+
const tier = item.impact === 'critical' ? '🔴' : item.impact === 'high' ? '🟡' : '🔵';
|
|
927
|
+
console.log(` ${index + 1}. ${tier} ${colorize(item.name, 'bold')}`);
|
|
928
|
+
console.log(colorize(` ${item.fix}`, 'dim'));
|
|
910
929
|
});
|
|
911
930
|
console.log('');
|
|
912
931
|
console.log(` Ready? Run: ${colorize(result.suggestedNextCommand, 'bold')}`);
|
|
913
932
|
if (result.platform === 'codex') {
|
|
914
933
|
console.log(colorize(' Note: Codex now supports no-write advisory flows via augment and suggest-only before setup/apply.', 'dim'));
|
|
915
934
|
}
|
|
935
|
+
console.log(colorize(` See all ${result.failed} failed checks: ${colorize('nerviq audit --full', 'bold')}`, 'dim'));
|
|
916
936
|
console.log('');
|
|
917
937
|
}
|
|
918
938
|
|
|
@@ -1195,7 +1215,8 @@ async function audit(options) {
|
|
|
1195
1215
|
if (critical.length > 0) {
|
|
1196
1216
|
console.log(colorize(' 🔴 Critical (fix immediately)', 'red'));
|
|
1197
1217
|
for (const r of critical) {
|
|
1198
|
-
|
|
1218
|
+
const conf = r.confidence ? ` [${confidenceLabel(r.confidence)}]` : '';
|
|
1219
|
+
console.log(` ${colorize(r.name, 'bold')}${colorize(conf, 'dim')}`);
|
|
1199
1220
|
if (r.file) {
|
|
1200
1221
|
console.log(colorize(` at ${formatLocation(r.file, r.line)}`, 'dim'));
|
|
1201
1222
|
}
|
|
@@ -1207,7 +1228,8 @@ async function audit(options) {
|
|
|
1207
1228
|
if (high.length > 0) {
|
|
1208
1229
|
console.log(colorize(' 🟡 High Impact', 'yellow'));
|
|
1209
1230
|
for (const r of high) {
|
|
1210
|
-
|
|
1231
|
+
const conf = r.confidence ? ` [${confidenceLabel(r.confidence)}]` : '';
|
|
1232
|
+
console.log(` ${colorize(r.name, 'bold')}${colorize(conf, 'dim')}`);
|
|
1211
1233
|
if (r.file) {
|
|
1212
1234
|
console.log(colorize(` at ${formatLocation(r.file, r.line)}`, 'dim'));
|
|
1213
1235
|
}
|
|
@@ -1219,7 +1241,8 @@ async function audit(options) {
|
|
|
1219
1241
|
if (medium.length > 0 && options.verbose) {
|
|
1220
1242
|
console.log(colorize(' 🔵 Recommended', 'blue'));
|
|
1221
1243
|
for (const r of medium) {
|
|
1222
|
-
|
|
1244
|
+
const conf = r.confidence ? ` [${confidenceLabel(r.confidence)}]` : '';
|
|
1245
|
+
console.log(` ${colorize(r.name, 'bold')}${colorize(conf, 'dim')}`);
|
|
1223
1246
|
if (r.file) {
|
|
1224
1247
|
console.log(colorize(` at ${formatLocation(r.file, r.line)}`, 'dim'));
|
|
1225
1248
|
}
|