@rigour-labs/cli 3.0.6 → 4.0.1
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 +55 -5
- package/dist/commands/check.d.ts +7 -0
- package/dist/commands/check.js +287 -61
- package/dist/commands/init.js +83 -1
- package/dist/commands/settings.d.ts +13 -0
- package/dist/commands/settings.js +143 -0
- package/dist/commands/setup.js +110 -19
- package/dist/commands/studio.js +37 -0
- package/package.json +2 -2
- package/studio-dist/assets/index-B2pKEIQ0.js +296 -0
- package/studio-dist/assets/{index-B3y-dtOQ.css → index-WNovVfFN.css} +1 -1
- package/studio-dist/index.html +2 -2
- package/studio-dist/assets/index-C0TtM2OR.js +0 -291
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadSettings, saveSettings, getSettingsPath, updateProviderKey, removeProviderKey } from '@rigour-labs/core';
|
|
3
|
+
/**
|
|
4
|
+
* `rigour settings` — manage ~/.rigour/settings.json
|
|
5
|
+
*
|
|
6
|
+
* Like Claude Code's settings.json or Gemini CLI's config.
|
|
7
|
+
* Stores API keys, default provider, multi-agent config, CLI preferences.
|
|
8
|
+
*/
|
|
9
|
+
export async function settingsShowCommand() {
|
|
10
|
+
const settingsPath = getSettingsPath();
|
|
11
|
+
const settings = loadSettings();
|
|
12
|
+
console.log(chalk.bold.cyan('\n Rigour Settings'));
|
|
13
|
+
console.log(chalk.dim(` ${settingsPath}\n`));
|
|
14
|
+
if (Object.keys(settings).length === 0) {
|
|
15
|
+
console.log(chalk.dim(' No settings configured yet.\n'));
|
|
16
|
+
console.log(chalk.dim(' Quick start:'));
|
|
17
|
+
console.log(chalk.dim(' rigour settings set-key anthropic sk-ant-xxx'));
|
|
18
|
+
console.log(chalk.dim(' rigour settings set-key openai sk-xxx'));
|
|
19
|
+
console.log(chalk.dim(' rigour settings set provider anthropic'));
|
|
20
|
+
console.log('');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Show providers
|
|
24
|
+
if (settings.providers && Object.keys(settings.providers).length > 0) {
|
|
25
|
+
console.log(chalk.bold(' Providers:'));
|
|
26
|
+
for (const [name, key] of Object.entries(settings.providers)) {
|
|
27
|
+
if (key) {
|
|
28
|
+
const masked = maskKey(key);
|
|
29
|
+
console.log(` ${chalk.green(name)}: ${chalk.dim(masked)}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
console.log('');
|
|
33
|
+
}
|
|
34
|
+
// Show deep defaults
|
|
35
|
+
if (settings.deep) {
|
|
36
|
+
console.log(chalk.bold(' Deep Analysis Defaults:'));
|
|
37
|
+
if (settings.deep.defaultProvider)
|
|
38
|
+
console.log(` Provider: ${chalk.cyan(settings.deep.defaultProvider)}`);
|
|
39
|
+
if (settings.deep.defaultModel)
|
|
40
|
+
console.log(` Model: ${chalk.cyan(settings.deep.defaultModel)}`);
|
|
41
|
+
if (settings.deep.apiBaseUrl)
|
|
42
|
+
console.log(` API Base: ${chalk.cyan(settings.deep.apiBaseUrl)}`);
|
|
43
|
+
if (settings.deep.maxTokens)
|
|
44
|
+
console.log(` Max Tokens: ${settings.deep.maxTokens}`);
|
|
45
|
+
if (settings.deep.temperature !== undefined)
|
|
46
|
+
console.log(` Temperature: ${settings.deep.temperature}`);
|
|
47
|
+
console.log('');
|
|
48
|
+
}
|
|
49
|
+
// Show agent configs
|
|
50
|
+
if (settings.agents && Object.keys(settings.agents).length > 0) {
|
|
51
|
+
console.log(chalk.bold(' Agent Configurations:'));
|
|
52
|
+
for (const [name, config] of Object.entries(settings.agents)) {
|
|
53
|
+
const parts = [];
|
|
54
|
+
if (config.model)
|
|
55
|
+
parts.push(`model: ${config.model}`);
|
|
56
|
+
if (config.provider)
|
|
57
|
+
parts.push(`provider: ${config.provider}`);
|
|
58
|
+
if (config.fallback)
|
|
59
|
+
parts.push(`fallback: ${config.fallback}`);
|
|
60
|
+
console.log(` ${chalk.green(name)}: ${chalk.dim(parts.join(', '))}`);
|
|
61
|
+
}
|
|
62
|
+
console.log('');
|
|
63
|
+
}
|
|
64
|
+
// Show CLI prefs
|
|
65
|
+
if (settings.cli) {
|
|
66
|
+
console.log(chalk.bold(' CLI Preferences:'));
|
|
67
|
+
if (settings.cli.defaultPreset)
|
|
68
|
+
console.log(` Default Preset: ${settings.cli.defaultPreset}`);
|
|
69
|
+
if (settings.cli.colorOutput !== undefined)
|
|
70
|
+
console.log(` Color Output: ${settings.cli.colorOutput}`);
|
|
71
|
+
if (settings.cli.verboseOutput !== undefined)
|
|
72
|
+
console.log(` Verbose: ${settings.cli.verboseOutput}`);
|
|
73
|
+
console.log('');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function settingsSetKeyCommand(provider, apiKey) {
|
|
77
|
+
updateProviderKey(provider, apiKey);
|
|
78
|
+
const masked = maskKey(apiKey);
|
|
79
|
+
console.log(chalk.green(` ✓ ${provider} API key saved: ${masked}`));
|
|
80
|
+
console.log(chalk.dim(` Stored in ${getSettingsPath()}`));
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(chalk.dim(` Usage: rigour check --deep --provider ${provider}`));
|
|
83
|
+
console.log(chalk.dim(` Or set as default: rigour settings set provider ${provider}`));
|
|
84
|
+
}
|
|
85
|
+
export async function settingsRemoveKeyCommand(provider) {
|
|
86
|
+
removeProviderKey(provider);
|
|
87
|
+
console.log(chalk.green(` ✓ ${provider} API key removed`));
|
|
88
|
+
}
|
|
89
|
+
export async function settingsSetCommand(key, value) {
|
|
90
|
+
const settings = loadSettings();
|
|
91
|
+
// Parse dot-notation keys: "deep.defaultProvider" -> settings.deep.defaultProvider
|
|
92
|
+
const parts = key.split('.');
|
|
93
|
+
let target = settings;
|
|
94
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
95
|
+
if (!target[parts[i]])
|
|
96
|
+
target[parts[i]] = {};
|
|
97
|
+
target = target[parts[i]];
|
|
98
|
+
}
|
|
99
|
+
const lastKey = parts[parts.length - 1];
|
|
100
|
+
// Auto-convert booleans and numbers
|
|
101
|
+
if (value === 'true')
|
|
102
|
+
target[lastKey] = true;
|
|
103
|
+
else if (value === 'false')
|
|
104
|
+
target[lastKey] = false;
|
|
105
|
+
else if (!isNaN(Number(value)) && value.trim() !== '')
|
|
106
|
+
target[lastKey] = Number(value);
|
|
107
|
+
else
|
|
108
|
+
target[lastKey] = value;
|
|
109
|
+
saveSettings(settings);
|
|
110
|
+
console.log(chalk.green(` ✓ ${key} = ${value}`));
|
|
111
|
+
}
|
|
112
|
+
export async function settingsGetCommand(key) {
|
|
113
|
+
const settings = loadSettings();
|
|
114
|
+
const parts = key.split('.');
|
|
115
|
+
let value = settings;
|
|
116
|
+
for (const part of parts) {
|
|
117
|
+
if (value === undefined || value === null)
|
|
118
|
+
break;
|
|
119
|
+
value = value[part];
|
|
120
|
+
}
|
|
121
|
+
if (value === undefined) {
|
|
122
|
+
console.log(chalk.dim(` ${key} is not set`));
|
|
123
|
+
}
|
|
124
|
+
else if (typeof value === 'object') {
|
|
125
|
+
console.log(` ${key} = ${JSON.stringify(value, null, 2)}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.log(` ${key} = ${value}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export async function settingsResetCommand() {
|
|
132
|
+
saveSettings({});
|
|
133
|
+
console.log(chalk.green(' ✓ Settings reset to defaults'));
|
|
134
|
+
console.log(chalk.dim(` ${getSettingsPath()}`));
|
|
135
|
+
}
|
|
136
|
+
export async function settingsPathCommand() {
|
|
137
|
+
console.log(getSettingsPath());
|
|
138
|
+
}
|
|
139
|
+
function maskKey(key) {
|
|
140
|
+
if (key.length <= 8)
|
|
141
|
+
return '***';
|
|
142
|
+
return key.substring(0, 6) + '...' + key.substring(key.length - 4);
|
|
143
|
+
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,22 +1,113 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { loadSettings, getSettingsPath, isModelCached, getModelsDir } from '@rigour-labs/core';
|
|
2
5
|
export async function setupCommand() {
|
|
3
|
-
console.log(chalk.bold.cyan('\n🛠️ Rigour Labs | Setup &
|
|
4
|
-
|
|
5
|
-
console.log(chalk.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
console.log(chalk.bold('
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
console.log(chalk.bold.cyan('\n🛠️ Rigour Labs | Setup & System Check\n'));
|
|
7
|
+
// ── Section 1: Installation Status ──
|
|
8
|
+
console.log(chalk.bold(' Installation'));
|
|
9
|
+
const cliVersion = getCliVersion();
|
|
10
|
+
if (cliVersion) {
|
|
11
|
+
console.log(chalk.green(` ✔ Rigour CLI ${cliVersion}`));
|
|
12
|
+
}
|
|
13
|
+
// Check if rigour.yml exists in cwd
|
|
14
|
+
const hasConfig = fs.existsSync(path.join(process.cwd(), 'rigour.yml'));
|
|
15
|
+
if (hasConfig) {
|
|
16
|
+
console.log(chalk.green(' ✔ rigour.yml found in current directory'));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(chalk.yellow(' ○ No rigour.yml — run `rigour init` to set up'));
|
|
20
|
+
}
|
|
21
|
+
// ── Section 2: Settings & API Keys ──
|
|
22
|
+
console.log(chalk.bold('\n Settings'));
|
|
23
|
+
const settingsPath = getSettingsPath();
|
|
24
|
+
const settings = loadSettings();
|
|
25
|
+
const providers = settings.providers || {};
|
|
26
|
+
const configuredKeys = Object.entries(providers).filter(([_, key]) => !!key);
|
|
27
|
+
if (configuredKeys.length > 0) {
|
|
28
|
+
for (const [name, key] of configuredKeys) {
|
|
29
|
+
if (key) {
|
|
30
|
+
const masked = key.length > 8 ? key.substring(0, 6) + '...' + key.substring(key.length - 4) : '***';
|
|
31
|
+
console.log(chalk.green(` ✔ ${name}: ${chalk.dim(masked)}`));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log(chalk.yellow(' ○ No API keys configured'));
|
|
37
|
+
console.log(chalk.dim(` ${settingsPath}`));
|
|
38
|
+
}
|
|
39
|
+
if (settings.deep?.defaultProvider) {
|
|
40
|
+
console.log(chalk.green(` ✔ Default provider: ${settings.deep.defaultProvider}`));
|
|
41
|
+
}
|
|
42
|
+
// ── Section 3: Deep Analysis Readiness ──
|
|
43
|
+
console.log(chalk.bold('\n Deep Analysis'));
|
|
44
|
+
// Check local models
|
|
45
|
+
const hasDeep = isModelCached('deep');
|
|
46
|
+
const hasPro = isModelCached('pro');
|
|
47
|
+
if (hasDeep)
|
|
48
|
+
console.log(chalk.green(' ✔ Local model: deep (Qwen2.5-Coder-0.5B, 350MB)'));
|
|
49
|
+
if (hasPro)
|
|
50
|
+
console.log(chalk.green(' ✔ Local model: pro (Qwen2.5-Coder-1.5B, 900MB)'));
|
|
51
|
+
if (!hasDeep && !hasPro) {
|
|
52
|
+
console.log(chalk.yellow(' ○ No local models cached'));
|
|
53
|
+
console.log(chalk.dim(` Models dir: ${getModelsDir()}`));
|
|
54
|
+
}
|
|
55
|
+
// Check sidecar binary
|
|
56
|
+
let hasSidecar = false;
|
|
57
|
+
try {
|
|
58
|
+
const { execSync } = await import('child_process');
|
|
59
|
+
execSync('which llama-cli 2>/dev/null || which rigour-brain 2>/dev/null', { encoding: 'utf-8', timeout: 3000 });
|
|
60
|
+
hasSidecar = true;
|
|
61
|
+
console.log(chalk.green(' ✔ Inference binary found'));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
const binDir = path.join(getModelsDir(), '..', 'bin');
|
|
65
|
+
if (fs.existsSync(path.join(binDir, 'rigour-brain')) || fs.existsSync(path.join(binDir, 'llama-cli'))) {
|
|
66
|
+
hasSidecar = true;
|
|
67
|
+
console.log(chalk.green(' ✔ Inference binary found'));
|
|
68
|
+
}
|
|
69
|
+
else if (configuredKeys.length === 0) {
|
|
70
|
+
console.log(chalk.yellow(' ○ No local inference binary'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Cloud readiness
|
|
74
|
+
const hasCloudKey = configuredKeys.length > 0;
|
|
75
|
+
const hasLocalReady = hasSidecar && (hasDeep || hasPro);
|
|
76
|
+
if (hasCloudKey || hasLocalReady) {
|
|
77
|
+
console.log(chalk.green.bold('\n ✓ Deep analysis is ready'));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log(chalk.yellow.bold('\n ⚠ Deep analysis not configured'));
|
|
81
|
+
}
|
|
82
|
+
// ── Section 4: Quick Setup Commands ──
|
|
83
|
+
if (!hasCloudKey && !hasLocalReady) {
|
|
84
|
+
console.log(chalk.bold('\n Quick Setup:'));
|
|
85
|
+
console.log(chalk.dim(' # Option A: Cloud (recommended)'));
|
|
86
|
+
console.log(` ${chalk.cyan('rigour settings set-key anthropic')} ${chalk.dim('sk-ant-xxx')}`);
|
|
87
|
+
console.log(` ${chalk.cyan('rigour settings set-key openai')} ${chalk.dim('sk-xxx')}`);
|
|
88
|
+
console.log(` ${chalk.cyan('rigour settings set-key groq')} ${chalk.dim('gsk_xxx')}`);
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk.dim(' # Option B: 100% Local'));
|
|
91
|
+
console.log(` ${chalk.cyan('rigour check --deep')} ${chalk.dim('# auto-downloads 350MB model')}`);
|
|
92
|
+
}
|
|
93
|
+
// ── Section 5: Installation Methods ──
|
|
94
|
+
console.log(chalk.bold('\n Installation Methods:'));
|
|
95
|
+
console.log(chalk.dim(' Global: ') + chalk.cyan('npm install -g @rigour-labs/cli'));
|
|
96
|
+
console.log(chalk.dim(' Local: ') + chalk.cyan('npm install --save-dev @rigour-labs/cli'));
|
|
97
|
+
console.log(chalk.dim(' No-install: ') + chalk.cyan('npx @rigour-labs/cli check'));
|
|
98
|
+
console.log(chalk.dim(' MCP: ') + chalk.cyan('packages/rigour-mcp/dist/index.js'));
|
|
99
|
+
console.log('');
|
|
100
|
+
}
|
|
101
|
+
function getCliVersion() {
|
|
102
|
+
try {
|
|
103
|
+
const pkgPath = path.resolve(new URL(import.meta.url).pathname, '../../../package.json');
|
|
104
|
+
if (fs.existsSync(pkgPath)) {
|
|
105
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
106
|
+
return pkg.version || null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// fallback
|
|
111
|
+
}
|
|
112
|
+
return '2.0.0';
|
|
22
113
|
}
|
package/dist/commands/studio.js
CHANGED
|
@@ -295,6 +295,43 @@ async function setupApiAndLaunch(apiPort, studioPort, eventsPath, cwd, studioPro
|
|
|
295
295
|
res.end(e.message);
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
|
+
else if (url.pathname === '/api/report-stats') {
|
|
299
|
+
try {
|
|
300
|
+
const reportPath = path.join(cwd, 'rigour-report.json');
|
|
301
|
+
if (await fs.pathExists(reportPath)) {
|
|
302
|
+
const report = await fs.readJson(reportPath);
|
|
303
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
304
|
+
res.end(JSON.stringify(report.stats || {}));
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
308
|
+
res.end(JSON.stringify({}));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch (e) {
|
|
312
|
+
res.writeHead(500);
|
|
313
|
+
res.end(e.message);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else if (url.pathname === '/api/deep-findings') {
|
|
317
|
+
try {
|
|
318
|
+
const reportPath = path.join(cwd, 'rigour-report.json');
|
|
319
|
+
if (await fs.pathExists(reportPath)) {
|
|
320
|
+
const report = await fs.readJson(reportPath);
|
|
321
|
+
const findings = (report.failures || []).filter((f) => f.provenance === 'deep-analysis' || f.source === 'llm' || f.source === 'hybrid');
|
|
322
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
323
|
+
res.end(JSON.stringify(findings));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
327
|
+
res.end(JSON.stringify([]));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
catch (e) {
|
|
331
|
+
res.writeHead(500);
|
|
332
|
+
res.end(e.message);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
298
335
|
else if (url.pathname === '/api/arbitrate' && req.method === 'POST') {
|
|
299
336
|
let body = '';
|
|
300
337
|
req.on('data', chunk => body += chunk);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "CLI quality gates for AI-generated code. Forces AI agents (Claude, Cursor, Copilot) to meet strict engineering standards with PASS/FAIL enforcement.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://rigour.run",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"inquirer": "9.2.16",
|
|
45
45
|
"ora": "^8.0.1",
|
|
46
46
|
"yaml": "^2.8.2",
|
|
47
|
-
"@rigour-labs/core": "
|
|
47
|
+
"@rigour-labs/core": "4.0.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/fs-extra": "^11.0.4",
|