@rigour-labs/cli 1.0.0 → 1.4.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.
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setupCommand = setupCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ async function setupCommand() {
9
+ console.log(chalk_1.default.bold.cyan('\nšŸ› ļø Rigour Labs | Setup & Installation\n'));
10
+ console.log(chalk_1.default.bold('1. Global Installation (Recommended)'));
11
+ console.log(chalk_1.default.dim(' To use Rigour anywhere in your terminal:'));
12
+ console.log(chalk_1.default.green(' $ npm install -g @rigour-labs/cli\n'));
13
+ console.log(chalk_1.default.bold('2. Project-Local installation'));
14
+ console.log(chalk_1.default.dim(' To keep Rigour versioned with your project:'));
15
+ console.log(chalk_1.default.green(' $ npm install --save-dev @rigour-labs/cli\n'));
16
+ console.log(chalk_1.default.bold('3. Standalone Binaries (Zero-Install)'));
17
+ console.log(chalk_1.default.dim(' If you do not want to use Node.js:'));
18
+ console.log(chalk_1.default.dim(' • macOS: ') + chalk_1.default.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-macos'));
19
+ console.log(chalk_1.default.dim(' • Linux: ') + chalk_1.default.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-linux'));
20
+ console.log(chalk_1.default.dim(' • Windows: ') + chalk_1.default.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-windows.exe\n'));
21
+ console.log(chalk_1.default.bold('4. MCP Integration (for AI Agents)'));
22
+ console.log(chalk_1.default.dim(' To let Cursor or Claude use Rigour natively:'));
23
+ console.log(chalk_1.default.dim(' Path to MCP: ') + chalk_1.default.cyan('packages/rigour-mcp/dist/index.js'));
24
+ console.log(chalk_1.default.dim(' Add this to your Cursor/Claude settings.\n'));
25
+ console.log(chalk_1.default.bold('Update Guidance:'));
26
+ console.log(chalk_1.default.dim(' Keep Rigour sharp by updating regularly:'));
27
+ console.log(chalk_1.default.green(' $ npm install -g @rigour-labs/cli@latest\n'));
28
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@rigour-labs/cli",
3
- "version": "1.0.0",
3
+ "version": "1.4.0",
4
4
  "bin": {
5
5
  "rigour": "dist/cli.js"
6
6
  },
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/erashu212/rigour"
9
+ "url": "https://github.com/rigour-labs/rigour"
10
10
  },
11
11
  "publishConfig": {
12
12
  "access": "public",
@@ -20,7 +20,7 @@
20
20
  "fs-extra": "^11.2.0",
21
21
  "globby": "^14.0.1",
22
22
  "yaml": "^2.8.2",
23
- "@rigour-labs/core": "1.0.0"
23
+ "@rigour-labs/core": "1.4.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/fs-extra": "^11.0.4",
package/src/cli.ts CHANGED
@@ -2,36 +2,98 @@
2
2
  import { Command } from 'commander';
3
3
  import { initCommand } from './commands/init.js';
4
4
  import { checkCommand } from './commands/check.js';
5
+ import { explainCommand } from './commands/explain.js';
5
6
  import { runLoop } from './commands/run.js';
7
+ import { guideCommand } from './commands/guide.js';
8
+ import { setupCommand } from './commands/setup.js';
9
+ import chalk from 'chalk';
6
10
 
7
11
  const program = new Command();
8
12
 
9
13
  program
10
14
  .name('rigour')
11
- .description('A quality gate loop controller for AI-assisted coding')
12
- .version('1.0.0');
15
+ .description('šŸ›”ļø Rigour: The Quality Gate Loop for AI-Assisted Engineering')
16
+ .version('1.3.0')
17
+ .addHelpText('before', chalk.bold.cyan(`
18
+ ____ _
19
+ / __ \\(_)____ ___ __ __ _____
20
+ / /_/ // // __ \`/ / / / / // ___/
21
+ / _, _// // /_/ // /_/ / / // /
22
+ /_/ |_|/_/ \\__, / \\__,_/_/ /_/
23
+ /____/
24
+ `));
13
25
 
14
26
  program
15
27
  .command('init')
16
- .description('Initialize VibeGuard in the current directory')
17
- .action(async () => {
18
- await initCommand(process.cwd());
28
+ .description('Initialize Rigour in the current directory')
29
+ .option('-p, --preset <name>', 'Project preset (ui, api, infra, data)')
30
+ .option('--paradigm <name>', 'Coding paradigm (oop, functional, minimal)')
31
+ .option('--dry-run', 'Show detected configuration without writing files')
32
+ .option('--explain', 'Show detection markers for roles and paradigms')
33
+ .addHelpText('after', `
34
+ Examples:
35
+ $ rigour init # Auto-discover role & paradigm
36
+ $ rigour init --preset api --explain # Force API role and show why
37
+ `)
38
+ .action(async (options: any) => {
39
+ await initCommand(process.cwd(), options);
19
40
  });
20
41
 
21
42
  program
22
43
  .command('check')
23
44
  .description('Run quality gate checks')
45
+ .option('--ci', 'CI mode (minimal output, non-zero exit on fail)')
46
+ .option('--json', 'Output report in JSON format')
47
+ .addHelpText('after', `
48
+ Examples:
49
+ $ rigour check # Run interactive check
50
+ $ rigour check --ci # Run in CI environment
51
+ `)
52
+ .action(async (options: any) => {
53
+ await checkCommand(process.cwd(), options);
54
+ });
55
+
56
+ program
57
+ .command('explain')
58
+ .description('Explain the last quality gate report with actionable bullets')
59
+ .addHelpText('after', `
60
+ Examples:
61
+ $ rigour explain # Get a human-readable violation summary
62
+ `)
24
63
  .action(async () => {
25
- await checkCommand(process.cwd());
64
+ await explainCommand(process.cwd());
26
65
  });
27
66
 
28
67
  program
29
68
  .command('run')
30
69
  .description('Execute an agent command in a loop until quality gates pass')
31
70
  .argument('[command...]', 'The agent command to run (e.g., cursor-agent ...)')
32
- .option('-i, --iterations <number>', 'Maximum number of loop iterations', '3')
33
- .action(async (args, options) => {
34
- await runLoop(process.cwd(), args, { iterations: parseInt(options.iterations) });
71
+ .option('-c, --max-cycles <number>', 'Maximum number of loop iterations', '3')
72
+ .option('--fail-fast', 'Abort loop immediately on first gate failure')
73
+ .addHelpText('after', `
74
+ Examples:
75
+ $ rigour run -- claude "fix issues" # Loop Claude until PASS
76
+ $ rigour run -c 5 -- cursor-agent # Run Cursor agent for up to 5 cycles
77
+ `)
78
+ .action(async (args: string[], options: any) => {
79
+ await runLoop(process.cwd(), args, {
80
+ iterations: parseInt(options.maxCycles),
81
+ failFast: !!options.failFast
82
+ });
83
+ });
84
+
85
+ program
86
+ .command('guide')
87
+ .description('Show the interactive engineering guide')
88
+ .action(async () => {
89
+ await guideCommand();
90
+ });
91
+
92
+ program
93
+ .command('setup')
94
+ .description('Show installation and global setup guidance')
95
+ .action(async () => {
96
+ await setupCommand();
35
97
  });
36
98
 
37
99
  program.parse();
@@ -4,52 +4,105 @@ import chalk from 'chalk';
4
4
  import yaml from 'yaml';
5
5
  import { GateRunner, ConfigSchema, Failure } from '@rigour-labs/core';
6
6
 
7
- export async function checkCommand(cwd: string) {
7
+ // Exit codes per spec
8
+ const EXIT_PASS = 0;
9
+ const EXIT_FAIL = 1;
10
+ const EXIT_CONFIG_ERROR = 2;
11
+ const EXIT_INTERNAL_ERROR = 3;
12
+
13
+ export interface CheckOptions {
14
+ ci?: boolean;
15
+ json?: boolean;
16
+ }
17
+
18
+ export async function checkCommand(cwd: string, options: CheckOptions = {}) {
8
19
  const configPath = path.join(cwd, 'rigour.yml');
9
20
 
10
21
  if (!(await fs.pathExists(configPath))) {
11
- console.error(chalk.red('Error: rigour.yml not found. Run `rigour init` first.'));
12
- process.exit(1);
22
+ if (options.json) {
23
+ console.log(JSON.stringify({ error: 'CONFIG_ERROR', message: 'rigour.yml not found' }));
24
+ } else if (!options.ci) {
25
+ console.error(chalk.red('Error: rigour.yml not found. Run `rigour init` first.'));
26
+ }
27
+ process.exit(EXIT_CONFIG_ERROR);
13
28
  }
14
29
 
15
- const configContent = await fs.readFile(configPath, 'utf-8');
16
- const rawConfig = yaml.parse(configContent);
17
- const config = ConfigSchema.parse(rawConfig);
30
+ try {
31
+ const configContent = await fs.readFile(configPath, 'utf-8');
32
+ const rawConfig = yaml.parse(configContent);
33
+ const config = ConfigSchema.parse(rawConfig);
18
34
 
19
- console.log(chalk.blue('Running Rigour checks...\n'));
35
+ if (!options.ci && !options.json) {
36
+ console.log(chalk.blue('Running Rigour checks...\n'));
37
+ }
38
+
39
+ const runner = new GateRunner(config);
40
+ const report = await runner.run(cwd);
20
41
 
21
- const runner = new GateRunner(config);
22
- const report = await runner.run(cwd);
42
+ // Write machine report
43
+ const reportPath = path.join(cwd, config.output.report_path);
44
+ await fs.writeJson(reportPath, report, { spaces: 2 });
23
45
 
24
- // Write machine report
25
- const reportPath = path.join(cwd, config.output.report_path);
26
- await fs.writeJson(reportPath, report, { spaces: 2 });
46
+ // Generate Fix Packet v2 on failure
47
+ if (report.status === 'FAIL') {
48
+ const { FixPacketService } = await import('@rigour-labs/core');
49
+ const fixPacketService = new FixPacketService();
50
+ const fixPacket = fixPacketService.generate(report, config);
51
+ const fixPacketPath = path.join(cwd, 'rigour-fix-packet.json');
52
+ await fs.writeJson(fixPacketPath, fixPacket, { spaces: 2 });
53
+ }
27
54
 
28
- // Print human summary
29
- if (report.status === 'PASS') {
30
- console.log(chalk.green.bold('āœ” PASS - All quality gates satisfied.'));
31
- } else {
32
- console.log(chalk.red.bold('✘ FAIL - Quality gate violations found.\n'));
55
+ // JSON output mode
56
+ if (options.json) {
57
+ console.log(JSON.stringify(report, null, 2));
58
+ process.exit(report.status === 'PASS' ? EXIT_PASS : EXIT_FAIL);
59
+ }
33
60
 
34
- for (const failure of report.failures as Failure[]) {
35
- console.log(chalk.red(`[${failure.id}] ${failure.title}`));
36
- console.log(chalk.dim(` Details: ${failure.details}`));
37
- if (failure.files && failure.files.length > 0) {
38
- console.log(chalk.dim(' Files:'));
39
- failure.files.forEach((f: string) => console.log(chalk.dim(` - ${f}`)));
61
+ // CI mode: minimal output
62
+ if (options.ci) {
63
+ if (report.status === 'PASS') {
64
+ console.log('PASS');
65
+ } else {
66
+ console.log(`FAIL: ${report.failures.length} violation(s)`);
67
+ report.failures.forEach((f: Failure) => {
68
+ console.log(` - [${f.id}] ${f.title}`);
69
+ });
40
70
  }
41
- if (failure.hint) {
42
- console.log(chalk.cyan(` Hint: ${failure.hint}`));
71
+ process.exit(report.status === 'PASS' ? EXIT_PASS : EXIT_FAIL);
72
+ }
73
+
74
+ // Normal human-readable output
75
+ if (report.status === 'PASS') {
76
+ console.log(chalk.green.bold('āœ” PASS - All quality gates satisfied.'));
77
+ } else {
78
+ console.log(chalk.red.bold('✘ FAIL - Quality gate violations found.\n'));
79
+
80
+ for (const failure of report.failures as Failure[]) {
81
+ console.log(chalk.red(`[${failure.id}] ${failure.title}`));
82
+ console.log(chalk.dim(` Details: ${failure.details}`));
83
+ if (failure.files && failure.files.length > 0) {
84
+ console.log(chalk.dim(' Files:'));
85
+ failure.files.forEach((f: string) => console.log(chalk.dim(` - ${f}`)));
86
+ }
87
+ if (failure.hint) {
88
+ console.log(chalk.cyan(` Hint: ${failure.hint}`));
89
+ }
90
+ console.log('');
43
91
  }
44
- console.log('');
92
+
93
+ console.log(chalk.yellow(`See ${config.output.report_path} for full details.`));
45
94
  }
46
95
 
47
- console.log(chalk.yellow(`See ${config.output.report_path} for full details.`));
48
- }
96
+ console.log(chalk.dim(`\nFinished in ${report.stats.duration_ms}ms`));
49
97
 
50
- console.log(chalk.dim(`\nFinished in ${report.stats.duration_ms}ms`));
98
+ process.exit(report.status === 'PASS' ? EXIT_PASS : EXIT_FAIL);
51
99
 
52
- if (report.status !== 'PASS') {
53
- process.exit(1);
100
+ } catch (error: any) {
101
+ if (options.json) {
102
+ console.log(JSON.stringify({ error: 'INTERNAL_ERROR', message: error.message }));
103
+ } else if (!options.ci) {
104
+ console.error(chalk.red(`Internal error: ${error.message}`));
105
+ }
106
+ process.exit(EXIT_INTERNAL_ERROR);
54
107
  }
55
108
  }
@@ -0,0 +1,68 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ export async function explainCommand(cwd: string) {
6
+ const configPath = path.join(cwd, 'rigour.yml');
7
+ let reportPath = path.join(cwd, 'rigour-report.json');
8
+
9
+ // Try to read custom path from config
10
+ if (await fs.pathExists(configPath)) {
11
+ try {
12
+ const yaml = await import('yaml');
13
+ const configContent = await fs.readFile(configPath, 'utf-8');
14
+ const config = yaml.parse(configContent);
15
+ if (config?.output?.report_path) {
16
+ reportPath = path.join(cwd, config.output.report_path);
17
+ }
18
+ } catch (e) { }
19
+ }
20
+
21
+ if (!(await fs.pathExists(reportPath))) {
22
+ console.error(chalk.red(`Error: No report found at ${reportPath}`));
23
+ console.error(chalk.dim('Run `rigour check` first to generate a report.'));
24
+ process.exit(2);
25
+ }
26
+
27
+ try {
28
+ const reportContent = await fs.readFile(reportPath, 'utf-8');
29
+ const report = JSON.parse(reportContent);
30
+
31
+ console.log(chalk.bold('\nšŸ“‹ Rigour Report Explanation\n'));
32
+ console.log(chalk.bold('Status: ') + (report.status === 'PASS'
33
+ ? chalk.green.bold('āœ… PASS')
34
+ : chalk.red.bold('šŸ›‘ FAIL')));
35
+
36
+ console.log(chalk.bold('\nGate Summary:'));
37
+ for (const [gate, status] of Object.entries(report.summary || {})) {
38
+ const icon = status === 'PASS' ? 'āœ…' : status === 'FAIL' ? 'āŒ' : 'ā­ļø';
39
+ console.log(` ${icon} ${gate}: ${status}`);
40
+ }
41
+
42
+ if (report.failures && report.failures.length > 0) {
43
+ console.log(chalk.bold.red(`\nšŸ”§ ${report.failures.length} Violation(s) to Fix:\n`));
44
+
45
+ report.failures.forEach((failure: any, index: number) => {
46
+ console.log(chalk.white(`${index + 1}. `) + chalk.bold.yellow(`[${failure.id.toUpperCase()}]`) + chalk.white(` ${failure.title}`));
47
+ console.log(chalk.dim(` └─ ${failure.details}`));
48
+ if (failure.files && failure.files.length > 0) {
49
+ console.log(chalk.cyan(` šŸ“ Files: ${failure.files.join(', ')}`));
50
+ }
51
+ if (failure.hint) {
52
+ console.log(chalk.green(` šŸ’” Hint: ${failure.hint}`));
53
+ }
54
+ console.log('');
55
+ });
56
+ } else if (report.status === 'PASS') {
57
+ console.log(chalk.green('\n✨ All quality gates passed! No violations found.\n'));
58
+ }
59
+
60
+ if (report.stats) {
61
+ console.log(chalk.dim(`Duration: ${report.stats.duration_ms}ms`));
62
+ }
63
+
64
+ } catch (error: any) {
65
+ console.error(chalk.red(`Error reading report: ${error.message}`));
66
+ process.exit(3);
67
+ }
68
+ }
@@ -0,0 +1,21 @@
1
+ import chalk from 'chalk';
2
+
3
+ export async function guideCommand() {
4
+ console.log(chalk.bold.cyan('\nšŸ›”ļø Rigour Labs | The Engineering Guide\n'));
5
+
6
+ console.log(chalk.bold('Getting Started:'));
7
+ console.log(chalk.dim(' 1. Run ') + chalk.cyan('rigour init') + chalk.dim(' to detect your project role and apply standards.'));
8
+ console.log(chalk.dim(' 2. Run ') + chalk.cyan('rigour check') + chalk.dim(' to see existing violations.'));
9
+ console.log(chalk.dim(' 3. Run ') + chalk.cyan('rigour run -- <your-agent-command>') + chalk.dim(' to automate the fix loop.\n'));
10
+
11
+ console.log(chalk.bold('Key Concepts:'));
12
+ console.log(chalk.yellow(' • Fix Packet v2') + chalk.dim(': Structured diagnostics fed directly into AI agents.'));
13
+ console.log(chalk.yellow(' • Safety Rails') + chalk.dim(': Prevents "explosive" refactoring (max files changed).'));
14
+ console.log(chalk.yellow(' • Strategic Guardians') + chalk.dim(': Dependency and Architectural boundary enforcement.\n'));
15
+
16
+ console.log(chalk.bold('Workflow Integration:'));
17
+ console.log(chalk.green(' • Cursor') + chalk.dim(': Add the MCP server or use the ') + chalk.cyan('.cursor/rules/rigour.mdc') + chalk.dim(' handshake.'));
18
+ console.log(chalk.green(' • CI/CD') + chalk.dim(': Use ') + chalk.cyan('rigour check --ci') + chalk.dim(' to fail PRs that violate quality gates.\n'));
19
+
20
+ console.log(chalk.dim('For more detailed docs, visit: ') + chalk.underline('https://github.com/erashu212/rigour/docs\n'));
21
+ }
@@ -4,9 +4,62 @@ import chalk from 'chalk';
4
4
  import yaml from 'yaml';
5
5
  import { DiscoveryService } from '@rigour-labs/core';
6
6
 
7
- export async function initCommand(cwd: string) {
7
+ export interface InitOptions {
8
+ preset?: string;
9
+ paradigm?: string;
10
+ dryRun?: boolean;
11
+ explain?: boolean;
12
+ }
13
+
14
+ export async function initCommand(cwd: string, options: InitOptions = {}) {
8
15
  const discovery = new DiscoveryService();
9
- const recommendedConfig = await discovery.discover(cwd);
16
+ const result = await discovery.discover(cwd);
17
+ let recommendedConfig = result.config;
18
+
19
+ // Override with user options if provided and re-apply template logic if necessary
20
+ if (options.preset || options.paradigm) {
21
+ const core = await import('@rigour-labs/core');
22
+
23
+ let customBase = { ...core.UNIVERSAL_CONFIG };
24
+
25
+ if (options.preset) {
26
+ const t = core.TEMPLATES.find((t: any) => t.name === options.preset);
27
+ if (t) customBase = (discovery as any).mergeConfig(customBase, t.config);
28
+ } else if (recommendedConfig.preset) {
29
+ const t = core.TEMPLATES.find((t: any) => t.name === recommendedConfig.preset);
30
+ if (t) customBase = (discovery as any).mergeConfig(customBase, t.config);
31
+ }
32
+
33
+ if (options.paradigm) {
34
+ const t = core.PARADIGM_TEMPLATES.find((t: any) => t.name === options.paradigm);
35
+ if (t) customBase = (discovery as any).mergeConfig(customBase, t.config);
36
+ } else if (recommendedConfig.paradigm) {
37
+ const t = core.PARADIGM_TEMPLATES.find((t: any) => t.name === recommendedConfig.paradigm);
38
+ if (t) customBase = (discovery as any).mergeConfig(customBase, t.config);
39
+ }
40
+
41
+ recommendedConfig = customBase;
42
+ if (options.preset) recommendedConfig.preset = options.preset;
43
+ if (options.paradigm) recommendedConfig.paradigm = options.paradigm;
44
+ }
45
+
46
+ if (options.dryRun || options.explain) {
47
+ console.log(chalk.bold.blue('\nšŸ” Rigour Auto-Discovery (Dry Run):'));
48
+ if (recommendedConfig.preset) {
49
+ console.log(chalk.cyan(` Role: `) + chalk.bold(recommendedConfig.preset.toUpperCase()));
50
+ if (options.explain && result.matches.preset) {
51
+ console.log(chalk.dim(` (Marker found: ${result.matches.preset.marker})`));
52
+ }
53
+ }
54
+ if (recommendedConfig.paradigm) {
55
+ console.log(chalk.cyan(` Paradigm: `) + chalk.bold(recommendedConfig.paradigm.toUpperCase()));
56
+ if (options.explain && result.matches.paradigm) {
57
+ console.log(chalk.dim(` (Marker found: ${result.matches.paradigm.marker})`));
58
+ }
59
+ }
60
+ console.log(chalk.yellow('\n[DRY RUN] No files will be written.'));
61
+ return;
62
+ }
10
63
 
11
64
  const configPath = path.join(cwd, 'rigour.yml');
12
65
 
@@ -15,6 +68,15 @@ export async function initCommand(cwd: string) {
15
68
  return;
16
69
  }
17
70
 
71
+ console.log(chalk.bold.blue('\nšŸ” Rigour Auto-Discovery:'));
72
+ if (recommendedConfig.preset) {
73
+ console.log(chalk.cyan(` Role: `) + chalk.bold(recommendedConfig.preset.toUpperCase()));
74
+ }
75
+ if (recommendedConfig.paradigm) {
76
+ console.log(chalk.cyan(` Paradigm: `) + chalk.bold(recommendedConfig.paradigm.toUpperCase()));
77
+ }
78
+ console.log('');
79
+
18
80
  await fs.writeFile(configPath, yaml.stringify(recommendedConfig));
19
81
  console.log(chalk.green('āœ” Created rigour.yml'));
20
82
 
@@ -28,36 +90,56 @@ export async function initCommand(cwd: string) {
28
90
  }
29
91
  }
30
92
 
31
- // Agent Handshake (Cursor/AntiGravity)
32
- const cursorRulesDir = path.join(cwd, '.cursor', 'rules');
33
- await fs.ensureDir(cursorRulesDir);
34
- const rulePath = path.join(cursorRulesDir, 'rigour.mdc');
93
+ // Agent Handshake (Universal / AntiGravity / Cursor)
94
+ const rigourDocsDir = path.join(cwd, 'docs');
95
+ await fs.ensureDir(rigourDocsDir);
96
+ const instructionsPath = path.join(rigourDocsDir, 'AGENT_INSTRUCTIONS.md');
35
97
 
36
- const ruleContent = `---
37
- description: Enforcement of Rigour quality gates and best practices.
38
- globs: **/*
39
- ---
98
+ const ruleContent = `# šŸ›”ļø Rigour: Engineering Excellence Protocol
99
+
100
+ You are an Elite Software Engineer. You do not just write code that "works"; you write code that is **modular, maintainable, and rigorously verified.**
101
+
102
+ ## 🚦 The Rigour Loop (Mandatory)
103
+ Before claiming "Done" for any task, you MUST follow this loop:
40
104
 
41
- # Rigour Enforcement
105
+ 1. **Check**: Run \`npx @rigour-labs/cli check\` to verify compliance.
106
+ 2. **Analyze**: If it fails, read \`rigour-fix-packet.json\` (V2 High-Fidelity) for exact failure points and constraints.
107
+ 3. **Refactor**: Apply **SOLID** and **DRY** principles to resolve the violations according to constraints.
108
+ 4. **Repeat**: Continue until \`npx @rigour-labs/cli check\` returns **PASS**.
42
109
 
43
- You are operating under Rigour engineering discipline.
110
+ ## 🧩 Engineering Standards
111
+ - **Single Responsibility**: Keep files small and focused (max 500 lines).
112
+ - **DRY (Don't Repeat Yourself)**: Extract common logic into utilities.
113
+ - **Done is Done**: No \`TODO\` or \`FIXME\` comments allowed in the final state.
114
+ - **Memory Preservation**: Always update docs/SPEC.md, docs/ARCH.md, docs/DECISIONS.md.
44
115
 
45
- ## Core Rules
46
- - **Never claim done** until you run \`rigour check\` and it returns PASS.
47
- - If checks FAIL, fix **only** the listed failures. Do not add new features or refactor unrelated code.
48
- - Maintain project memory in \`docs/SPEC.md\`, \`docs/ARCH.md\`, and \`docs/DECISIONS.md\`.
49
- - Keep files modular. If a file exceeds 500 lines, you MUST break it into smaller components.
50
- - No \`TODO\` or \`FIXME\` comments allowed in the final submission.
116
+ ## šŸ› ļø Commands
117
+ \`\`\`bash
118
+ # Verify current state
119
+ npx @rigour-labs/cli check
51
120
 
52
- ## Workflow
53
- 1. Write/Modify code.
54
- 2. Run \`rigour check\`.
55
- 3. If FAIL: Read \`rigour-report.json\` for exact failure points and fix them.
56
- 4. If PASS: You may claim task completion.
121
+ # Self-healing agent loop
122
+ npx @rigour-labs/cli run -- <agent-command>
123
+ \`\`\`
57
124
  `;
58
125
 
59
- await fs.writeFile(rulePath, ruleContent);
60
- console.log(chalk.green('āœ” Initialized Agent Handshake (.cursor/rules/rigour.mdc)'));
126
+ // 1. Create Universal Instructions
127
+ await fs.writeFile(instructionsPath, ruleContent);
128
+ console.log(chalk.green('āœ” Initialized Universal Agent Handshake (docs/AGENT_INSTRUCTIONS.md)'));
129
+
130
+ // 2. Create Cursor Specific Rules (.mdc)
131
+ const cursorRulesDir = path.join(cwd, '.cursor', 'rules');
132
+ await fs.ensureDir(cursorRulesDir);
133
+ const mdcPath = path.join(cursorRulesDir, 'rigour.mdc');
134
+ const mdcContent = `---
135
+ description: Enforcement of Rigour quality gates and best practices.
136
+ globs: **/*
137
+ ---
138
+
139
+ ${ruleContent}`;
140
+
141
+ await fs.writeFile(mdcPath, mdcContent);
142
+ console.log(chalk.green('āœ” Initialized Cursor Handshake (.cursor/rules/rigour.mdc)'));
61
143
 
62
- console.log(chalk.blue('\nRigour is ready. Run `rigour check` to verify your project.'));
144
+ console.log(chalk.blue('\nRigour is ready. Run `npx @rigour-labs/cli check` to verify your project.'));
63
145
  }