@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.
- package/LICENSE +1 -1
- package/dist/cli.js +70 -8
- package/dist/commands/check.d.ts +5 -1
- package/dist/commands/check.js +78 -31
- package/dist/commands/explain.d.ts +1 -0
- package/dist/commands/explain.js +67 -0
- package/dist/commands/guide.d.ts +1 -0
- package/dist/commands/guide.js +22 -0
- package/dist/commands/init.d.ts +7 -1
- package/dist/commands/init.js +99 -25
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.js +63 -19
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +28 -0
- package/package.json +3 -3
- package/src/cli.ts +71 -9
- package/src/commands/check.ts +84 -31
- package/src/commands/explain.ts +68 -0
- package/src/commands/guide.ts +21 -0
- package/src/commands/init.ts +108 -26
- package/src/commands/run.ts +71 -19
- package/src/commands/setup.ts +28 -0
package/src/commands/run.ts
CHANGED
|
@@ -5,12 +5,18 @@ import yaml from 'yaml';
|
|
|
5
5
|
import { execa } from 'execa';
|
|
6
6
|
import { GateRunner, ConfigSchema } from '@rigour-labs/core';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// Exit codes per spec
|
|
9
|
+
const EXIT_PASS = 0;
|
|
10
|
+
const EXIT_FAIL = 1;
|
|
11
|
+
const EXIT_CONFIG_ERROR = 2;
|
|
12
|
+
const EXIT_INTERNAL_ERROR = 3;
|
|
13
|
+
|
|
14
|
+
export async function runLoop(cwd: string, agentArgs: string[], options: { iterations: number, failFast?: boolean }) {
|
|
9
15
|
const configPath = path.join(cwd, 'rigour.yml');
|
|
10
16
|
|
|
11
17
|
if (!(await fs.pathExists(configPath))) {
|
|
12
18
|
console.error(chalk.red('Error: rigour.yml not found. Run `rigour init` first.'));
|
|
13
|
-
process.exit(
|
|
19
|
+
process.exit(EXIT_CONFIG_ERROR);
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
try {
|
|
@@ -28,52 +34,98 @@ export async function runLoop(cwd: string, agentArgs: string[], options: { itera
|
|
|
28
34
|
console.log(chalk.bold.blue(` RIGOUR LOOP: Iteration ${iteration}/${maxIterations}`));
|
|
29
35
|
console.log(chalk.bold.blue(`══════════════════════════════════════════════════════════════════`));
|
|
30
36
|
|
|
31
|
-
// 1.
|
|
32
|
-
|
|
37
|
+
// 1. Prepare Command
|
|
38
|
+
let currentArgs = [...agentArgs];
|
|
39
|
+
if (iteration > 1 && agentArgs.length > 0) {
|
|
40
|
+
// Iteration contract: In later cycles, we focus strictly on the fix packet
|
|
41
|
+
console.log(chalk.yellow(`\n🔄 REFINEMENT CYCLE - Instructing agent to fix specific violations...`));
|
|
42
|
+
// We keep the first part of the command (the agent) but can append or wrap
|
|
43
|
+
// For simplicity, we assume the agent can read the JSON file we generate
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Snapshot changed files before agent runs
|
|
47
|
+
let beforeFiles: string[] = [];
|
|
48
|
+
try {
|
|
49
|
+
const { stdout } = await execa('git', ['status', '--porcelain'], { cwd });
|
|
50
|
+
beforeFiles = stdout.split('\n').filter(l => l.trim()).map(l => l.slice(3).trim());
|
|
51
|
+
} catch (e) { }
|
|
52
|
+
|
|
53
|
+
// 2. Run the agent command
|
|
54
|
+
if (currentArgs.length > 0) {
|
|
33
55
|
console.log(chalk.cyan(`\n🚀 DEPLOYING AGENT:`));
|
|
34
|
-
console.log(chalk.dim(` Command: ${
|
|
56
|
+
console.log(chalk.dim(` Command: ${currentArgs.join(' ')}`));
|
|
35
57
|
try {
|
|
36
|
-
await execa(
|
|
58
|
+
await execa(currentArgs[0], currentArgs.slice(1), { shell: true, stdio: 'inherit', cwd });
|
|
37
59
|
} catch (error: any) {
|
|
38
60
|
console.warn(chalk.yellow(`\n⚠️ Agent command finished with non-zero exit code. Rigour will now verify state...`));
|
|
39
61
|
}
|
|
40
62
|
}
|
|
41
63
|
|
|
42
|
-
//
|
|
64
|
+
// Snapshot changed files after agent runs
|
|
65
|
+
let afterFiles: string[] = [];
|
|
66
|
+
try {
|
|
67
|
+
const { stdout } = await execa('git', ['status', '--porcelain'], { cwd });
|
|
68
|
+
afterFiles = stdout.split('\n').filter(l => l.trim()).map(l => l.slice(3).trim());
|
|
69
|
+
} catch (e) { }
|
|
70
|
+
|
|
71
|
+
const changedThisCycle = afterFiles.filter(f => !beforeFiles.includes(f));
|
|
72
|
+
const maxFiles = config.gates.safety?.max_files_changed_per_cycle || 10;
|
|
73
|
+
|
|
74
|
+
if (changedThisCycle.length > maxFiles) {
|
|
75
|
+
console.log(chalk.red.bold(`\n🛑 SAFETY RAIL ABORT: Agent changed ${changedThisCycle.length} files (max: ${maxFiles}).`));
|
|
76
|
+
console.log(chalk.red(` This looks like explosive behavior. Check your agent's instructions.`));
|
|
77
|
+
process.exit(EXIT_FAIL);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 3. Run Rigour Check
|
|
43
81
|
console.log(chalk.magenta('\n🔍 AUDITING QUALITY GATES...'));
|
|
44
82
|
const report = await runner.run(cwd);
|
|
45
83
|
|
|
84
|
+
// Write report
|
|
85
|
+
const reportPath = path.join(cwd, config.output.report_path);
|
|
86
|
+
await fs.writeJson(reportPath, report, { spaces: 2 });
|
|
87
|
+
|
|
46
88
|
if (report.status === 'PASS') {
|
|
47
89
|
console.log(chalk.green.bold('\n✨ PASS - All quality gates satisfied.'));
|
|
48
90
|
console.log(chalk.green(` Your solution meets the required Engineering Rigour criteria.\n`));
|
|
49
91
|
return;
|
|
50
92
|
}
|
|
51
93
|
|
|
52
|
-
//
|
|
94
|
+
// 4. Generate Fix Packet v2
|
|
95
|
+
const { FixPacketService } = await import('@rigour-labs/core');
|
|
96
|
+
const fixPacketService = new FixPacketService();
|
|
97
|
+
const fixPacket = fixPacketService.generate(report, config);
|
|
98
|
+
const fixPacketPath = path.join(cwd, 'rigour-fix-packet.json');
|
|
99
|
+
await fs.writeJson(fixPacketPath, fixPacket, { spaces: 2 });
|
|
100
|
+
|
|
53
101
|
console.log(chalk.red.bold(`\n🛑 FAIL - Found ${report.failures.length} engineering violations.`));
|
|
102
|
+
console.log(chalk.dim(` Fix Packet generated: rigour-fix-packet.json`));
|
|
54
103
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return msg;
|
|
60
|
-
}).join('\n\n');
|
|
104
|
+
if (options.failFast) {
|
|
105
|
+
console.log(chalk.red.bold(`\n🛑 FAIL-FAST: Aborting loop as requested.`));
|
|
106
|
+
process.exit(EXIT_FAIL);
|
|
107
|
+
}
|
|
61
108
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
109
|
+
// Print summary
|
|
110
|
+
const summary = report.failures.map((f, i) => {
|
|
111
|
+
return chalk.white(`${i + 1}. `) + chalk.bold.red(`[${f.id.toUpperCase()}] `) + chalk.white(f.title);
|
|
112
|
+
}).join('\n');
|
|
113
|
+
console.log(chalk.bold.white('\n📋 VIOLATIONS SUMMARY:'));
|
|
114
|
+
console.log(summary);
|
|
65
115
|
|
|
66
116
|
if (iteration === maxIterations) {
|
|
67
117
|
console.log(chalk.red.bold(`\n❌ CRITICAL: Reached maximum iterations (${maxIterations}).`));
|
|
68
118
|
console.log(chalk.red(` Quality gates remain unfulfilled. Refactor manually or check agent logs.`));
|
|
69
|
-
process.exit(
|
|
119
|
+
process.exit(EXIT_FAIL);
|
|
70
120
|
}
|
|
121
|
+
|
|
122
|
+
console.log(chalk.dim('\nReturning control to agent for the next refinement cycle...'));
|
|
71
123
|
}
|
|
72
124
|
} catch (error: any) {
|
|
73
125
|
console.error(chalk.red(`\n❌ FATAL ERROR: ${error.message}`));
|
|
74
126
|
if (error.issues) {
|
|
75
127
|
console.error(chalk.dim(JSON.stringify(error.issues, null, 2)));
|
|
76
128
|
}
|
|
77
|
-
process.exit(
|
|
129
|
+
process.exit(EXIT_INTERNAL_ERROR);
|
|
78
130
|
}
|
|
79
131
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export async function setupCommand() {
|
|
4
|
+
console.log(chalk.bold.cyan('\n🛠️ Rigour Labs | Setup & Installation\n'));
|
|
5
|
+
|
|
6
|
+
console.log(chalk.bold('1. Global Installation (Recommended)'));
|
|
7
|
+
console.log(chalk.dim(' To use Rigour anywhere in your terminal:'));
|
|
8
|
+
console.log(chalk.green(' $ npm install -g @rigour-labs/cli\n'));
|
|
9
|
+
|
|
10
|
+
console.log(chalk.bold('2. Project-Local installation'));
|
|
11
|
+
console.log(chalk.dim(' To keep Rigour versioned with your project:'));
|
|
12
|
+
console.log(chalk.green(' $ npm install --save-dev @rigour-labs/cli\n'));
|
|
13
|
+
|
|
14
|
+
console.log(chalk.bold('3. Standalone Binaries (Zero-Install)'));
|
|
15
|
+
console.log(chalk.dim(' If you do not want to use Node.js:'));
|
|
16
|
+
console.log(chalk.dim(' • macOS: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-macos'));
|
|
17
|
+
console.log(chalk.dim(' • Linux: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-linux'));
|
|
18
|
+
console.log(chalk.dim(' • Windows: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-windows.exe\n'));
|
|
19
|
+
|
|
20
|
+
console.log(chalk.bold('4. MCP Integration (for AI Agents)'));
|
|
21
|
+
console.log(chalk.dim(' To let Cursor or Claude use Rigour natively:'));
|
|
22
|
+
console.log(chalk.dim(' Path to MCP: ') + chalk.cyan('packages/rigour-mcp/dist/index.js'));
|
|
23
|
+
console.log(chalk.dim(' Add this to your Cursor/Claude settings.\n'));
|
|
24
|
+
|
|
25
|
+
console.log(chalk.bold('Update Guidance:'));
|
|
26
|
+
console.log(chalk.dim(' Keep Rigour sharp by updating regularly:'));
|
|
27
|
+
console.log(chalk.green(' $ npm install -g @rigour-labs/cli@latest\n'));
|
|
28
|
+
}
|