@nerviq/cli 1.8.9 → 1.10.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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@nerviq/cli)](https://www.npmjs.com/package/@nerviq/cli)
6
6
  [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE)
7
- [![Checks: 2431](https://img.shields.io/badge/checks-2431-brightgreen)](https://github.com/nerviq/nerviq)
7
+ [![Checks: 2438](https://img.shields.io/badge/checks-2438-brightgreen)](https://github.com/nerviq/nerviq)
8
8
 
9
9
  ---
10
10
 
@@ -14,7 +14,7 @@ Nerviq audits, sets up, and governs AI coding agent configurations for **8 platf
14
14
 
15
15
  | Platform | Checks | Status |
16
16
  |----------|--------|--------|
17
- | Claude Code | 393 | Full |
17
+ | Claude Code | 400 | Full |
18
18
  | Codex (OpenAI) | 272 | Full |
19
19
  | Gemini CLI (Google) | 300 | Full |
20
20
  | GitHub Copilot | 299 | Full |
@@ -64,18 +64,26 @@ Nerviq scores your AI coding agent setup from 0 to 100, finds what's missing, an
64
64
  Next: nerviq setup
65
65
  ```
66
66
 
67
- ## Quick Start
68
-
69
- ```bash
70
- npx @nerviq/cli audit # Quick scan: score + top 3 actions
71
- npx @nerviq/cli audit --full # Full audit with all checks + badge
72
- npx @nerviq/cli setup # Generate starter-safe baseline
73
- npx @nerviq/cli augment # Improvement plan, no writes
74
- npx @nerviq/cli governance # Permission profiles + policy packs
75
- npx @nerviq/cli benchmark # Before/after in isolated copy
76
- ```
77
-
78
- No install required. Zero dependencies.
67
+ ## Quick Start
68
+
69
+ ```bash
70
+ npx @nerviq/cli --beginner # Show only the 5 starter commands
71
+ npx @nerviq/cli audit # Quick scan: score + top 3 actions
72
+ npx @nerviq/cli audit --full # Full audit with all checks + badge
73
+ npx @nerviq/cli audit --workspace packages/* # Monorepo: root governance + workspace average/package scores
74
+ npx @nerviq/cli setup # Generate starter-safe baseline
75
+ npx @nerviq/cli augment # Improvement plan, no writes
76
+ npx @nerviq/cli governance # Permission profiles + policy packs
77
+ npx @nerviq/cli benchmark # Baseline vs projected score in isolated copy
78
+ ```
79
+
80
+ No install required. Zero dependencies.
81
+
82
+ If you want the shortest possible command list inside the terminal, start with:
83
+
84
+ ```bash
85
+ npx @nerviq/cli --beginner
86
+ ```
79
87
 
80
88
  ## Get Started by Role
81
89
 
@@ -85,7 +93,7 @@ No install required. Zero dependencies.
85
93
  | **Team lead / DevEx** | `nerviq governance` → `nerviq audit --json` | CI threshold + `nerviq watch` |
86
94
  | **Enterprise / Platform** | `nerviq harmony-audit` → `nerviq harmony-drift` | Policy packs + `nerviq certify` |
87
95
 
88
- ## 2,431 Checks Across 96 Categories (8 Platforms × ~300 Governance Rules)
96
+ ## 2,438 Checks Across 96 Categories (8 Platforms × ~300 Governance Rules)
89
97
 
90
98
  | Category Group | Checks | Examples |
91
99
  |----------------|--------|---------|
@@ -236,14 +244,14 @@ Levels:
236
244
  | `nerviq plan` | Export proposal bundles with previews |
237
245
  | `nerviq apply` | Apply proposals with rollback |
238
246
  | `nerviq governance` | Permission profiles, hooks, policy packs |
239
- | `nerviq benchmark` | Before/after in isolated temp copy |
247
+ | `nerviq benchmark` | Baseline vs projected score in isolated temp copy |
240
248
  | `nerviq check-health` | Detect regressions between audit snapshots |
241
249
  | `nerviq deep-review` | AI-powered config review (opt-in) |
242
250
  | `nerviq interactive` | Step-by-step guided wizard |
243
251
  | `nerviq watch` | Live monitoring with score delta |
244
- | `nerviq history` | Score history from snapshots |
245
- | `nerviq compare` | Compare latest vs previous |
246
- | `nerviq trend` | Export trend report |
252
+ | `nerviq history` | Audit snapshot history from saved snapshots |
253
+ | `nerviq compare` | Compare latest vs previous audit snapshot |
254
+ | `nerviq trend` | Export audit snapshot trend report |
247
255
  | `nerviq feedback` | Record recommendation outcomes |
248
256
  | `nerviq anti-patterns` | Detect anti-patterns in current project |
249
257
  | `nerviq freshness` | Show verification freshness for all checks |
@@ -281,7 +289,7 @@ Levels:
281
289
  | `--only A,B` | Limit apply to selected proposal IDs |
282
290
  | `--format sarif` | SARIF output for code scanning |
283
291
  | `--platform NAME` | Target platform (claude, codex, gemini, copilot, cursor, windsurf, aider, opencode) |
284
- | `--workspace GLOB` | Audit workspaces separately (e.g. packages/*) |
292
+ | `--workspace GLOB` | Audit workspaces separately as package-level live audits (e.g. packages/*) |
285
293
  | `--external PATH` | Benchmark an external repo |
286
294
 
287
295
  ## Backed by Research
@@ -290,7 +298,7 @@ Nerviq is built on the NERVIQ knowledge engine — the largest verified catalog
290
298
 
291
299
  - **448+ research documents** covering all 8 platforms
292
300
  - **332+ experiments** with tested, rated results
293
- - **2,431 checks** across 8 platforms (~300 unique governance rules × 8 platform adaptations), each with `sourceUrl` and `confidence` level (0.0-1.0)
301
+ - **2,438 checks** across 8 platforms (~300 unique governance rules × 8 platform adaptations), each with `sourceUrl` and `confidence` level (0.0-1.0)
294
302
  - Every check is traceable to primary documentation or verified experiment
295
303
  - 90-day freshness cycle: stale findings are re-verified or pruned
296
304
 
@@ -333,9 +341,9 @@ If Nerviq helped you, consider giving it a ⭐ on [GitHub](https://github.com/ne
333
341
 
334
342
  **Not designed for:** Deeply customized setups with 20+ skills, agent teams, and bespoke MCP integrations. If you've already built advanced agent workflows, you may not need this.
335
343
 
336
- **Strongest at:** Agent configuration, workflow governance, repo policy hygiene, cross-platform alignment, and setup standardization.
337
-
338
- **Not a replacement for:** Deep architectural review of business logic, runtime performance profiling, or security penetration testing. Nerviq focuses on how your AI coding agents are configured and governed — not on what your application code does.
344
+ **Strongest at:** AI agent governance, configuration intelligence, workflow policy hygiene, cross-platform alignment, and setup standardization.
345
+
346
+ **Not a replacement for:** Deep architectural review of business logic, runtime performance profiling, full SAST coverage, secret scanning, or security penetration testing. Nerviq focuses on how your AI coding agents are configured and governed — not on what your application code does.
339
347
 
340
348
  **Confidence levels:** Every check includes a `confidence` score (0.0–1.0) and a `sourceUrl` linking to primary documentation. Checks marked `heuristic` are pattern-based and may produce false positives on non-standard project structures.
341
349
 
package/bin/cli.js CHANGED
@@ -14,6 +14,7 @@ const { auditWorkspaces } = require('../src/workspace');
14
14
  const { scanOrg } = require('../src/org');
15
15
  const { detectAntiPatterns, printAntiPatterns, printAntiPatternCatalog } = require('../src/anti-patterns');
16
16
  const { VERIFICATION_DATES, getVerificationDate, getVerificationStats } = require('../src/verification-metadata');
17
+ const { init: initI18n, t } = require('../src/i18n');
17
18
  const { version } = require('../package.json');
18
19
 
19
20
  const args = process.argv.slice(2);
@@ -60,9 +61,9 @@ function suggestCommand(input) {
60
61
  return bestDistance <= 3 ? best : null;
61
62
  }
62
63
 
63
- function parseArgs(rawArgs) {
64
- const flags = [];
65
- let command = 'audit';
64
+ function parseArgs(rawArgs) {
65
+ const flags = [];
66
+ let command = 'audit';
66
67
  let threshold = null;
67
68
  let out = null;
68
69
  let planFile = null;
@@ -88,14 +89,16 @@ function parseArgs(rawArgs) {
88
89
  let migrateFrom = null;
89
90
  let migrateTo = null;
90
91
  let checkVersion = null;
91
- let external = null;
92
- let repos = [];
93
- let teamProfile = null;
92
+ let external = null;
93
+ let repos = [];
94
+ let teamProfile = null;
95
+ let lang = null;
96
+ let commandExplicit = false;
94
97
 
95
98
  for (let i = 0; i < rawArgs.length; i++) {
96
99
  const arg = rawArgs[i];
97
100
 
98
- if (arg === '--threshold' || arg === '--out' || arg === '--plan' || arg === '--only' || arg === '--profile' || arg === '--mcp-pack' || arg === '--require' || arg === '--key' || arg === '--status' || arg === '--effect' || arg === '--notes' || arg === '--source' || arg === '--score-delta' || arg === '--platform' || arg === '--format' || arg === '--from' || arg === '--to' || arg === '--port' || arg === '--workspace' || arg === '--check-version' || arg === '--webhook' || arg === '--external' || arg === '--team-profile') {
101
+ if (arg === '--threshold' || arg === '--out' || arg === '--plan' || arg === '--only' || arg === '--profile' || arg === '--mcp-pack' || arg === '--require' || arg === '--key' || arg === '--status' || arg === '--effect' || arg === '--notes' || arg === '--source' || arg === '--score-delta' || arg === '--platform' || arg === '--format' || arg === '--from' || arg === '--to' || arg === '--port' || arg === '--workspace' || arg === '--check-version' || arg === '--webhook' || arg === '--external' || arg === '--team-profile' || arg === '--lang') {
99
102
  const value = rawArgs[i + 1];
100
103
  if (!value || value.startsWith('--')) {
101
104
  throw new Error(`${arg} requires a value`);
@@ -123,10 +126,16 @@ function parseArgs(rawArgs) {
123
126
  if (arg === '--webhook') webhookUrl = value.trim();
124
127
  if (arg === '--external') external = value.trim();
125
128
  if (arg === '--team-profile') teamProfile = value.trim();
129
+ if (arg === '--lang') lang = value.trim().toLowerCase();
126
130
  i++;
127
131
  continue;
128
132
  }
129
133
 
134
+ if (arg.startsWith('--lang=')) {
135
+ lang = arg.split('=').slice(1).join('=').trim().toLowerCase();
136
+ continue;
137
+ }
138
+
130
139
  if (arg.startsWith('--team-profile=')) {
131
140
  teamProfile = arg.split('=').slice(1).join('=').trim();
132
141
  continue;
@@ -248,37 +257,47 @@ function parseArgs(rawArgs) {
248
257
  continue;
249
258
  }
250
259
 
251
- if (!commandSet) {
252
- command = arg;
253
- commandSet = true;
254
- } else {
255
- extraArgs.push(arg);
256
- }
257
- }
260
+ if (!commandSet) {
261
+ command = arg;
262
+ commandSet = true;
263
+ commandExplicit = true;
264
+ } else {
265
+ extraArgs.push(arg);
266
+ }
267
+ }
258
268
 
259
269
  const normalizedCommand = COMMAND_ALIASES[command] || command;
260
270
 
261
- return { flags, command, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks, requireChecks, feedbackKey, feedbackStatus, feedbackEffect, feedbackNotes, feedbackSource, feedbackScoreDelta, platform, format, port, workspace, extraArgs, convertFrom, convertTo, migrateFrom, migrateTo, checkVersion, webhookUrl, external, repos, teamProfile };
262
- }
263
-
264
- function printWorkspaceSummary(summary, options) {
265
- if (options.json) {
266
- console.log(JSON.stringify(summary, null, 2));
267
- return;
268
- }
269
-
270
- console.log('');
271
- console.log('\x1b[1m nerviq workspace audit\x1b[0m');
272
- console.log('\x1b[2m ═══════════════════════════════════════\x1b[0m');
273
- console.log(` Root: ${summary.rootDir}`);
274
- console.log(` Platform: ${summary.platform}`);
275
- console.log(` Workspaces: ${summary.workspaceCount}`);
276
- console.log(` Average score: \x1b[1m${summary.averageScore}/100\x1b[0m`);
277
- console.log('');
278
- console.log('\x1b[1m Workspace Score Pass Total Top action\x1b[0m');
279
- console.log(' ' + '─'.repeat(72));
280
- for (const item of summary.workspaces) {
281
- const score = item.score === null ? 'ERR' : String(item.score);
271
+ return { flags, command, commandExplicit, normalizedCommand, threshold, out, planFile, only, profile, mcpPacks, requireChecks, feedbackKey, feedbackStatus, feedbackEffect, feedbackNotes, feedbackSource, feedbackScoreDelta, platform, format, port, workspace, extraArgs, convertFrom, convertTo, migrateFrom, migrateTo, checkVersion, webhookUrl, external, repos, teamProfile, lang };
272
+ }
273
+
274
+ function printWorkspaceSummary(summary, options) {
275
+ if (options.json) {
276
+ console.log(JSON.stringify(summary, null, 2));
277
+ return;
278
+ }
279
+
280
+ const rootScore = summary.rootGovernance?.score === null ? 'ERR' : `${summary.rootGovernance?.score ?? 0}/100`;
281
+ const workspaceAverage = summary.workspaceAggregate?.score ?? summary.averageScore;
282
+
283
+ console.log('');
284
+ console.log('\x1b[1m nerviq workspace audit\x1b[0m');
285
+ console.log('\x1b[2m ═══════════════════════════════════════\x1b[0m');
286
+ console.log(` Root: ${summary.rootDir}`);
287
+ console.log(` Platform: ${summary.platform}`);
288
+ console.log(` Workspaces: ${summary.workspaceCount}`);
289
+ if (summary.patterns?.length > 0) {
290
+ console.log(` Selection: ${summary.patterns.join(', ')}`);
291
+ }
292
+ console.log(` Root governance audit: \x1b[1m${rootScore}\x1b[0m`);
293
+ console.log(` Workspace audit average: \x1b[1m${workspaceAverage}/100\x1b[0m`);
294
+ console.log(' Score semantics: root governance shows shared repo policy health; workspace average shows package-level coverage across the selected workspaces.');
295
+ console.log(' Aggregate vs package: per-workspace scores can legitimately trail the root repo score in a monorepo.');
296
+ console.log('');
297
+ console.log('\x1b[1m Workspace Audit Pass Total Top action\x1b[0m');
298
+ console.log(' ' + '─'.repeat(72));
299
+ for (const item of summary.workspaces) {
300
+ const score = item.score === null ? 'ERR' : String(item.score);
282
301
  const topAction = item.error || item.topAction || '-';
283
302
  console.log(` ${item.workspace.padEnd(26)} ${score.padStart(5)} ${String(item.passed).padStart(5)} ${String(item.total).padStart(6)} ${topAction}`);
284
303
  }
@@ -358,17 +377,18 @@ function printOrgSummary(summary, options) {
358
377
  console.log('');
359
378
  }
360
379
 
361
- const HELP = `
362
- nerviq v${version}
363
- The intelligent nervous system for AI coding agents.
364
- Audit, align, and amplify every platform on every project.
365
-
366
- DISCOVER
367
- nerviq audit Quick scan: score + top 3 gaps (default)
368
- nerviq audit --full Full audit with all checks, weakest areas, badge
369
- nerviq audit --platform X Audit specific platform (claude|codex|cursor|copilot|gemini|windsurf|aider|opencode)
370
- nerviq audit --json Machine-readable JSON output (for CI)
371
- nerviq audit --workspace packages/* Audit each workspace in a monorepo
380
+ const HELP = `
381
+ nerviq v${version}
382
+ The intelligent nervous system for AI coding agents.
383
+ Audit, align, and amplify every platform on every project.
384
+ New here? Run: nerviq --beginner
385
+
386
+ DISCOVER
387
+ nerviq audit Quick scan: score + top 3 gaps (default)
388
+ nerviq audit --full Full audit with all checks, weakest areas, badge
389
+ nerviq audit --platform X Audit specific platform (claude|codex|cursor|copilot|gemini|windsurf|aider|opencode)
390
+ nerviq audit --json Machine-readable JSON output (for CI)
391
+ nerviq audit --workspace packages/* Audit monorepo workspaces with root-vs-package score semantics
372
392
  nerviq scan dir1 dir2 Compare multiple repos side-by-side
373
393
  nerviq org scan dir1 dir2 Aggregate multiple repos into one score table
374
394
  nerviq catalog Full check catalog (all 8 platforms)
@@ -405,30 +425,30 @@ const HELP = `
405
425
  GOVERN
406
426
  nerviq governance Permission profiles + hooks + policy packs
407
427
  nerviq governance --json Machine-readable governance summary
408
- nerviq benchmark Before/after score in isolated temp copy
428
+ nerviq benchmark Baseline vs projected score in isolated temp copy
409
429
  nerviq benchmark --external /path Benchmark an external repo
410
430
  nerviq freshness Show verification freshness for all checks
411
431
  nerviq certify Generate certification badge for your project
412
432
 
413
433
  CROSS-PLATFORM
414
- nerviq harmony-audit Drift detection across all active platforms
415
- nerviq harmony-sync Preview cross-platform sync (dry run)
416
- nerviq harmony-sync --fix Apply cross-platform sync (write files)
417
- nerviq harmony-sync --json JSON output for CI/automation
418
- nerviq harmony-add <platform> Add a new platform to the project
419
- nerviq synergy-report Multi-agent amplification opportunities
434
+ nerviq harmony-audit Drift detection across all active platforms (GA)
435
+ nerviq harmony-sync Preview cross-platform sync (dry run, GA)
436
+ nerviq harmony-sync --fix Apply cross-platform sync (write files, GA)
437
+ nerviq harmony-sync --json JSON output for CI/automation
438
+ nerviq harmony-add <platform> Add a new platform to the project
439
+ nerviq synergy-report [EXPERIMENTAL] Static-rule multi-agent amplification report
420
440
  nerviq convert --from X --to Y Convert configs between platforms
421
441
  nerviq migrate --platform X Platform version migration helper
422
442
  nerviq migrate --platform cursor --from v2 --to v3
423
443
 
424
444
  MONITOR
425
- nerviq dashboard Generate static HTML dashboard report
445
+ nerviq dashboard Generate static dashboard from latest audit snapshot (or live audit if none)
426
446
  nerviq dashboard --out F Save dashboard to custom file
427
447
  nerviq dashboard --open Open dashboard in browser after generating
428
448
  nerviq watch Live config monitoring (re-audits on file change)
429
- nerviq history Score history from saved snapshots
430
- nerviq compare Latest vs previous snapshot diff
431
- nerviq trend Score trend over time
449
+ nerviq history Audit snapshot history from saved snapshots
450
+ nerviq compare Latest vs previous audit snapshot diff
451
+ nerviq trend Audit snapshot trend over time
432
452
  nerviq trend --out report.md Export trend report as markdown
433
453
  nerviq feedback Record recommendation outcomes
434
454
 
@@ -461,26 +481,28 @@ const HELP = `
461
481
  --webhook URL Send audit results to a webhook (Slack/Discord/generic JSON)
462
482
  --external PATH Benchmark an external repo instead of cwd
463
483
  --port N Port for \`serve\` (default: 3000)
464
- --workspace GLOBS Audit workspaces separately (e.g. packages/* or apps/web,apps/api)
484
+ --workspace GLOBS Audit workspaces separately and label root governance vs package scores
465
485
  --snapshot Save snapshot artifact under .claude/nerviq/snapshots/
466
486
  --full Show full audit output (all checks, weakest areas, badge)
467
487
  --lite Short top-3 scan (default behavior since v1.5.2)
468
488
  --dry-run Preview changes without writing files
469
489
  --config-only Only write config files (.claude/, rules, hooks) — never source code
470
490
  --verbose Full audit + medium-priority recommendations
471
- --show-deprecated Show deprecated checks (excluded from scoring)
472
- --json Output as JSON
473
- --auto Apply all generated files without prompting
474
- --key NAME Feedback: recommendation key (e.g. permissionDeny)
491
+ --show-deprecated Show deprecated checks (excluded from scoring)
492
+ --json Output as JSON
493
+ --auto Apply all generated files without prompting
494
+ --beginner Show only the 5 starter commands for first-time users
495
+ --key NAME Feedback: recommendation key (e.g. permissionDeny)
475
496
  --status VALUE Feedback: accepted | rejected | deferred
476
497
  --effect VALUE Feedback: positive | neutral | negative
477
498
  --score-delta N Feedback: observed score delta
478
499
  --help Show this help
479
500
  --version Show version
480
501
 
481
- EXAMPLES
482
- npx nerviq
483
- npx nerviq --lite
502
+ EXAMPLES
503
+ npx nerviq --beginner
504
+ npx nerviq
505
+ npx nerviq --lite
484
506
  npx nerviq --platform cursor
485
507
  npx nerviq audit --workspace packages/*
486
508
  npx nerviq --platform codex augment
@@ -497,9 +519,34 @@ const HELP = `
497
519
  npx nerviq feedback --key permissionDeny --status accepted --effect positive
498
520
 
499
521
  EXIT CODES
500
- 0 Success
501
- 1 Error, unknown command, or score below --threshold
502
- `;
522
+ 0 Success
523
+ 1 Error, unknown command, or score below --threshold
524
+ `;
525
+
526
+ const BEGINNER_HELP = `
527
+ nerviq v${version}
528
+ Start here.
529
+
530
+ If this is your first time, learn just these 5 commands:
531
+
532
+ STARTER COMMANDS
533
+ nerviq audit Score the repo and show the top gaps
534
+ nerviq setup Generate a starter-safe baseline
535
+ nerviq fix Fix what can be fixed or show manual fix guidance
536
+ nerviq augment Show an improvement plan without writing
537
+ nerviq doctor Check install health, freshness, and platform detection
538
+
539
+ SIMPLE PATH
540
+ 1. nerviq audit
541
+ 2. nerviq setup --auto
542
+ 3. nerviq fix --all-critical --auto
543
+ 4. nerviq augment
544
+ 5. nerviq doctor
545
+
546
+ WHEN YOU ARE READY
547
+ nerviq --help Show the full command set
548
+ Docs: https://nerviq.net/docs/getting-started
549
+ `;
503
550
 
504
551
  async function main() {
505
552
  let parsed;
@@ -510,17 +557,27 @@ async function main() {
510
557
  process.exit(1);
511
558
  }
512
559
 
513
- const { flags, command, normalizedCommand } = parsed;
560
+ const { flags, command, commandExplicit, normalizedCommand } = parsed;
514
561
 
515
- if (flags.includes('--help') || command === 'help') {
516
- console.log(HELP);
517
- process.exit(0);
562
+ // Initialize i18n with --lang flag or NERVIQ_LANG env var
563
+ if (parsed.lang) {
564
+ initI18n(parsed.lang);
518
565
  }
519
566
 
520
- if (flags.includes('--version') || command === 'version') {
521
- console.log(version);
522
- process.exit(0);
523
- }
567
+ if (flags.includes('--version') || command === 'version') {
568
+ console.log(version);
569
+ process.exit(0);
570
+ }
571
+
572
+ if (flags.includes('--beginner') && (!commandExplicit || flags.includes('--help') || command === 'help')) {
573
+ console.log(BEGINNER_HELP);
574
+ process.exit(0);
575
+ }
576
+
577
+ if (flags.includes('--help') || command === 'help') {
578
+ console.log(HELP);
579
+ process.exit(0);
580
+ }
524
581
 
525
582
  const options = {
526
583
  verbose: flags.includes('--verbose'),
@@ -547,6 +604,7 @@ async function main() {
547
604
  port: parsed.port !== null ? Number(parsed.port) : null,
548
605
  workspace: parsed.workspace || null,
549
606
  webhookUrl: parsed.webhookUrl || null,
607
+ lang: parsed.lang || null,
550
608
  external: parsed.external || null,
551
609
  dir: process.cwd()
552
610
  };
@@ -732,9 +790,9 @@ async function main() {
732
790
  process.exit(1);
733
791
  }
734
792
  process.exit(0);
735
- } else if (normalizedCommand === 'history') {
736
- const { formatHistory, readSnapshotIndex } = require('../src/activity');
737
- // Handle --prune N
793
+ } else if (normalizedCommand === 'history') {
794
+ const { formatHistory, readSnapshotIndex } = require('../src/activity');
795
+ // Handle --prune N
738
796
  const pruneIdx = flags.indexOf('--prune');
739
797
  if (pruneIdx >= 0) {
740
798
  const keepCount = parseInt(flags[pruneIdx + 1] || parsed.extraArgs[0], 10) || 10;
@@ -742,7 +800,7 @@ async function main() {
742
800
  const pathMod = require('path');
743
801
  const entries = readSnapshotIndex(options.dir);
744
802
  if (entries.length <= keepCount) {
745
- console.log(`\n Nothing to prune (${entries.length} snapshots, keeping ${keepCount}).\n`);
803
+ console.log(`\n Nothing to prune (${entries.length} audit snapshots, keeping ${keepCount}).\n`);
746
804
  } else {
747
805
  const toRemove = entries.slice(0, entries.length - keepCount);
748
806
  let removed = 0;
@@ -753,42 +811,53 @@ async function main() {
753
811
  const kept = entries.slice(entries.length - keepCount);
754
812
  const indexPath = pathMod.join(options.dir, '.nerviq', 'snapshots', 'index.json');
755
813
  try { fsMod.writeFileSync(indexPath, JSON.stringify(kept, null, 2), 'utf8'); } catch {}
756
- console.log(`\n Pruned ${removed} snapshots, kept ${kept.length}.\n`);
814
+ console.log(`\n Pruned ${removed} audit snapshots, kept ${kept.length}.\n`);
757
815
  }
758
816
  process.exit(0);
759
817
  }
760
818
  console.log('');
761
- console.log(formatHistory(options.dir));
762
- console.log('');
763
- process.exit(0);
764
- } else if (normalizedCommand === 'compare') {
765
- const { compareLatest } = require('../src/activity');
766
- const result = compareLatest(options.dir);
767
- if (!result) {
768
- console.log('\n Need at least 2 snapshots to compare. Run `npx nerviq --snapshot` twice.\n');
769
- process.exit(0);
770
- }
819
+ console.log(formatHistory(options.dir));
820
+ console.log('');
821
+ process.exit(0);
822
+ } else if (normalizedCommand === 'compare') {
823
+ const { compareLatest, formatSnapshotBootstrap } = require('../src/activity');
824
+ const result = compareLatest(options.dir);
825
+ if (!result) {
826
+ console.log('');
827
+ console.log(formatSnapshotBootstrap(options.dir, 'compare'));
828
+ console.log('');
829
+ process.exit(0);
830
+ }
771
831
  if (options.json) {
772
832
  console.log(JSON.stringify(result, null, 2));
773
833
  } else {
774
834
  const sign = result.delta.score >= 0 ? '+' : '';
775
835
  console.log('');
776
- console.log(` Previous: ${result.previous.score}/100 (${result.previous.date?.split('T')[0]})`);
777
- console.log(` Current: ${result.current.score}/100 (${result.current.date?.split('T')[0]})`);
778
- console.log(` Delta: ${sign}${result.delta.score} points`);
779
- console.log(` Trend: ${result.trend}`);
836
+ console.log(` Previous snapshot: ${result.previous.score}/100 (${result.previous.date?.split('T')[0]})`);
837
+ console.log(` Current snapshot: ${result.current.score}/100 (${result.current.date?.split('T')[0]})`);
838
+ console.log(` Snapshot delta: ${sign}${result.delta.score} points`);
839
+ console.log(` Trend: ${result.trend}`);
780
840
  if (result.improvements.length > 0) console.log(` Fixed: ${result.improvements.join(', ')}`);
781
841
  if (result.regressions.length > 0) console.log(` New gaps: ${result.regressions.join(', ')}`);
782
842
  console.log('');
783
- }
784
- process.exit(0);
785
- } else if (normalizedCommand === 'trend') {
786
- const { exportTrendReport } = require('../src/activity');
787
- const report = exportTrendReport(options.dir);
788
- if (!report) {
789
- console.log('\n No snapshots found. Run `npx nerviq --snapshot` to start tracking.\n');
790
- process.exit(0);
791
- }
843
+ }
844
+ process.exit(0);
845
+ } else if (normalizedCommand === 'trend') {
846
+ const { exportTrendReport, getHistory, formatSnapshotBootstrap } = require('../src/activity');
847
+ const auditHistory = getHistory(options.dir, 2);
848
+ if (auditHistory.length < 2) {
849
+ console.log('');
850
+ console.log(formatSnapshotBootstrap(options.dir, 'trend'));
851
+ console.log('');
852
+ process.exit(0);
853
+ }
854
+ const report = exportTrendReport(options.dir);
855
+ if (!report) {
856
+ console.log('');
857
+ console.log(formatSnapshotBootstrap(options.dir, 'trend'));
858
+ console.log('');
859
+ process.exit(0);
860
+ }
792
861
  if (options.out) {
793
862
  require('fs').writeFileSync(options.out, report, 'utf8');
794
863
  console.log(`\n Trend report exported to ${options.out}\n`);