@rigour-labs/cli 5.2.2 → 5.2.4

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.
@@ -2,7 +2,7 @@ import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import chalk from 'chalk';
4
4
  import yaml from 'yaml';
5
- import { GateRunner, ConfigSchema, recordScore, getScoreTrend, resolveDeepOptions, getProvenanceTrends, getQualityTrend, IncrementalCache } from '@rigour-labs/core';
5
+ import { GateRunner, ConfigSchema, recordScore, getScoreTrend, resolveDeepOptions, getProvenanceTrends, getQualityTrend, IncrementalCache, renderFullReport } from '@rigour-labs/core';
6
6
  import inquirer from 'inquirer';
7
7
  import { randomUUID } from 'crypto';
8
8
  // Exit codes per spec
@@ -417,64 +417,20 @@ function renderDeepOutput(report, config, options, resolvedDeepMode) {
417
417
  console.log(chalk.yellow(` See ${config.output.report_path} for full details.`));
418
418
  }
419
419
  /**
420
- * Render standard AST-only output (existing behavior).
420
+ * Render standard AST-only output uses shared terminal renderer.
421
421
  */
422
- function renderStandardOutput(report, config) {
423
- if (report.status === 'PASS') {
424
- console.log(chalk.green.bold('✔ PASS - All quality gates satisfied.'));
425
- }
426
- else {
427
- console.log(chalk.red.bold('✘ FAIL - Quality gate violations found.\n'));
428
- // Score summary line
429
- const stats = report.stats;
430
- const scoreParts = [];
431
- if (stats.score !== undefined)
432
- scoreParts.push(`Score: ${stats.score}/100`);
433
- if (stats.ai_health_score !== undefined)
434
- scoreParts.push(`AI Health: ${stats.ai_health_score}/100`);
435
- if (stats.structural_score !== undefined)
436
- scoreParts.push(`Structural: ${stats.structural_score}/100`);
437
- if (scoreParts.length > 0) {
438
- console.log(chalk.bold(scoreParts.join(' | ')) + '\n');
439
- }
440
- // Severity breakdown
441
- if (stats.severity_breakdown) {
442
- const parts = Object.entries(stats.severity_breakdown)
443
- .filter(([, count]) => count > 0)
444
- .map(([sev, count]) => {
445
- const color = sev === 'critical' ? chalk.red.bold : sev === 'high' ? chalk.red : sev === 'medium' ? chalk.yellow : chalk.dim;
446
- return color(`${sev}: ${count}`);
447
- });
448
- if (parts.length > 0) {
449
- console.log('Severity: ' + parts.join(', ') + '\n');
450
- }
451
- }
452
- // ── Temporal Drift Trends (standard mode) ──
453
- try {
454
- const trend = getQualityTrend(process.cwd());
455
- if (trend !== 'stable') {
456
- const trendIcon = trend === 'improving' ? chalk.green('↑') : chalk.red('↓');
457
- const trendColor = trend === 'improving' ? chalk.green : chalk.red;
458
- console.log(`Trend: ${trendIcon} ${trendColor(trend)} (Z-score)\n`);
459
- }
460
- }
461
- catch { /* ignore */ }
462
- for (const failure of report.failures) {
463
- const sev = severityIcon(failure.severity);
464
- const prov = failure.provenance ? chalk.dim(`[${failure.provenance}]`) : '';
465
- console.log(`${sev} ${prov} ${chalk.red(`[${failure.id}]`)} ${failure.title}`);
466
- console.log(chalk.dim(` Details: ${failure.details}`));
467
- if (failure.files && failure.files.length > 0) {
468
- console.log(chalk.dim(' Files:'));
469
- failure.files.forEach((f) => console.log(chalk.dim(` - ${f}`)));
470
- }
471
- if (failure.hint) {
472
- console.log(chalk.cyan(` Hint: ${failure.hint}`));
473
- }
474
- console.log('');
475
- }
476
- console.log(chalk.yellow(`See ${config.output.report_path} for full details.`));
422
+ function renderStandardOutput(report, _config) {
423
+ const trend = getScoreTrend(process.cwd());
424
+ const renderOpts = {
425
+ showBrain: true,
426
+ brainPatterns: 0,
427
+ brainTrend: 'stable',
428
+ };
429
+ if (trend && trend.recentScores.length >= 3) {
430
+ renderOpts.recentScores = trend.recentScores;
431
+ renderOpts.brainTrend = trend.direction;
477
432
  }
433
+ console.log(renderFullReport(report, renderOpts));
478
434
  }
479
435
  function severityIcon(s) {
480
436
  switch (s) {
@@ -1,4 +1,4 @@
1
1
  export declare const CODE_QUALITY_RULES = "\n# Code Quality Standards\n\n## PRODUCTION-GRADE CODE ONLY\n- No debug logging in production code\n- No shortcuts or \"temporary\" fixes\n- No over-engineering - simplest solution that works\n- Follow existing code patterns and conventions\n- Handle edge cases properly\n- No TODO/FIXME comments in final code\n\n## MODULAR CODE STRUCTURE\n- Write SMALL, focused functions (< 50 lines ideally)\n- One function = one job, clearly named\n- New features go in SEPARATE FILES, not flooding existing ones\n- Keep files under 500 lines - split if growing larger\n- Extract reusable logic into utility modules\n- Avoid \"god files\" that do everything\n- When adding to existing code, check if a new module is more appropriate\n\n## Technical Standards\n\n### DRY Principle\n- Extract repeated logic into utilities\n- Single Responsibility: One function, one job\n- Defensive coding: Validate inputs at boundaries\n- Lazy initialization for external dependencies (secrets, connections)\n- Graceful degradation over hard failures\n\n### File Organization\n```\n# Good: Separate concerns into focused files\ngovernor/\n main.py # Entry point only\n drift_detector.py # Drift detection logic\n lip_sync_analyzer.py # SyncNet integration\n audio_analyzer.py # Audio analysis\n\n# Bad: One massive file with everything\ngovernor/\n main.py (2000+ lines with all logic mixed)\n```\n\n### API Design\n- Consistent error responses\n- Proper HTTP status codes\n- Authentication at the edge\n- Rate limiting on public endpoints\n\n## PRODUCTION-READY SELF-REVIEW (THE GATEKEEPER)\n\nBefore asking for \"approval,\" internally verify:\n\n- **Zero-Dependency Check**: Does this fix rely on a local environment variable not yet in `talentlyt-kv`?\n- **Side-Effect Audit**: Could this change trigger a 502 Bad Gateway at the `/auth/callback` or `/api/agent` endpoints?\n- **Biometric Integrity**: If touching the `Governor`, have I verified that the `similarity_score` logic remains deterministic?\n- **Cost Impact**: Does this change increase egress costs (e.g., unnecessary cross-region logging)?\n- **Error Handling**: Does the UI have a graceful fallback if the backend service is slow?\n";
2
2
  export declare const DEBUGGING_RULES = "\n# Investigation & Debugging Protocol\n\n## INVESTIGATION PROTOCOL\n\nWhen debugging:\n1. Check DEPLOYED environment (Azure, prod), not localhost unless explicitly asked\n2. Trace the actual request flow end-to-end\n3. Collect evidence at each step\n4. Present findings before proposing fixes\n\n## GAP ANALYSIS\n\nWhen debugging or proposing changes:\n\n1. **Trace the actual request flow** end-to-end:\n - Client \u2192 Cloudflare \u2192 Vercel/Container App \u2192 DB\n\n2. **Identify Hidden Gaps** - Explicitly check if the change affects:\n - **Cross-Region Handshakes**: Will this increase latency for users in Pakistan/India?\n - **Forensic Continuity**: Does this change how Maya captures gaze or audio data?\n - **Auth Persistence**: Will this interfere with WorkOS session tokens or M2M keys?\n\n3. **Evidence-First**: Collect logs from `talentlyt-dashboard` before proposing a fix.\n\n## Request Flow Tracing\n\n```\nClient Browser\n \u2193\nCloudflare (CDN/WAF)\n \u2193\nAzure Container Apps\n \u251C\u2500\u2500 talentlyt-dashboard (Next.js)\n \u2514\u2500\u2500 talentlyt-agent (Python/LiveKit)\n \u2193\nPostgreSQL Database\n \u2193\nAzure Blob Storage (recordings, evidence)\n```\n\n## Evidence Collection\n\nBefore proposing any fix:\n1. Get the actual error from logs (not assumed)\n2. Identify the exact file and line number\n3. Trace the data flow that led to the error\n4. Verify the fix doesn't break other paths\n";
3
3
  export declare const COLLABORATION_RULES = "\n# Role & Collaboration\n\nYou are a Senior Staff Engineer working alongside a Principal Engineer (the user). \nYou do NOT work autonomously - you work collaboratively with approval at each step.\n\n## 1. NO ASSUMPTIONS\n- Never assume root cause without evidence from logs/code\n- Never assume a fix works without verification\n- Always trace the ACTUAL flow, not the expected flow\n- When debugging, read the DEPLOYED code, not local code\n\n## 2. APPROVAL REQUIRED\nBefore making ANY code change, you MUST:\n1. Show the evidence (logs, code trace) proving the issue\n2. Explain the root cause with proof\n3. Propose the fix with rationale\n4. Wait for explicit approval: \"approved\", \"go ahead\", \"do it\"\n\nException: Only proceed without approval if user explicitly says \"just do it\" or \"fix it\"\n\n## 3. NEVER LOSE TRACK\n- Maintain TODO list for multi-step tasks\n- Complete current task before starting new ones\n- If interrupted, summarize current state before switching\n- Reference previous findings, don't repeat investigations\n\n## Communication\n\n### When Reporting Issues\n```\n**Evidence:** [actual log/error message]\n**Location:** [file:line or endpoint]\n**Root Cause:** [proven, not assumed]\n**Privacy Impact:** [Does this affect biometric/PII data?]\n**Fix:** [proposed solution]\n```\n\n### When Asking for Approval\n```\nI found: [evidence]\nRoot cause: [explanation]\nProposed fix: [code change summary]\n\nApprove to proceed?\n```\n\n### When Stuck\n- Say \"I need more information\" not guess\n- Ask specific questions\n- Propose diagnostic steps\n\n## \u26A0\uFE0F RIGOUR.YML IS SACRED\n\nThe `rigour.yml` file represents **team-agreed quality standards**. You are FORBIDDEN from:\n\n1. \u274C Increasing thresholds to pass checks (e.g., raising `complexity: 100`)\n2. \u274C Adding patterns to `ignore:` to skip problematic files\n3. \u274C Removing items from `required_files`\n4. \u274C Disabling gates to avoid failures\n\n**Your job is to FIX THE CODE to meet the standards, NOT weaken the standards to pass the check.**\n\nIf thresholds genuinely need adjustment, escalate to the team lead with justification.\n\n## Forbidden Actions\n\n1. \u274C Making code changes without showing evidence first\n2. \u274C Testing on localhost when asked to check production\n3. \u274C Adding debug logs as a \"fix\"\n4. \u274C Multiple deployment attempts hoping it works\n5. \u274C Over-engineering simple solutions\n6. \u274C Assuming secrets/env vars are available at init time\n7. \u274C Ignoring user corrections\n8. \u274C Losing context between messages\n9. \u274C Modifying rigour.yml to pass quality checks\n";
4
- export declare const AGNOSTIC_AI_INSTRUCTIONS = "\n# \uD83E\uDD16 CRITICAL INSTRUCTION FOR AI\n\nWhen asked to implement a feature or fix an issue:\n\n1. **FIRST**: Read ALL relevant rules files (e.g., `.cursor/rules/*.mdc`, `.clinerules`, `docs/AGENT_INSTRUCTIONS.md`).\n2. **NEVER** claim \"done\" until you can demonstrate the feature WORKS or the fix is verified.\n3. **ALWAYS** run `npx @rigour-labs/cli check` before claiming completion.\n4. **CONNECTivity**: \n - If you create backend code, you MUST wire it to the frontend.\n - If you create a service, you MUST connect it to the UI.\n\n## \u2705 VERIFICATION PROOF REQUIRED\n\nBefore saying \"done\", show ONE of:\n- Screenshot/output proving it works.\n- The exact commands the user can run to verify.\n- The full flow from initiation (e.g., button click) to result.\n\n\"Code exists\" \u2260 \"Feature works\"\n";
4
+ export declare const AGNOSTIC_AI_INSTRUCTIONS = "\n# Rigour Quality Gates\n\nThis project uses **Rigour MCP tools** for automated quality governance.\nThe tools are self-describing \u2014 follow their descriptions to discover the correct workflow.\n\n## Key Rules\n- **Never** modify `rigour.yml` to pass checks \u2014 fix the code instead.\n- **Never** claim \"done\" until you can demonstrate the feature works or the fix is verified.\n- If you create backend code, wire it to the frontend. If you create a service, connect it to the UI.\n\n## Verification\nBefore saying \"done\", show ONE of:\n- Output proving it works.\n- The exact commands the user can run to verify.\n- The full flow from initiation to result.\n";
@@ -184,23 +184,19 @@ If thresholds genuinely need adjustment, escalate to the team lead with justific
184
184
  9. ❌ Modifying rigour.yml to pass quality checks
185
185
  `;
186
186
  export const AGNOSTIC_AI_INSTRUCTIONS = `
187
- # 🤖 CRITICAL INSTRUCTION FOR AI
187
+ # Rigour Quality Gates
188
188
 
189
- When asked to implement a feature or fix an issue:
189
+ This project uses **Rigour MCP tools** for automated quality governance.
190
+ The tools are self-describing — follow their descriptions to discover the correct workflow.
190
191
 
191
- 1. **FIRST**: Read ALL relevant rules files (e.g., \`.cursor/rules/*.mdc\`, \`.clinerules\`, \`docs/AGENT_INSTRUCTIONS.md\`).
192
- 2. **NEVER** claim "done" until you can demonstrate the feature WORKS or the fix is verified.
193
- 3. **ALWAYS** run \`npx @rigour-labs/cli check\` before claiming completion.
194
- 4. **CONNECTivity**:
195
- - If you create backend code, you MUST wire it to the frontend.
196
- - If you create a service, you MUST connect it to the UI.
197
-
198
- ## ✅ VERIFICATION PROOF REQUIRED
192
+ ## Key Rules
193
+ - **Never** modify \`rigour.yml\` to pass checks fix the code instead.
194
+ - **Never** claim "done" until you can demonstrate the feature works or the fix is verified.
195
+ - If you create backend code, wire it to the frontend. If you create a service, connect it to the UI.
199
196
 
197
+ ## Verification
200
198
  Before saying "done", show ONE of:
201
- - Screenshot/output proving it works.
199
+ - Output proving it works.
202
200
  - The exact commands the user can run to verify.
203
- - The full flow from initiation (e.g., button click) to result.
204
-
205
- "Code exists" ≠ "Feature works"
201
+ - The full flow from initiation to result.
206
202
  `;
@@ -186,49 +186,16 @@ export async function initCommand(cwd, options = {}) {
186
186
  const rigourDocsDir = path.join(cwd, 'docs');
187
187
  await fs.ensureDir(rigourDocsDir);
188
188
  const instructionsPath = path.join(rigourDocsDir, 'AGENT_INSTRUCTIONS.md');
189
- const ruleContent = `# 🛡️ Rigour: Mandatory Engineering Governance Protocol
189
+ const ruleContent = `# Rigour: Engineering Governance
190
190
 
191
- **You are an AI Engineering Agent governed by Rigour.** You MUST use the Rigour MCP tools at specific points in your workflow. This is non-negotiable.
191
+ This project uses **Rigour MCP tools** for automated quality governance. The tools are self-describing read their descriptions to discover the correct workflow automatically.
192
192
 
193
- ## 🚦 BEFORE Writing Any Code
193
+ ## Key Rules
194
194
 
195
- 1. **Load Context**: Call the \`rigour_recall\` MCP tool to load project memory and conventions.
196
- 2. **Check Patterns**: Call the \`rigour_check_pattern\` MCP tool with the name and type of what you're about to create (e.g., name: "capitalize", type: "function"). This prevents reinventing existing utilities and catches security issues (CVEs).
197
-
198
- ## ✍️ AFTER Writing Code (Automatic)
199
-
200
- Real-time hooks run automatically after every file edit. If a hook returns a violation, you MUST fix the issue before continuing. Do NOT ignore hook warnings or errors.
201
-
202
- ## ✅ BEFORE Declaring "Done"
203
-
204
- 1. **Run Quality Gates**: Call the \`rigour_check\` MCP tool to verify all quality gates pass.
205
- 2. **If FAIL**: Read the failure details, fix the code, and call \`rigour_check\` again.
206
- 3. **Only declare a task complete when \`rigour_check\` returns PASS.**
207
-
208
- ## 📋 Available Rigour MCP Tools
209
-
210
- You MUST use these tools. They are registered via MCP and available in your tool list:
211
-
212
- - \`rigour_recall\` — Load project memory and conventions (call at the START of every task)
213
- - \`rigour_check_pattern\` — Check if a function/component/hook already exists BEFORE creating a new one
214
- - \`rigour_check\` — Run all quality gates (call BEFORE declaring done)
215
- - \`rigour_explain\` — Get detailed, actionable fix instructions for gate failures
216
- - \`rigour_get_fix_packet\` — Get machine-readable fix data for automated remediation
217
- - \`rigour_remember\` — Save important decisions, conventions, or context for future tasks
218
- - \`rigour_security_audit\` — Audit project dependencies for known CVEs
219
- - \`rigour_review\` — Review a code diff against quality gates
220
- - \`rigour_hooks_check\` — Run the fast hook checker on specific files manually
221
-
222
- ## ⚖️ Transparency & Accountability
223
-
224
- Every action, tool call, and code change is automatically logged to the project's local audit trail. This data is visible in real-time in **Rigour Studio** (the human-monitored governance dashboard).
225
-
226
- ## ⚠️ CRITICAL RULES
227
-
228
- - NEVER skip the governance loop (recall → check_pattern → write → rigour_check)
229
- - NEVER modify \`rigour.yml\` thresholds or ignore lists to make checks pass
230
- - NEVER claim "done" without a passing \`rigour_check\` result
231
- - If you're unsure whether to proceed, call \`rigour_check\` — it's fast and free
195
+ - **Never** modify \`rigour.yml\` thresholds or ignore lists to make checks pass fix the code instead.
196
+ - **Never** claim "done" without a passing quality gate result.
197
+ - Real-time hooks run automatically after every file edit. If a hook blocks you, fix the issue before continuing.
198
+ - All actions are logged to the project's audit trail, visible in **Rigour Studio**.
232
199
 
233
200
  ${AGNOSTIC_AI_INSTRUCTIONS}
234
201
  ${CODE_QUALITY_RULES}
@@ -251,40 +218,20 @@ ${COLLABORATION_RULES}
251
218
  // Cursor .mdc must be SHORT and forceful — long rules get ignored.
252
219
  // Keep ONLY the mandatory MCP tool workflow, no generic coding advice.
253
220
  const mdcContent = `---
254
- description: MANDATORY - Rigour governance. You MUST call Rigour MCP tools before and after every code task.
221
+ description: Rigour governance use Rigour MCP tools for quality gates.
255
222
  globs: **/*
256
223
  alwaysApply: true
257
224
  ---
258
225
 
259
- # Rigour Governance — MANDATORY for every task
260
-
261
- You MUST follow this exact sequence for EVERY coding task. No exceptions.
262
-
263
- ## Step 1: BEFORE writing any code
264
- \`\`\`
265
- Call rigour_recall → loads project memory and conventions
266
- Call rigour_check_pattern → checks if the thing you're creating already exists
267
- \`\`\`
268
- Both calls are REQUIRED before you write a single line of code.
269
-
270
- ## Step 2: Write your code
271
- Hooks will automatically check your code after each file edit. If a hook blocks you, fix the issue immediately.
226
+ # Rigour Governance
272
227
 
273
- ## Step 3: BEFORE saying "done"
274
- \`\`\`
275
- Call rigour_check → runs all quality gates
276
- \`\`\`
277
- If it returns FAIL, fix the issues and call rigour_check again. You may ONLY declare done when it returns PASS.
228
+ This project uses **Rigour MCP tools** for automated quality governance. The tools are self-describing — read their descriptions to discover the correct workflow automatically.
278
229
 
279
- ## When the user asks you to remember something
280
- \`\`\`
281
- Call rigour_remember with key="short_snake_case_id" and value="the full text to remember"
282
- \`\`\`
230
+ Hooks run automatically after every file edit. If a hook blocks you, fix the issue before continuing.
283
231
 
284
- ## NEVER do these
285
- - Never skip rigour_recall at the start of a task
286
- - Never skip rigour_check before declaring done
287
- - Never modify rigour.yml to make checks pass
232
+ ## Rules
233
+ - Never modify rigour.yml to make checks pass fix the code instead.
234
+ - Never claim "done" without a passing quality gate result.
288
235
  `;
289
236
  if (!(await fs.pathExists(mdcPath)) || options.force) {
290
237
  await fs.writeFile(mdcPath, mdcContent);
@@ -308,25 +255,16 @@ Call rigour_remember with key="short_snake_case_id" and value="the full text to
308
255
  const claudePath = path.join(cwd, 'CLAUDE.md');
309
256
  const claudeContent = `# CLAUDE.md - Project Instructions for Claude Code
310
257
 
311
- This file provides Claude Code with context about this project.
258
+ This project uses Rigour for quality gates. Rigour MCP tools are available — they are self-describing.
312
259
 
313
- ## Quick Commands
260
+ ## CLI Commands (alternative to MCP tools)
314
261
 
315
262
  \`\`\`bash
316
- # Run quality gates (CLI alternative to MCP)
317
- npx @rigour-labs/cli check
318
-
319
- # Get fix instructions
320
- npx @rigour-labs/cli explain
321
-
322
- # Self-healing agent loop
323
- npx @rigour-labs/cli run -- claude "<task>"
263
+ npx @rigour-labs/cli check # Run quality gates
264
+ npx @rigour-labs/cli explain # Explain failures
265
+ npx @rigour-labs/cli run -- claude "<task>" # Self-healing agent loop
324
266
  \`\`\`
325
267
 
326
- ## Rigour MCP Tools (PREFERRED over CLI)
327
-
328
- Use the Rigour MCP tools instead of CLI commands when available. They are faster and integrated into your workflow.
329
-
330
268
  ${ruleContent}`;
331
269
  if (!(await fs.pathExists(claudePath)) || options.force) {
332
270
  await fs.writeFile(claudePath, claudeContent);
@@ -340,11 +278,7 @@ ${ruleContent}`;
340
278
  const geminiStylePath = path.join(geminiDir, 'styleguide.md');
341
279
  const geminiContent = `# Gemini Code Assist Style Guide
342
280
 
343
- This project uses Rigour for quality gates.
344
-
345
- ## Required Before Completion
346
-
347
- Always run \`npx @rigour-labs/cli check\` before marking any task complete.
281
+ This project uses Rigour for quality gates. If Rigour MCP tools are available, they are self-describing — use them.
348
282
 
349
283
  ${ruleContent}`;
350
284
  if (!(await fs.pathExists(geminiStylePath)) || options.force) {
@@ -355,24 +289,13 @@ ${ruleContent}`;
355
289
  // OpenAI Codex / Aider (AGENTS.md - Universal Standard)
356
290
  if (shouldSetup('codex')) {
357
291
  const agentsPath = path.join(cwd, 'AGENTS.md');
358
- const agentsContent = `# AGENTS.md - Universal AI Agent Instructions
359
-
360
- This file provides instructions for AI coding agents (Codex, Aider, and others).
361
-
362
- ## Setup
363
-
364
- \`\`\`bash
365
- npm install
366
- npm run dev
367
- npm test
368
- \`\`\`
369
-
370
- ## Quality Gates
292
+ const agentsContent = `# AGENTS.md - AI Agent Instructions
371
293
 
372
- This project uses Rigour. Before completing any task:
294
+ This project uses Rigour for quality gates. If Rigour MCP tools are available, they are self-describing — use them. Otherwise use the CLI:
373
295
 
374
296
  \`\`\`bash
375
- npx @rigour-labs/cli check
297
+ npx @rigour-labs/cli check # Run quality gates (must PASS before task is done)
298
+ npx @rigour-labs/cli explain # Explain failures
376
299
  \`\`\`
377
300
 
378
301
  ${ruleContent}`;
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import chalk from 'chalk';
4
4
  import yaml from 'yaml';
5
5
  import { globby } from 'globby';
6
- import { GateRunner, ConfigSchema, DiscoveryService, FixPacketService, recordScore, getScoreTrend, } from '@rigour-labs/core';
6
+ import { GateRunner, ConfigSchema, DiscoveryService, FixPacketService, recordScore, getScoreTrend, renderFullReport, } from '@rigour-labs/core';
7
7
  import { buildDeepOpts, renderDeepScanResults } from './scan-deep.js';
8
8
  // Exit codes per spec
9
9
  const EXIT_PASS = 0;
@@ -73,7 +73,6 @@ export async function scanCommand(cwd, files = [], options = {}) {
73
73
  else {
74
74
  renderScanResults(report, stackSignals, scanCtx.config.output.report_path, cwd);
75
75
  }
76
- renderSummaryTable(report, isDeep);
77
76
  process.exit(report.status === 'PASS' ? EXIT_PASS : EXIT_FAIL);
78
77
  }
79
78
  catch (error) {
@@ -178,92 +177,32 @@ function renderScanHeader(scanCtx, stackSignals, isDeep = false) {
178
177
  console.log('');
179
178
  }
180
179
  function renderScanResults(report, stackSignals, reportPath, cwd) {
181
- const fakePackages = extractHallucinatedImports(report.failures);
182
- const criticalSecrets = report.failures.filter(f => f.id === 'security-patterns' && f.severity === 'critical');
183
- const phantomApis = report.failures.filter(f => f.id === 'phantom-apis');
184
- const ignoredErrors = report.failures.filter(f => f.id === 'promise-safety' && (f.severity === 'high' || f.severity === 'critical'));
185
- // --- Scary headlines for the worst findings ---
186
- let scaryHeadlines = 0;
187
- if (criticalSecrets.length > 0) {
188
- console.log(chalk.red.bold(`🔑 HARDCODED SECRETS: ${criticalSecrets.length} credential(s) exposed in plain text`));
189
- const firstFile = criticalSecrets[0].files?.[0];
190
- if (firstFile)
191
- console.log(chalk.dim(` First hit: ${firstFile}`));
192
- scaryHeadlines++;
193
- }
194
- if (fakePackages.length > 0) {
195
- const unique = [...new Set(fakePackages)];
196
- console.log(chalk.red.bold(`📦 HALLUCINATED PACKAGES: ${unique.length} import(s) don't exist — will crash at runtime`));
197
- console.log(chalk.dim(` Examples: ${unique.slice(0, 4).join(', ')}${unique.length > 4 ? `, +${unique.length - 4} more` : ''}`));
198
- scaryHeadlines++;
199
- }
200
- if (phantomApis.length > 0) {
201
- console.log(chalk.red.bold(`👻 PHANTOM APIs: ${phantomApis.length} call(s) to methods that don't exist in stdlib`));
202
- scaryHeadlines++;
203
- }
204
- if (ignoredErrors.length > 0) {
205
- console.log(chalk.yellow.bold(`🔇 SILENT FAILURES: ${ignoredErrors.length} async error(s) swallowed — failures will vanish without a trace`));
206
- scaryHeadlines++;
207
- }
208
- if (scaryHeadlines > 0)
209
- console.log('');
210
- const statusColor = report.status === 'PASS' ? chalk.green.bold : chalk.red.bold;
211
- const statusLabel = report.status === 'PASS' ? 'PASS' : 'FAIL';
212
- const score = report.stats.score ?? 0;
213
- const aiHealth = report.stats.ai_health_score ?? 0;
214
- const structural = report.stats.structural_score ?? 0;
215
- console.log(statusColor(`${statusLabel} | Score ${score}/100 | AI Health ${aiHealth}/100 | Structural ${structural}/100`));
216
- const severity = report.stats.severity_breakdown || {};
217
- const sevParts = ['critical', 'high', 'medium', 'low', 'info']
218
- .filter(level => (severity[level] || 0) > 0)
219
- .map(level => `${level}: ${severity[level]}`);
220
- if (sevParts.length > 0) {
221
- console.log(`Severity: ${sevParts.join(', ')}`);
222
- }
223
- renderCoverageWarnings(stackSignals);
224
- console.log('');
225
- if (report.status === 'FAIL') {
226
- // Sort by severity so critical findings appear first
227
- const SEVERITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
228
- const sorted = [...report.failures].sort((a, b) => (SEVERITY_ORDER[a.severity ?? 'medium'] ?? 2) - (SEVERITY_ORDER[b.severity ?? 'medium'] ?? 2));
229
- const topFindings = sorted.slice(0, 8);
230
- for (const failure of topFindings) {
231
- const sev = failure.severity ?? 'medium';
232
- const sevColor = sev === 'critical' ? chalk.red.bold
233
- : sev === 'high' ? chalk.yellow.bold
234
- : sev === 'medium' ? chalk.white
235
- : chalk.dim;
236
- console.log(sevColor(`${sev.toUpperCase().padEnd(8)} [${failure.id}] ${failure.title}`));
237
- if (failure.files && failure.files.length > 0) {
238
- console.log(chalk.dim(` ${failure.files.slice(0, 2).join(', ')}`));
239
- }
240
- }
241
- if (report.failures.length > topFindings.length) {
242
- console.log(chalk.dim(`\n...and ${report.failures.length - topFindings.length} more. See full report.`));
243
- }
244
- }
180
+ // Build render options with Brain + trend data
245
181
  const trend = getScoreTrend(cwd);
182
+ const renderOpts = {
183
+ showBrain: true,
184
+ brainPatterns: 0,
185
+ brainTrend: 'stable',
186
+ };
246
187
  if (trend && trend.recentScores.length >= 3) {
247
- const arrow = trend.direction === 'improving' ? '↑' : trend.direction === 'degrading' ? '↓' : '→';
248
- const color = trend.direction === 'improving' ? chalk.green : trend.direction === 'degrading' ? chalk.red : chalk.dim;
249
- console.log(color(`\nTrend: ${trend.recentScores.join(' → ')} ${arrow}`));
188
+ renderOpts.recentScores = trend.recentScores;
189
+ renderOpts.brainTrend = trend.direction;
250
190
  }
251
- console.log(chalk.yellow(`\nFull report: ${reportPath}`));
252
- if (report.status === 'FAIL') {
253
- console.log(chalk.yellow('Fix packet: rigour-fix-packet.json'));
191
+ // Try to get Brain pattern count
192
+ try {
193
+ const dbPath = path.join(cwd, '.rigour', 'rigour.db');
194
+ if (fs.existsSync(dbPath)) {
195
+ renderOpts.brainPatterns = 1; // Indicate Brain is active (exact count comes from SQLite)
196
+ }
254
197
  }
255
- console.log(chalk.dim(`Finished in ${report.stats.duration_ms}ms`));
256
- // --- Next steps ---
257
- console.log('');
198
+ catch { /* ignore */ }
199
+ // Render the rich report
200
+ console.log(renderFullReport(report, renderOpts));
201
+ // Coverage warnings still relevant
202
+ renderCoverageWarnings(stackSignals);
203
+ console.log(chalk.dim(`\n Report: ${reportPath}`));
258
204
  if (report.status === 'FAIL') {
259
- console.log(chalk.bold('Next steps:'));
260
- console.log(` ${chalk.cyan('rigour explain')} — get plain-English fix suggestions`);
261
- console.log(` ${chalk.cyan('rigour init')} — add quality gates to your project (blocks AI from repeating this)`);
262
- console.log(` ${chalk.cyan('rigour check --ci')} — enforce in CI/CD pipeline`);
263
- }
264
- else {
265
- console.log(chalk.green.bold('✓ This repo is clean. Add it to CI to keep it that way:'));
266
- console.log(` ${chalk.cyan('rigour init')} — write quality gates to rigour.yml + CI config`);
205
+ console.log(chalk.dim(` Fix packet: rigour-fix-packet.json`));
267
206
  }
268
207
  }
269
208
  export function renderCoverageWarnings(stackSignals) {
@@ -343,58 +282,3 @@ async function writeLastScanJson(cwd, scanCtx, stackSignals, report, isDeep) {
343
282
  };
344
283
  await fs.writeJson(lastScanPath, payload, { spaces: 2 });
345
284
  }
346
- /**
347
- * Render a compact summary table to the terminal after main scan output.
348
- * Shows findings grouped by gate and provenance — always printed regardless of deep/standard mode.
349
- */
350
- function renderSummaryTable(report, isDeep) {
351
- if (report.failures.length === 0)
352
- return;
353
- console.log('');
354
- console.log(chalk.bold.underline('Summary by Gate'));
355
- console.log('');
356
- // Group failures by gate ID
357
- const byGate = new Map();
358
- for (const f of report.failures) {
359
- const existing = byGate.get(f.id) || { count: 0, critical: 0, high: 0, medium: 0, low: 0, provenance: f.provenance || 'traditional' };
360
- existing.count++;
361
- const sev = f.severity ?? 'medium';
362
- if (sev === 'critical')
363
- existing.critical++;
364
- else if (sev === 'high')
365
- existing.high++;
366
- else if (sev === 'medium')
367
- existing.medium++;
368
- else
369
- existing.low++;
370
- byGate.set(f.id, existing);
371
- }
372
- // Sort by total count descending
373
- const sorted = [...byGate.entries()].sort((a, b) => b[1].count - a[1].count);
374
- // Print header
375
- const gateCol = 28;
376
- const numCol = 6;
377
- const header = ` ${'Gate'.padEnd(gateCol)} ${'Total'.padStart(numCol)} ${'Crit'.padStart(numCol)} ${'High'.padStart(numCol)} ${'Med'.padStart(numCol)} ${'Low'.padStart(numCol)} Provenance`;
378
- console.log(chalk.dim(header));
379
- console.log(chalk.dim(' ' + '─'.repeat(header.length - 2)));
380
- for (const [gateId, stats] of sorted) {
381
- const provColor = stats.provenance === 'ai-drift' ? chalk.magenta
382
- : stats.provenance === 'security' ? chalk.red
383
- : stats.provenance === 'deep-analysis' ? chalk.blue
384
- : chalk.dim;
385
- const critStr = stats.critical > 0 ? chalk.red.bold(String(stats.critical).padStart(numCol)) : chalk.dim(String(stats.critical).padStart(numCol));
386
- const highStr = stats.high > 0 ? chalk.yellow(String(stats.high).padStart(numCol)) : chalk.dim(String(stats.high).padStart(numCol));
387
- console.log(` ${gateId.padEnd(gateCol)} ${String(stats.count).padStart(numCol)} ${critStr} ${highStr} ${chalk.dim(String(stats.medium).padStart(numCol))} ${chalk.dim(String(stats.low).padStart(numCol))} ${provColor(stats.provenance)}`);
388
- }
389
- // Totals row
390
- const totals = sorted.reduce((acc, [, s]) => ({
391
- count: acc.count + s.count,
392
- critical: acc.critical + s.critical,
393
- high: acc.high + s.high,
394
- medium: acc.medium + s.medium,
395
- low: acc.low + s.low,
396
- }), { count: 0, critical: 0, high: 0, medium: 0, low: 0 });
397
- console.log(chalk.dim(' ' + '─'.repeat(header.length - 2)));
398
- console.log(chalk.bold(` ${'TOTAL'.padEnd(gateCol)} ${String(totals.count).padStart(numCol)} ${String(totals.critical).padStart(numCol)} ${String(totals.high).padStart(numCol)} ${String(totals.medium).padStart(numCol)} ${String(totals.low).padStart(numCol)}`));
399
- console.log(chalk.dim(`\n Details saved to: .rigour/last-scan.json`));
400
- }
@@ -25,10 +25,10 @@ describe('Init Command Rules Verification', () => {
25
25
  const instructionsContent = await fs.readFile(instructionsPath, 'utf-8');
26
26
  const mdcContent = await fs.readFile(mdcPath, 'utf-8');
27
27
  // Check for agnostic instructions
28
- expect(instructionsContent).toContain('# 🤖 CRITICAL INSTRUCTION FOR AI');
29
- expect(instructionsContent).toContain('VERIFICATION PROOF REQUIRED');
28
+ expect(instructionsContent).toContain('# Rigour Quality Gates');
29
+ expect(instructionsContent).toContain('Verification');
30
30
  // Check for key sections in universal instructions
31
- expect(instructionsContent).toContain('# 🛡️ Rigour: Mandatory Engineering Governance Protocol');
31
+ expect(instructionsContent).toContain('# Rigour: Engineering Governance');
32
32
  expect(instructionsContent).toContain('# Code Quality Standards');
33
33
  // Check that MDC includes governance rules
34
34
  expect(mdcContent).toContain('# Rigour Governance');
@@ -39,6 +39,6 @@ describe('Init Command Rules Verification', () => {
39
39
  const clineRulesPath = path.join(testDir, '.clinerules');
40
40
  expect(await fs.pathExists(clineRulesPath)).toBe(true);
41
41
  const content = await fs.readFile(clineRulesPath, 'utf-8');
42
- expect(content).toContain('# 🤖 CRITICAL INSTRUCTION FOR AI');
42
+ expect(content).toContain('# Rigour: Engineering Governance');
43
43
  });
44
44
  });
package/package.json CHANGED
@@ -1,21 +1,30 @@
1
1
  {
2
2
  "name": "@rigour-labs/cli",
3
- "version": "5.2.2",
4
- "description": "CLI quality gates for AI-generated code. Forces AI agents (Claude, Cursor, Copilot) to meet strict engineering standards with PASS/FAIL enforcement.",
3
+ "version": "5.2.4",
4
+ "description": "AI-native quality gates with local LLM analysis. Forces AI agents (Claude, Cursor, Copilot, Cline, Windsurf) to meet engineering standards. Bayesian Brain learns your codebase. Zero config: npx rigour-scan.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
7
7
  "keywords": [
8
- "quality-gates",
8
+ "ai",
9
+ "llm",
9
10
  "ai-code-quality",
11
+ "ai-agent",
12
+ "quality-gates",
10
13
  "cli",
11
14
  "linter",
12
15
  "static-analysis",
16
+ "security",
17
+ "vibe-coding",
13
18
  "claude",
14
19
  "cursor",
15
20
  "copilot",
21
+ "cline",
22
+ "windsurf",
16
23
  "mcp",
17
24
  "code-review",
18
- "ci-cd"
25
+ "ci-cd",
26
+ "fix-packets",
27
+ "agent-governance"
19
28
  ],
20
29
  "type": "module",
21
30
  "bin": {
@@ -44,7 +53,7 @@
44
53
  "inquirer": "9.2.16",
45
54
  "ora": "^8.0.1",
46
55
  "yaml": "^2.8.2",
47
- "@rigour-labs/core": "5.2.2"
56
+ "@rigour-labs/core": "5.2.4"
48
57
  },
49
58
  "devDependencies": {
50
59
  "@types/fs-extra": "^11.0.4",