@rigour-labs/cli 2.9.4 ā 2.11.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/dist/cli.js +20 -21
- package/dist/commands/check.js +77 -50
- package/dist/commands/constants.js +4 -7
- package/dist/commands/explain.js +30 -36
- package/dist/commands/guide.js +15 -21
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +88 -0
- package/dist/commands/init.js +142 -105
- package/dist/commands/run.js +42 -48
- package/dist/commands/setup.js +21 -27
- package/dist/commands/studio.d.ts +2 -0
- package/dist/commands/studio.js +272 -0
- package/dist/init-rules.test.js +34 -34
- package/dist/smoke.test.js +35 -34
- package/package.json +4 -2
- package/src/cli.ts +5 -0
- package/src/commands/check.ts +36 -0
- package/src/commands/index.ts +105 -0
- package/src/commands/init.ts +64 -17
- package/src/commands/studio.ts +273 -0
- package/src/init-rules.test.ts +10 -2
- package/src/smoke.test.ts +10 -2
- package/src/templates/handshake.mdc +23 -26
- package/vitest.config.ts +10 -0
- package/vitest.setup.ts +30 -0
package/dist/commands/init.js
CHANGED
|
@@ -1,42 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import yaml from 'yaml';
|
|
5
|
+
import { DiscoveryService } from '@rigour-labs/core';
|
|
6
|
+
import { CODE_QUALITY_RULES, DEBUGGING_RULES, COLLABORATION_RULES, AGNOSTIC_AI_INSTRUCTIONS } from './constants.js';
|
|
7
|
+
import { randomUUID } from 'crypto';
|
|
8
|
+
// Helper to log events for Rigour Studio
|
|
9
|
+
async function logStudioEvent(cwd, event) {
|
|
10
|
+
try {
|
|
11
|
+
const rigourDir = path.join(cwd, ".rigour");
|
|
12
|
+
await fs.ensureDir(rigourDir);
|
|
13
|
+
const eventsPath = path.join(rigourDir, "events.jsonl");
|
|
14
|
+
const logEntry = JSON.stringify({
|
|
15
|
+
id: randomUUID(),
|
|
16
|
+
timestamp: new Date().toISOString(),
|
|
17
|
+
...event
|
|
18
|
+
}) + "\n";
|
|
19
|
+
await fs.appendFile(eventsPath, logEntry);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Silent fail
|
|
23
|
+
}
|
|
24
|
+
}
|
|
13
25
|
function detectIDE(cwd) {
|
|
14
26
|
// Check for Claude Code markers
|
|
15
|
-
if (
|
|
27
|
+
if (fs.existsSync(path.join(cwd, 'CLAUDE.md')) || fs.existsSync(path.join(cwd, '.claude'))) {
|
|
16
28
|
return 'claude';
|
|
17
29
|
}
|
|
18
30
|
// Check for Gemini Code Assist markers
|
|
19
|
-
if (
|
|
31
|
+
if (fs.existsSync(path.join(cwd, '.gemini'))) {
|
|
20
32
|
return 'gemini';
|
|
21
33
|
}
|
|
22
34
|
// Check for Codex/Aider AGENTS.md (universal standard)
|
|
23
|
-
if (
|
|
35
|
+
if (fs.existsSync(path.join(cwd, 'AGENTS.md'))) {
|
|
24
36
|
return 'codex';
|
|
25
37
|
}
|
|
26
38
|
// Check for Windsurf markers
|
|
27
|
-
if (
|
|
39
|
+
if (fs.existsSync(path.join(cwd, '.windsurfrules')) || fs.existsSync(path.join(cwd, '.windsurf'))) {
|
|
28
40
|
return 'windsurf';
|
|
29
41
|
}
|
|
30
42
|
// Check for Cline-specific markers
|
|
31
|
-
if (
|
|
43
|
+
if (fs.existsSync(path.join(cwd, '.clinerules'))) {
|
|
32
44
|
return 'cline';
|
|
33
45
|
}
|
|
34
46
|
// Check for Cursor-specific markers
|
|
35
|
-
if (
|
|
47
|
+
if (fs.existsSync(path.join(cwd, '.cursor'))) {
|
|
36
48
|
return 'cursor';
|
|
37
49
|
}
|
|
38
50
|
// Check for VS Code markers
|
|
39
|
-
if (
|
|
51
|
+
if (fs.existsSync(path.join(cwd, '.vscode'))) {
|
|
40
52
|
return 'vscode';
|
|
41
53
|
}
|
|
42
54
|
// Check environment variables that IDEs/Agents set
|
|
@@ -62,8 +74,8 @@ function detectIDE(cwd) {
|
|
|
62
74
|
}
|
|
63
75
|
return 'unknown';
|
|
64
76
|
}
|
|
65
|
-
async function initCommand(cwd, options = {}) {
|
|
66
|
-
const discovery = new
|
|
77
|
+
export async function initCommand(cwd, options = {}) {
|
|
78
|
+
const discovery = new DiscoveryService();
|
|
67
79
|
const result = await discovery.discover(cwd);
|
|
68
80
|
let recommendedConfig = result.config;
|
|
69
81
|
// Override with user options if provided and re-apply template logic if necessary
|
|
@@ -97,33 +109,40 @@ async function initCommand(cwd, options = {}) {
|
|
|
97
109
|
recommendedConfig.paradigm = options.paradigm;
|
|
98
110
|
}
|
|
99
111
|
if (options.dryRun || options.explain) {
|
|
100
|
-
console.log(
|
|
112
|
+
console.log(chalk.bold.blue('\nš Rigour Auto-Discovery (Dry Run):'));
|
|
101
113
|
if (recommendedConfig.preset) {
|
|
102
|
-
console.log(
|
|
114
|
+
console.log(chalk.cyan(` Role: `) + chalk.bold(recommendedConfig.preset.toUpperCase()));
|
|
103
115
|
if (options.explain && result.matches.preset) {
|
|
104
|
-
console.log(
|
|
116
|
+
console.log(chalk.dim(` (Marker found: ${result.matches.preset.marker})`));
|
|
105
117
|
}
|
|
106
118
|
}
|
|
107
119
|
if (recommendedConfig.paradigm) {
|
|
108
|
-
console.log(
|
|
120
|
+
console.log(chalk.cyan(` Paradigm: `) + chalk.bold(recommendedConfig.paradigm.toUpperCase()));
|
|
109
121
|
if (options.explain && result.matches.paradigm) {
|
|
110
|
-
console.log(
|
|
122
|
+
console.log(chalk.dim(` (Marker found: ${result.matches.paradigm.marker})`));
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
|
-
console.log(
|
|
125
|
+
console.log(chalk.yellow('\n[DRY RUN] No files will be written.'));
|
|
114
126
|
return;
|
|
115
127
|
}
|
|
116
|
-
const configPath =
|
|
117
|
-
if (await
|
|
118
|
-
console.log(
|
|
128
|
+
const configPath = path.join(cwd, 'rigour.yml');
|
|
129
|
+
if (await fs.pathExists(configPath)) {
|
|
130
|
+
console.log(chalk.yellow('rigour.yml already exists. Skipping initialization.'));
|
|
119
131
|
return;
|
|
120
132
|
}
|
|
121
|
-
console.log(
|
|
133
|
+
console.log(chalk.bold.blue('\nš Rigour Auto-Discovery:'));
|
|
134
|
+
const requestId = randomUUID();
|
|
135
|
+
await logStudioEvent(cwd, {
|
|
136
|
+
type: "tool_call",
|
|
137
|
+
requestId,
|
|
138
|
+
tool: "rigour_init",
|
|
139
|
+
arguments: options
|
|
140
|
+
});
|
|
122
141
|
if (recommendedConfig.preset) {
|
|
123
|
-
console.log(
|
|
142
|
+
console.log(chalk.cyan(` Role: `) + chalk.bold(recommendedConfig.preset.toUpperCase()));
|
|
124
143
|
}
|
|
125
144
|
if (recommendedConfig.paradigm) {
|
|
126
|
-
console.log(
|
|
145
|
+
console.log(chalk.cyan(` Paradigm: `) + chalk.bold(recommendedConfig.paradigm.toUpperCase()));
|
|
127
146
|
}
|
|
128
147
|
console.log('');
|
|
129
148
|
const yamlHeader = `# ā ļø TEAM STANDARD - DO NOT MODIFY WITHOUT TEAM APPROVAL
|
|
@@ -132,90 +151,86 @@ async function initCommand(cwd, options = {}) {
|
|
|
132
151
|
# See: docs/AGENT_INSTRUCTIONS.md for the correct workflow.
|
|
133
152
|
|
|
134
153
|
`;
|
|
135
|
-
await
|
|
136
|
-
console.log(
|
|
154
|
+
await fs.writeFile(configPath, yamlHeader + yaml.stringify(recommendedConfig));
|
|
155
|
+
console.log(chalk.green('ā Created rigour.yml'));
|
|
137
156
|
// Create required directories and files
|
|
138
157
|
const requireddocs = recommendedConfig.gates.required_files || [];
|
|
139
158
|
for (const file of requireddocs) {
|
|
140
|
-
const filePath =
|
|
141
|
-
if (!(await
|
|
142
|
-
await
|
|
143
|
-
|
|
159
|
+
const filePath = path.join(cwd, file);
|
|
160
|
+
if (!(await fs.pathExists(filePath))) {
|
|
161
|
+
await fs.ensureDir(path.dirname(filePath)); // Ensure parent directory exists
|
|
162
|
+
await fs.ensureFile(filePath);
|
|
163
|
+
console.log(chalk.dim(` - Created ${file}`));
|
|
144
164
|
}
|
|
145
165
|
}
|
|
146
166
|
// Agent Handshake (Universal / AntiGravity / Cursor)
|
|
147
|
-
const rigourDocsDir =
|
|
148
|
-
await
|
|
149
|
-
const instructionsPath =
|
|
150
|
-
const ruleContent = `# š”ļø Rigour: Engineering
|
|
151
|
-
|
|
152
|
-
You are an Elite Software Engineer. You do not just write code that "works"; you write code that is **modular, maintainable, and rigorously verified.**
|
|
153
|
-
|
|
154
|
-
## š¦ The Rigour Loop (Mandatory)
|
|
155
|
-
Before claiming "Done" for any task, you MUST follow this loop:
|
|
167
|
+
const rigourDocsDir = path.join(cwd, 'docs');
|
|
168
|
+
await fs.ensureDir(rigourDocsDir);
|
|
169
|
+
const instructionsPath = path.join(rigourDocsDir, 'AGENT_INSTRUCTIONS.md');
|
|
170
|
+
const ruleContent = `# š”ļø Rigour: Mandatory Engineering Governance Protocol
|
|
156
171
|
|
|
157
|
-
|
|
158
|
-
2. **Analyze**: If it fails, read \`rigour-fix-packet.json\` (V2 High-Fidelity) for exact failure points and constraints.
|
|
159
|
-
3. **Refactor**: Apply **SOLID** and **DRY** principles to resolve the violations according to constraints.
|
|
160
|
-
4. **Repeat**: Continue until \`npx @rigour-labs/cli check\` returns **PASS**.
|
|
172
|
+
**You are an AI Engineering Agent governed by Rigour.**
|
|
161
173
|
|
|
162
|
-
|
|
163
|
-
\`\`\`bash
|
|
164
|
-
# Verify current state
|
|
165
|
-
npx @rigour-labs/cli check
|
|
174
|
+
Your access to this codebase is conditional upon your strict adherence to the **Rigour Governance Protocol**. This is an automated requirement for every engineering task.
|
|
166
175
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
\`\`\`
|
|
176
|
+
## š¦ The Mandatory Governance Loop
|
|
177
|
+
You MUST execute this loop for every task. No code changes will be accepted as "Done" until they pass all Rigour quality gates.
|
|
170
178
|
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
1. **Context Loading**: Call \`rigour_recall\` (MCP) to align with project-specific engineering memory.
|
|
180
|
+
2. **Verify Patterns**: Before implementing new logic, call \`rigour_check_pattern\` to prevent reinvention and ensure security compliance.
|
|
181
|
+
3. **Audit Enforcement**: Before finishing, you MUST call \`npx @rigour-labs/cli check\`.
|
|
182
|
+
4. **Failure Remediation**: If the check returns **FAIL**, you MUST implement all required engineering refinements.
|
|
183
|
+
5. **PASS or REJECT**: You may only declare a task complete when the check returns **PASS**.
|
|
173
184
|
|
|
174
|
-
|
|
185
|
+
## āļø Transparency & Accountability
|
|
186
|
+
**Every action, tool call, and logic shift you perform is automatically logged to the project's local audit trail.** This data is visible in real-time in the human-monitored **Rigour Studio**.
|
|
175
187
|
|
|
176
|
-
${
|
|
188
|
+
${AGNOSTIC_AI_INSTRUCTIONS}
|
|
189
|
+
${CODE_QUALITY_RULES}
|
|
190
|
+
${DEBUGGING_RULES}
|
|
191
|
+
${COLLABORATION_RULES}
|
|
177
192
|
`;
|
|
178
193
|
// 1. Create Universal Instructions
|
|
179
|
-
if (!(await
|
|
180
|
-
await
|
|
181
|
-
console.log(
|
|
194
|
+
if (!(await fs.pathExists(instructionsPath))) {
|
|
195
|
+
await fs.writeFile(instructionsPath, ruleContent);
|
|
196
|
+
console.log(chalk.green('ā Initialized Universal Agent Handshake (docs/AGENT_INSTRUCTIONS.md)'));
|
|
182
197
|
}
|
|
183
198
|
// 2. Create IDE-Specific Rules based on detection or user preference
|
|
184
199
|
const detectedIDE = detectIDE(cwd);
|
|
185
200
|
const targetIDE = options.ide || (detectedIDE !== 'unknown' ? detectedIDE : 'all');
|
|
186
201
|
if (detectedIDE !== 'unknown' && !options.ide) {
|
|
187
|
-
console.log(
|
|
202
|
+
console.log(chalk.dim(` (Auto-detected IDE: ${detectedIDE})`));
|
|
188
203
|
}
|
|
189
204
|
if (targetIDE === 'cursor' || targetIDE === 'all') {
|
|
190
|
-
const cursorRulesDir =
|
|
191
|
-
await
|
|
192
|
-
const mdcPath =
|
|
205
|
+
const cursorRulesDir = path.join(cwd, '.cursor', 'rules');
|
|
206
|
+
await fs.ensureDir(cursorRulesDir);
|
|
207
|
+
const mdcPath = path.join(cursorRulesDir, 'rigour.mdc');
|
|
193
208
|
const mdcContent = `---
|
|
194
209
|
description: Enforcement of Rigour quality gates and best practices.
|
|
195
210
|
globs: **/*
|
|
196
211
|
---
|
|
197
212
|
|
|
198
213
|
${ruleContent}`;
|
|
199
|
-
if (!(await
|
|
200
|
-
await
|
|
201
|
-
console.log(
|
|
214
|
+
if (!(await fs.pathExists(mdcPath))) {
|
|
215
|
+
await fs.writeFile(mdcPath, mdcContent);
|
|
216
|
+
console.log(chalk.green('ā Initialized Cursor Handshake (.cursor/rules/rigour.mdc)'));
|
|
202
217
|
}
|
|
203
218
|
}
|
|
204
219
|
if (targetIDE === 'vscode' || targetIDE === 'all') {
|
|
205
220
|
// VS Code users use the universal AGENT_INSTRUCTIONS.md (already created above)
|
|
206
221
|
// We could also add .vscode/settings.json or snippets here if needed
|
|
207
|
-
console.log(
|
|
222
|
+
console.log(chalk.green('ā VS Code mode - using Universal Handshake (docs/AGENT_INSTRUCTIONS.md)'));
|
|
208
223
|
}
|
|
209
224
|
if (targetIDE === 'cline' || targetIDE === 'all') {
|
|
210
|
-
const clineRulesPath =
|
|
211
|
-
if (!(await
|
|
212
|
-
await
|
|
213
|
-
console.log(
|
|
225
|
+
const clineRulesPath = path.join(cwd, '.clinerules');
|
|
226
|
+
if (!(await fs.pathExists(clineRulesPath))) {
|
|
227
|
+
await fs.writeFile(clineRulesPath, ruleContent);
|
|
228
|
+
console.log(chalk.green('ā Initialized Cline Handshake (.clinerules)'));
|
|
214
229
|
}
|
|
215
230
|
}
|
|
216
231
|
// Claude Code (CLAUDE.md)
|
|
217
232
|
if (targetIDE === 'claude' || targetIDE === 'all') {
|
|
218
|
-
const claudePath =
|
|
233
|
+
const claudePath = path.join(cwd, 'CLAUDE.md');
|
|
219
234
|
const claudeContent = `# CLAUDE.md - Project Instructions for Claude Code
|
|
220
235
|
|
|
221
236
|
This file provides Claude Code with context about this project.
|
|
@@ -238,16 +253,16 @@ npx @rigour-labs/cli run -- claude "<task>"
|
|
|
238
253
|
\`\`\`
|
|
239
254
|
|
|
240
255
|
${ruleContent}`;
|
|
241
|
-
if (!(await
|
|
242
|
-
await
|
|
243
|
-
console.log(
|
|
256
|
+
if (!(await fs.pathExists(claudePath))) {
|
|
257
|
+
await fs.writeFile(claudePath, claudeContent);
|
|
258
|
+
console.log(chalk.green('ā Initialized Claude Code Handshake (CLAUDE.md)'));
|
|
244
259
|
}
|
|
245
260
|
}
|
|
246
261
|
// Gemini Code Assist (.gemini/styleguide.md)
|
|
247
262
|
if (targetIDE === 'gemini' || targetIDE === 'all') {
|
|
248
|
-
const geminiDir =
|
|
249
|
-
await
|
|
250
|
-
const geminiStylePath =
|
|
263
|
+
const geminiDir = path.join(cwd, '.gemini');
|
|
264
|
+
await fs.ensureDir(geminiDir);
|
|
265
|
+
const geminiStylePath = path.join(geminiDir, 'styleguide.md');
|
|
251
266
|
const geminiContent = `# Gemini Code Assist Style Guide
|
|
252
267
|
|
|
253
268
|
This project uses Rigour for quality gates.
|
|
@@ -257,14 +272,14 @@ This project uses Rigour for quality gates.
|
|
|
257
272
|
Always run \`npx @rigour-labs/cli check\` before marking any task complete.
|
|
258
273
|
|
|
259
274
|
${ruleContent}`;
|
|
260
|
-
if (!(await
|
|
261
|
-
await
|
|
262
|
-
console.log(
|
|
275
|
+
if (!(await fs.pathExists(geminiStylePath))) {
|
|
276
|
+
await fs.writeFile(geminiStylePath, geminiContent);
|
|
277
|
+
console.log(chalk.green('ā Initialized Gemini Handshake (.gemini/styleguide.md)'));
|
|
263
278
|
}
|
|
264
279
|
}
|
|
265
280
|
// OpenAI Codex / Aider (AGENTS.md - Universal Standard)
|
|
266
281
|
if (targetIDE === 'codex' || targetIDE === 'all') {
|
|
267
|
-
const agentsPath =
|
|
282
|
+
const agentsPath = path.join(cwd, 'AGENTS.md');
|
|
268
283
|
const agentsContent = `# AGENTS.md - Universal AI Agent Instructions
|
|
269
284
|
|
|
270
285
|
This file provides instructions for AI coding agents (Codex, Aider, and others).
|
|
@@ -286,40 +301,62 @@ npx @rigour-labs/cli check
|
|
|
286
301
|
\`\`\`
|
|
287
302
|
|
|
288
303
|
${ruleContent}`;
|
|
289
|
-
if (!(await
|
|
290
|
-
await
|
|
291
|
-
console.log(
|
|
304
|
+
if (!(await fs.pathExists(agentsPath))) {
|
|
305
|
+
await fs.writeFile(agentsPath, agentsContent);
|
|
306
|
+
console.log(chalk.green('ā Initialized Universal Agent Handshake (AGENTS.md)'));
|
|
292
307
|
}
|
|
293
308
|
}
|
|
294
309
|
// Windsurf (.windsurfrules)
|
|
295
310
|
if (targetIDE === 'windsurf' || targetIDE === 'all') {
|
|
296
|
-
const windsurfPath =
|
|
297
|
-
if (!(await
|
|
298
|
-
await
|
|
299
|
-
console.log(
|
|
311
|
+
const windsurfPath = path.join(cwd, '.windsurfrules');
|
|
312
|
+
if (!(await fs.pathExists(windsurfPath))) {
|
|
313
|
+
await fs.writeFile(windsurfPath, ruleContent);
|
|
314
|
+
console.log(chalk.green('ā Initialized Windsurf Handshake (.windsurfrules)'));
|
|
300
315
|
}
|
|
301
316
|
}
|
|
302
317
|
// 3. Update .gitignore
|
|
303
|
-
const gitignorePath =
|
|
318
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
304
319
|
const ignorePatterns = ['rigour-report.json', 'rigour-fix-packet.json', '.rigour/'];
|
|
305
320
|
try {
|
|
306
321
|
let content = '';
|
|
307
|
-
if (await
|
|
308
|
-
content = await
|
|
322
|
+
if (await fs.pathExists(gitignorePath)) {
|
|
323
|
+
content = await fs.readFile(gitignorePath, 'utf-8');
|
|
309
324
|
}
|
|
310
325
|
const toAdd = ignorePatterns.filter(p => !content.includes(p));
|
|
311
326
|
if (toAdd.length > 0) {
|
|
312
327
|
const separator = content.endsWith('\n') ? '' : '\n';
|
|
313
328
|
const newContent = `${content}${separator}\n# Rigour Artifacts\n${toAdd.join('\n')}\n`;
|
|
314
|
-
await
|
|
315
|
-
console.log(
|
|
329
|
+
await fs.writeFile(gitignorePath, newContent);
|
|
330
|
+
console.log(chalk.green('ā Updated .gitignore'));
|
|
316
331
|
}
|
|
317
332
|
}
|
|
318
333
|
catch (e) {
|
|
319
334
|
// Failing to update .gitignore isn't fatal
|
|
320
335
|
}
|
|
321
|
-
console.log(
|
|
322
|
-
console.log(
|
|
323
|
-
|
|
324
|
-
|
|
336
|
+
console.log(chalk.blue('\nRigour is ready. Run `npx @rigour-labs/cli check` to verify your project.'));
|
|
337
|
+
console.log(chalk.cyan('Next Step: ') + chalk.bold('rigour index') + chalk.dim(' (Populate the Pattern Index)'));
|
|
338
|
+
// Bootstrap initial memory for the Studio
|
|
339
|
+
const rigourDir = path.join(cwd, ".rigour");
|
|
340
|
+
await fs.ensureDir(rigourDir);
|
|
341
|
+
const memPath = path.join(rigourDir, "memory.json");
|
|
342
|
+
if (!(await fs.pathExists(memPath))) {
|
|
343
|
+
await fs.writeJson(memPath, {
|
|
344
|
+
memories: {
|
|
345
|
+
"project_boot": {
|
|
346
|
+
value: `Governance initiated via '${options.preset || 'api'}' preset. This project is now monitored by Rigour Studio.`,
|
|
347
|
+
timestamp: new Date().toISOString()
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}, { spaces: 2 });
|
|
351
|
+
}
|
|
352
|
+
console.log(chalk.dim('\nš” Tip: Planning to use a framework like Next.js?'));
|
|
353
|
+
console.log(chalk.dim(' Run its scaffolding tool (e.g., npx create-next-app) BEFORE rigour init,'));
|
|
354
|
+
console.log(chalk.dim(' or move rigour.yml and docs/ aside temporarily to satisfy empty-directory checks.'));
|
|
355
|
+
await logStudioEvent(cwd, {
|
|
356
|
+
type: "tool_response",
|
|
357
|
+
requestId,
|
|
358
|
+
tool: "rigour_init",
|
|
359
|
+
status: "success",
|
|
360
|
+
content: [{ type: "text", text: `Rigour Governance Initialized` }]
|
|
361
|
+
});
|
|
325
362
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -1,49 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const yaml_1 = __importDefault(require("yaml"));
|
|
11
|
-
const execa_1 = require("execa");
|
|
12
|
-
const core_1 = require("@rigour-labs/core");
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import yaml from 'yaml';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
import { GateRunner, ConfigSchema } from '@rigour-labs/core';
|
|
13
7
|
// Exit codes per spec
|
|
14
8
|
const EXIT_PASS = 0;
|
|
15
9
|
const EXIT_FAIL = 1;
|
|
16
10
|
const EXIT_CONFIG_ERROR = 2;
|
|
17
11
|
const EXIT_INTERNAL_ERROR = 3;
|
|
18
|
-
async function runLoop(cwd, agentArgs, options) {
|
|
19
|
-
const configPath =
|
|
20
|
-
if (!(await
|
|
21
|
-
console.error(
|
|
12
|
+
export async function runLoop(cwd, agentArgs, options) {
|
|
13
|
+
const configPath = path.join(cwd, 'rigour.yml');
|
|
14
|
+
if (!(await fs.pathExists(configPath))) {
|
|
15
|
+
console.error(chalk.red('Error: rigour.yml not found. Run `rigour init` first.'));
|
|
22
16
|
process.exit(EXIT_CONFIG_ERROR);
|
|
23
17
|
}
|
|
24
18
|
try {
|
|
25
|
-
const configContent = await
|
|
26
|
-
const rawConfig =
|
|
27
|
-
const config =
|
|
28
|
-
const runner = new
|
|
19
|
+
const configContent = await fs.readFile(configPath, 'utf-8');
|
|
20
|
+
const rawConfig = yaml.parse(configContent);
|
|
21
|
+
const config = ConfigSchema.parse(rawConfig);
|
|
22
|
+
const runner = new GateRunner(config);
|
|
29
23
|
let iteration = 0;
|
|
30
24
|
const maxIterations = options.iterations;
|
|
31
25
|
while (iteration < maxIterations) {
|
|
32
26
|
iteration++;
|
|
33
|
-
console.log(
|
|
34
|
-
console.log(
|
|
35
|
-
console.log(
|
|
27
|
+
console.log(chalk.bold.blue(`\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`));
|
|
28
|
+
console.log(chalk.bold.blue(` RIGOUR LOOP: Iteration ${iteration}/${maxIterations}`));
|
|
29
|
+
console.log(chalk.bold.blue(`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`));
|
|
36
30
|
// 1. Prepare Command
|
|
37
31
|
let currentArgs = [...agentArgs];
|
|
38
32
|
if (iteration > 1 && agentArgs.length > 0) {
|
|
39
33
|
// Iteration contract: In later cycles, we focus strictly on the fix packet
|
|
40
|
-
console.log(
|
|
34
|
+
console.log(chalk.yellow(`\nš REFINEMENT CYCLE - Instructing agent to fix specific violations...`));
|
|
41
35
|
// We keep the first part of the command (the agent) but can append or wrap
|
|
42
36
|
// For simplicity, we assume the agent can read the JSON file we generate
|
|
43
37
|
}
|
|
44
38
|
const getTrackedChanges = async () => {
|
|
45
39
|
try {
|
|
46
|
-
const { stdout } = await
|
|
40
|
+
const { stdout } = await execa('git', ['status', '--porcelain'], { cwd });
|
|
47
41
|
return stdout.split('\n')
|
|
48
42
|
.filter(l => l.trim())
|
|
49
43
|
.filter(line => /M|A|D|R/.test(line.slice(0, 2)))
|
|
@@ -57,13 +51,13 @@ async function runLoop(cwd, agentArgs, options) {
|
|
|
57
51
|
const beforeFiles = await getTrackedChanges();
|
|
58
52
|
// 2. Run the agent command
|
|
59
53
|
if (currentArgs.length > 0) {
|
|
60
|
-
console.log(
|
|
61
|
-
console.log(
|
|
54
|
+
console.log(chalk.cyan(`\nš DEPLOYING AGENT:`));
|
|
55
|
+
console.log(chalk.dim(` Command: ${currentArgs.join(' ')}`));
|
|
62
56
|
try {
|
|
63
|
-
await
|
|
57
|
+
await execa(currentArgs[0], currentArgs.slice(1), { shell: true, stdio: 'inherit', cwd });
|
|
64
58
|
}
|
|
65
59
|
catch (error) {
|
|
66
|
-
console.warn(
|
|
60
|
+
console.warn(chalk.yellow(`\nā ļø Agent command finished with non-zero exit code. Rigour will now verify state...`));
|
|
67
61
|
}
|
|
68
62
|
}
|
|
69
63
|
// Snapshot changed files after agent runs
|
|
@@ -71,51 +65,51 @@ async function runLoop(cwd, agentArgs, options) {
|
|
|
71
65
|
const changedThisCycle = afterFiles.filter(f => !beforeFiles.includes(f));
|
|
72
66
|
const maxFiles = config.gates.safety?.max_files_changed_per_cycle || 10;
|
|
73
67
|
if (changedThisCycle.length > maxFiles) {
|
|
74
|
-
console.log(
|
|
75
|
-
console.log(
|
|
68
|
+
console.log(chalk.red.bold(`\nš SAFETY RAIL ABORT: Agent changed ${changedThisCycle.length} files (max: ${maxFiles}).`));
|
|
69
|
+
console.log(chalk.red(` This looks like explosive behavior. Check your agent's instructions.`));
|
|
76
70
|
process.exit(EXIT_FAIL);
|
|
77
71
|
}
|
|
78
72
|
// 3. Run Rigour Check
|
|
79
|
-
console.log(
|
|
73
|
+
console.log(chalk.magenta('\nš AUDITING QUALITY GATES...'));
|
|
80
74
|
const report = await runner.run(cwd);
|
|
81
75
|
// Write report
|
|
82
|
-
const reportPath =
|
|
83
|
-
await
|
|
76
|
+
const reportPath = path.join(cwd, config.output.report_path);
|
|
77
|
+
await fs.writeJson(reportPath, report, { spaces: 2 });
|
|
84
78
|
if (report.status === 'PASS') {
|
|
85
|
-
console.log(
|
|
86
|
-
console.log(
|
|
79
|
+
console.log(chalk.green.bold('\n⨠PASS - All quality gates satisfied.'));
|
|
80
|
+
console.log(chalk.green(` Your solution meets the required Engineering Rigour criteria.\n`));
|
|
87
81
|
return;
|
|
88
82
|
}
|
|
89
83
|
// 4. Generate Fix Packet v2
|
|
90
84
|
const { FixPacketService } = await import('@rigour-labs/core');
|
|
91
85
|
const fixPacketService = new FixPacketService();
|
|
92
86
|
const fixPacket = fixPacketService.generate(report, config);
|
|
93
|
-
const fixPacketPath =
|
|
94
|
-
await
|
|
95
|
-
console.log(
|
|
96
|
-
console.log(
|
|
87
|
+
const fixPacketPath = path.join(cwd, 'rigour-fix-packet.json');
|
|
88
|
+
await fs.writeJson(fixPacketPath, fixPacket, { spaces: 2 });
|
|
89
|
+
console.log(chalk.red.bold(`\nš FAIL - Found ${report.failures.length} engineering violations.`));
|
|
90
|
+
console.log(chalk.dim(` Fix Packet generated: rigour-fix-packet.json`));
|
|
97
91
|
if (options.failFast) {
|
|
98
|
-
console.log(
|
|
92
|
+
console.log(chalk.red.bold(`\nš FAIL-FAST: Aborting loop as requested.`));
|
|
99
93
|
process.exit(EXIT_FAIL);
|
|
100
94
|
}
|
|
101
95
|
// Print summary
|
|
102
96
|
const summary = report.failures.map((f, i) => {
|
|
103
|
-
return
|
|
97
|
+
return chalk.white(`${i + 1}. `) + chalk.bold.red(`[${f.id.toUpperCase()}] `) + chalk.white(f.title);
|
|
104
98
|
}).join('\n');
|
|
105
|
-
console.log(
|
|
99
|
+
console.log(chalk.bold.white('\nš VIOLATIONS SUMMARY:'));
|
|
106
100
|
console.log(summary);
|
|
107
101
|
if (iteration === maxIterations) {
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(
|
|
102
|
+
console.log(chalk.red.bold(`\nā CRITICAL: Reached maximum iterations (${maxIterations}).`));
|
|
103
|
+
console.log(chalk.red(` Quality gates remain unfulfilled. Refactor manually or check agent logs.`));
|
|
110
104
|
process.exit(EXIT_FAIL);
|
|
111
105
|
}
|
|
112
|
-
console.log(
|
|
106
|
+
console.log(chalk.dim('\nReturning control to agent for the next refinement cycle...'));
|
|
113
107
|
}
|
|
114
108
|
}
|
|
115
109
|
catch (error) {
|
|
116
|
-
console.error(
|
|
110
|
+
console.error(chalk.red(`\nā FATAL ERROR: ${error.message}`));
|
|
117
111
|
if (error.issues) {
|
|
118
|
-
console.error(
|
|
112
|
+
console.error(chalk.dim(JSON.stringify(error.issues, null, 2)));
|
|
119
113
|
}
|
|
120
114
|
process.exit(EXIT_INTERNAL_ERROR);
|
|
121
115
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
console.log(
|
|
10
|
-
console.log(
|
|
11
|
-
console.log(
|
|
12
|
-
console.log(
|
|
13
|
-
console.log(
|
|
14
|
-
console.log(
|
|
15
|
-
console.log(
|
|
16
|
-
console.log(
|
|
17
|
-
console.log(
|
|
18
|
-
console.log(
|
|
19
|
-
console.log(
|
|
20
|
-
console.log(
|
|
21
|
-
console.log(
|
|
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'));
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export async function setupCommand() {
|
|
3
|
+
console.log(chalk.bold.cyan('\nš ļø Rigour Labs | Setup & Installation\n'));
|
|
4
|
+
console.log(chalk.bold('1. Global Installation (Recommended)'));
|
|
5
|
+
console.log(chalk.dim(' To use Rigour anywhere in your terminal:'));
|
|
6
|
+
console.log(chalk.green(' $ npm install -g @rigour-labs/cli\n'));
|
|
7
|
+
console.log(chalk.bold('2. Project-Local installation'));
|
|
8
|
+
console.log(chalk.dim(' To keep Rigour versioned with your project:'));
|
|
9
|
+
console.log(chalk.green(' $ npm install --save-dev @rigour-labs/cli\n'));
|
|
10
|
+
console.log(chalk.bold('3. Standalone Binaries (Zero-Install)'));
|
|
11
|
+
console.log(chalk.dim(' If you do not want to use Node.js:'));
|
|
12
|
+
console.log(chalk.dim(' ⢠macOS: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-macos'));
|
|
13
|
+
console.log(chalk.dim(' ⢠Linux: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-linux'));
|
|
14
|
+
console.log(chalk.dim(' ⢠Windows: ') + chalk.cyan('https://github.com/erashu212/rigour/releases/latest/download/rigour-windows.exe\n'));
|
|
15
|
+
console.log(chalk.bold('4. MCP Integration (for AI Agents)'));
|
|
16
|
+
console.log(chalk.dim(' To let Cursor or Claude use Rigour natively:'));
|
|
17
|
+
console.log(chalk.dim(' Path to MCP: ') + chalk.cyan('packages/rigour-mcp/dist/index.js'));
|
|
18
|
+
console.log(chalk.dim(' Add this to your Cursor/Claude settings.\n'));
|
|
19
|
+
console.log(chalk.bold('Update Guidance:'));
|
|
20
|
+
console.log(chalk.dim(' Keep Rigour sharp by updating regularly:'));
|
|
21
|
+
console.log(chalk.green(' $ npm install -g @rigour-labs/cli@latest\n'));
|
|
28
22
|
}
|