@rigour-labs/cli 2.19.0 β†’ 2.19.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 ADDED
@@ -0,0 +1,85 @@
1
+ # @rigour-labs/cli
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@rigour-labs/cli?color=cyan)](https://www.npmjs.com/package/@rigour-labs/cli)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@rigour-labs/cli?color=blue)](https://www.npmjs.com/package/@rigour-labs/cli)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ **Local-first quality gates for AI-generated code.**
8
+ Rigour forces AI agents to meet strict engineering standards before marking tasks "Done".
9
+
10
+ > **Zero cloud. Zero telemetry. PASS/FAIL is always free.**
11
+
12
+ ## πŸš€ Quick Start
13
+
14
+ ```bash
15
+ npx rigour init # Initialize quality gates
16
+ npx rigour check # Verify code quality
17
+ npx rigour run -- claude "Build feature X" # Agent loop
18
+ ```
19
+
20
+ ## πŸ›‘ The Problem
21
+
22
+ AI agents often fall into **"Vibe Coding"**β€”claiming success based on narrative, not execution:
23
+
24
+ 1. Agent makes a change
25
+ 2. Agent **claims** "Task 100% complete"
26
+ 3. **CI Fails** with type errors, lint failures, or broken tests
27
+
28
+ **Rigour breaks this cycle** by forcing agents to face the same verification tools (ruff, mypy, vitest) that CI runsβ€”locally and immediately.
29
+
30
+ ## πŸ”„ How It Works
31
+
32
+ ```
33
+ Agent writes code β†’ Rigour checks β†’ FAIL? β†’ Fix Packet β†’ Agent retries β†’ PASS βœ“
34
+ ```
35
+
36
+ ## βš™οΈ Quality Gates
37
+
38
+ | Gate | Description |
39
+ |:---|:---|
40
+ | **File Size** | Max lines per file (default: 300-500) |
41
+ | **Hygiene** | No TODO/FIXME comments allowed |
42
+ | **Complexity** | Cyclomatic complexity limits (AST-based) |
43
+ | **Required Docs** | SPEC.md, ARCH.md, README must exist |
44
+ | **Safety Rails** | Protected paths, max files changed |
45
+ | **Context Alignment** | Prevents drift by anchoring on project patterns |
46
+
47
+ ## πŸ› οΈ Commands
48
+
49
+ | Command | Purpose |
50
+ |:---|:---|
51
+ | `rigour init` | Setup Rigour in your project |
52
+ | `rigour check` | Validate code against quality gates |
53
+ | `rigour check --ci` | CI mode with appropriate output |
54
+ | `rigour explain` | Detailed explanation of validation results |
55
+ | `rigour run` | Supervisor loop for iterative refinement |
56
+ | `rigour studio` | Dashboard for monitoring |
57
+ | `rigour index` | Build semantic index of codebase patterns |
58
+
59
+ ## πŸ€– Works With
60
+
61
+ - **Claude Code**: `rigour run -- claude "..."`
62
+ - **Cursor / Cline / Gemini**: Via MCP server (`rigour_check`, `rigour_explain`)
63
+
64
+ ## πŸ“– Documentation
65
+
66
+ **[πŸ“š Full Documentation β†’](https://docs.rigour.run/)**
67
+
68
+ | Quick Links | |
69
+ |:---|:---|
70
+ | [Getting Started](https://docs.rigour.run/getting-started) | Install and run in 60 seconds |
71
+ | [CLI Reference](https://docs.rigour.run/cli/commands) | All commands and options |
72
+ | [Configuration](https://docs.rigour.run/reference/configuration) | Customize quality gates |
73
+ | [MCP Integration](https://docs.rigour.run/mcp/mcp-server) | AI agent setup |
74
+
75
+ ## πŸ§ͺ CI Integration
76
+
77
+ ```yaml
78
+ - run: npx rigour check --ci
79
+ ```
80
+
81
+ ## πŸ“œ License
82
+
83
+ MIT Β© [Rigour Labs](https://github.com/rigour-labs)
84
+
85
+ > *"Rigour adds the engineering."*
package/dist/cli.js CHANGED
@@ -8,14 +8,16 @@ import { guideCommand } from './commands/guide.js';
8
8
  import { setupCommand } from './commands/setup.js';
9
9
  import { indexCommand } from './commands/index.js';
10
10
  import { studioCommand } from './commands/studio.js';
11
+ import { checkForUpdates } from './utils/version.js';
11
12
  import chalk from 'chalk';
13
+ const CLI_VERSION = '2.0.0';
12
14
  const program = new Command();
13
15
  program.addCommand(indexCommand);
14
16
  program.addCommand(studioCommand);
15
17
  program
16
18
  .name('rigour')
17
19
  .description('πŸ›‘οΈ Rigour: The Quality Gate Loop for AI-Assisted Engineering')
18
- .version('2.0.0')
20
+ .version(CLI_VERSION)
19
21
  .addHelpText('before', chalk.bold.cyan(`
20
22
  ____ _
21
23
  / __ \\(_)____ ___ __ __ _____
@@ -32,6 +34,7 @@ program
32
34
  .option('--ide <name>', 'Target IDE (cursor, vscode, all). Auto-detects if not specified.')
33
35
  .option('--dry-run', 'Show detected configuration without writing files')
34
36
  .option('--explain', 'Show detection markers for roles and paradigms')
37
+ .option('-f, --force', 'Force re-initialization, overwriting existing rigour.yml')
35
38
  .addHelpText('after', `
36
39
  Examples:
37
40
  $ rigour init # Auto-discover role & paradigm
@@ -100,4 +103,17 @@ program
100
103
  .action(async () => {
101
104
  await setupCommand();
102
105
  });
103
- program.parse();
106
+ // Check for updates before parsing (non-blocking)
107
+ (async () => {
108
+ try {
109
+ const updateInfo = await checkForUpdates(CLI_VERSION);
110
+ if (updateInfo?.hasUpdate) {
111
+ console.log(chalk.yellow(`\n⚑ Update available: ${updateInfo.currentVersion} β†’ ${updateInfo.latestVersion}`));
112
+ console.log(chalk.dim(` Run: npx @rigour-labs/cli@latest init --force\n`));
113
+ }
114
+ }
115
+ catch {
116
+ // Ignore version check errors
117
+ }
118
+ program.parse();
119
+ })();
@@ -4,5 +4,6 @@ export interface InitOptions {
4
4
  ide?: 'cursor' | 'vscode' | 'cline' | 'claude' | 'gemini' | 'codex' | 'windsurf' | 'all';
5
5
  dryRun?: boolean;
6
6
  explain?: boolean;
7
+ force?: boolean;
7
8
  }
8
9
  export declare function initCommand(cwd: string, options?: InitOptions): Promise<void>;
@@ -127,8 +127,16 @@ export async function initCommand(cwd, options = {}) {
127
127
  }
128
128
  const configPath = path.join(cwd, 'rigour.yml');
129
129
  if (await fs.pathExists(configPath)) {
130
- console.log(chalk.yellow('rigour.yml already exists. Skipping initialization.'));
131
- return;
130
+ if (!options.force) {
131
+ console.log(chalk.yellow('rigour.yml already exists.'));
132
+ console.log(chalk.dim(' β†’ Run with --force to regenerate with latest templates'));
133
+ console.log(chalk.dim(' β†’ Your current config will be backed up to rigour.yml.bak'));
134
+ return;
135
+ }
136
+ // Backup existing config
137
+ const backupPath = path.join(cwd, 'rigour.yml.bak');
138
+ await fs.copy(configPath, backupPath);
139
+ console.log(chalk.dim(` Backed up existing config to rigour.yml.bak`));
132
140
  }
133
141
  console.log(chalk.bold.blue('\nπŸ” Rigour Auto-Discovery:'));
134
142
  const requestId = randomUUID();
@@ -0,0 +1,7 @@
1
+ interface UpdateCheckResult {
2
+ hasUpdate: boolean;
3
+ currentVersion: string;
4
+ latestVersion: string;
5
+ }
6
+ export declare function checkForUpdates(currentVersion: string): Promise<UpdateCheckResult | null>;
7
+ export {};
@@ -0,0 +1,81 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const CACHE_FILE = path.join(os.homedir(), '.rigour-version-cache.json');
5
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
6
+ const NPM_REGISTRY_URL = 'https://registry.npmjs.org/@rigour-labs/cli/latest';
7
+ async function getCachedVersion() {
8
+ try {
9
+ if (await fs.pathExists(CACHE_FILE)) {
10
+ const cache = await fs.readJson(CACHE_FILE);
11
+ if (Date.now() - cache.timestamp < CACHE_TTL_MS) {
12
+ return cache.latestVersion;
13
+ }
14
+ }
15
+ }
16
+ catch {
17
+ // Ignore cache read errors
18
+ }
19
+ return null;
20
+ }
21
+ async function cacheVersion(version) {
22
+ try {
23
+ await fs.writeJson(CACHE_FILE, {
24
+ latestVersion: version,
25
+ timestamp: Date.now()
26
+ });
27
+ }
28
+ catch {
29
+ // Ignore cache write errors
30
+ }
31
+ }
32
+ async function fetchLatestVersion() {
33
+ try {
34
+ const controller = new AbortController();
35
+ const timeout = setTimeout(() => controller.abort(), 3000);
36
+ const response = await fetch(NPM_REGISTRY_URL, {
37
+ signal: controller.signal,
38
+ headers: { 'Accept': 'application/json' }
39
+ });
40
+ clearTimeout(timeout);
41
+ if (!response.ok)
42
+ return null;
43
+ const data = await response.json();
44
+ return data.version || null;
45
+ }
46
+ catch {
47
+ // Network errors are non-fatal
48
+ return null;
49
+ }
50
+ }
51
+ function compareVersions(current, latest) {
52
+ const currentParts = current.replace(/^v/, '').split('.').map(Number);
53
+ const latestParts = latest.replace(/^v/, '').split('.').map(Number);
54
+ for (let i = 0; i < 3; i++) {
55
+ const c = currentParts[i] || 0;
56
+ const l = latestParts[i] || 0;
57
+ if (l > c)
58
+ return true;
59
+ if (l < c)
60
+ return false;
61
+ }
62
+ return false;
63
+ }
64
+ export async function checkForUpdates(currentVersion) {
65
+ // Try cache first
66
+ let latestVersion = await getCachedVersion();
67
+ // Fetch from npm if no cache
68
+ if (!latestVersion) {
69
+ latestVersion = await fetchLatestVersion();
70
+ if (latestVersion) {
71
+ await cacheVersion(latestVersion);
72
+ }
73
+ }
74
+ if (!latestVersion)
75
+ return null;
76
+ return {
77
+ hasUpdate: compareVersions(currentVersion, latestVersion),
78
+ currentVersion,
79
+ latestVersion
80
+ };
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/cli",
3
- "version": "2.19.0",
3
+ "version": "2.19.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "rigour": "dist/cli.js"
@@ -28,7 +28,7 @@
28
28
  "inquirer": "9.2.16",
29
29
  "ora": "^8.0.1",
30
30
  "yaml": "^2.8.2",
31
- "@rigour-labs/core": "2.19.0"
31
+ "@rigour-labs/core": "2.19.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/fs-extra": "^11.0.4",