@rigour-labs/cli 3.0.5 ā 4.0.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 +55 -5
- package/dist/commands/check.d.ts +7 -0
- package/dist/commands/check.js +287 -61
- package/dist/commands/demo-display.d.ts +11 -0
- package/dist/commands/demo-display.js +181 -0
- package/dist/commands/demo-helpers.d.ts +9 -0
- package/dist/commands/demo-helpers.js +28 -0
- package/dist/commands/demo-scenarios.d.ts +11 -0
- package/dist/commands/demo-scenarios.js +356 -0
- package/dist/commands/demo.d.ts +2 -15
- package/dist/commands/demo.js +5 -569
- package/dist/commands/init.js +83 -1
- package/dist/commands/scan.js +53 -10
- package/dist/commands/settings.d.ts +13 -0
- package/dist/commands/settings.js +143 -0
- package/dist/commands/setup.js +110 -19
- package/package.json +2 -2
package/dist/commands/scan.js
CHANGED
|
@@ -157,12 +157,34 @@ function renderScanHeader(scanCtx, stackSignals) {
|
|
|
157
157
|
}
|
|
158
158
|
function renderScanResults(report, stackSignals, reportPath, cwd) {
|
|
159
159
|
const fakePackages = extractHallucinatedImports(report.failures);
|
|
160
|
+
const criticalSecrets = report.failures.filter(f => f.id === 'security-patterns' && f.severity === 'critical');
|
|
161
|
+
const phantomApis = report.failures.filter(f => f.id === 'phantom-apis');
|
|
162
|
+
const ignoredErrors = report.failures.filter(f => f.id === 'promise-safety' && (f.severity === 'high' || f.severity === 'critical'));
|
|
163
|
+
// --- Scary headlines for the worst findings ---
|
|
164
|
+
let scaryHeadlines = 0;
|
|
165
|
+
if (criticalSecrets.length > 0) {
|
|
166
|
+
console.log(chalk.red.bold(`š HARDCODED SECRETS: ${criticalSecrets.length} credential(s) exposed in plain text`));
|
|
167
|
+
const firstFile = criticalSecrets[0].files?.[0];
|
|
168
|
+
if (firstFile)
|
|
169
|
+
console.log(chalk.dim(` First hit: ${firstFile}`));
|
|
170
|
+
scaryHeadlines++;
|
|
171
|
+
}
|
|
160
172
|
if (fakePackages.length > 0) {
|
|
161
173
|
const unique = [...new Set(fakePackages)];
|
|
162
|
-
console.log(chalk.red.bold(
|
|
163
|
-
console.log(chalk.dim(`Examples: ${unique.slice(0,
|
|
164
|
-
|
|
174
|
+
console.log(chalk.red.bold(`š¦ HALLUCINATED PACKAGES: ${unique.length} import(s) don't exist ā will crash at runtime`));
|
|
175
|
+
console.log(chalk.dim(` Examples: ${unique.slice(0, 4).join(', ')}${unique.length > 4 ? `, +${unique.length - 4} more` : ''}`));
|
|
176
|
+
scaryHeadlines++;
|
|
177
|
+
}
|
|
178
|
+
if (phantomApis.length > 0) {
|
|
179
|
+
console.log(chalk.red.bold(`š» PHANTOM APIs: ${phantomApis.length} call(s) to methods that don't exist in stdlib`));
|
|
180
|
+
scaryHeadlines++;
|
|
165
181
|
}
|
|
182
|
+
if (ignoredErrors.length > 0) {
|
|
183
|
+
console.log(chalk.yellow.bold(`š SILENT FAILURES: ${ignoredErrors.length} async error(s) swallowed ā failures will vanish without a trace`));
|
|
184
|
+
scaryHeadlines++;
|
|
185
|
+
}
|
|
186
|
+
if (scaryHeadlines > 0)
|
|
187
|
+
console.log('');
|
|
166
188
|
const statusColor = report.status === 'PASS' ? chalk.green.bold : chalk.red.bold;
|
|
167
189
|
const statusLabel = report.status === 'PASS' ? 'PASS' : 'FAIL';
|
|
168
190
|
const score = report.stats.score ?? 0;
|
|
@@ -179,27 +201,48 @@ function renderScanResults(report, stackSignals, reportPath, cwd) {
|
|
|
179
201
|
renderCoverageWarnings(stackSignals);
|
|
180
202
|
console.log('');
|
|
181
203
|
if (report.status === 'FAIL') {
|
|
182
|
-
|
|
204
|
+
// Sort by severity so critical findings appear first
|
|
205
|
+
const SEVERITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
206
|
+
const sorted = [...report.failures].sort((a, b) => (SEVERITY_ORDER[a.severity ?? 'medium'] ?? 2) - (SEVERITY_ORDER[b.severity ?? 'medium'] ?? 2));
|
|
207
|
+
const topFindings = sorted.slice(0, 8);
|
|
183
208
|
for (const failure of topFindings) {
|
|
184
|
-
const sev =
|
|
185
|
-
|
|
209
|
+
const sev = failure.severity ?? 'medium';
|
|
210
|
+
const sevColor = sev === 'critical' ? chalk.red.bold
|
|
211
|
+
: sev === 'high' ? chalk.yellow.bold
|
|
212
|
+
: sev === 'medium' ? chalk.white
|
|
213
|
+
: chalk.dim;
|
|
214
|
+
console.log(sevColor(`${sev.toUpperCase().padEnd(8)} [${failure.id}] ${failure.title}`));
|
|
186
215
|
if (failure.files && failure.files.length > 0) {
|
|
187
|
-
console.log(chalk.dim(`
|
|
216
|
+
console.log(chalk.dim(` ${failure.files.slice(0, 2).join(', ')}`));
|
|
188
217
|
}
|
|
189
218
|
}
|
|
190
219
|
if (report.failures.length > topFindings.length) {
|
|
191
|
-
console.log(chalk.dim(
|
|
220
|
+
console.log(chalk.dim(`\n...and ${report.failures.length - topFindings.length} more. See full report.`));
|
|
192
221
|
}
|
|
193
222
|
}
|
|
194
223
|
const trend = getScoreTrend(cwd);
|
|
195
224
|
if (trend && trend.recentScores.length >= 3) {
|
|
196
|
-
|
|
225
|
+
const arrow = trend.direction === 'improving' ? 'ā' : trend.direction === 'degrading' ? 'ā' : 'ā';
|
|
226
|
+
const color = trend.direction === 'improving' ? chalk.green : trend.direction === 'degrading' ? chalk.red : chalk.dim;
|
|
227
|
+
console.log(color(`\nTrend: ${trend.recentScores.join(' ā ')} ${arrow}`));
|
|
197
228
|
}
|
|
198
229
|
console.log(chalk.yellow(`\nFull report: ${reportPath}`));
|
|
199
230
|
if (report.status === 'FAIL') {
|
|
200
|
-
console.log(chalk.yellow('Fix packet:
|
|
231
|
+
console.log(chalk.yellow('Fix packet: rigour-fix-packet.json'));
|
|
201
232
|
}
|
|
202
233
|
console.log(chalk.dim(`Finished in ${report.stats.duration_ms}ms`));
|
|
234
|
+
// --- Next steps ---
|
|
235
|
+
console.log('');
|
|
236
|
+
if (report.status === 'FAIL') {
|
|
237
|
+
console.log(chalk.bold('Next steps:'));
|
|
238
|
+
console.log(` ${chalk.cyan('rigour explain')} ā get plain-English fix suggestions`);
|
|
239
|
+
console.log(` ${chalk.cyan('rigour init')} ā add quality gates to your project (blocks AI from repeating this)`);
|
|
240
|
+
console.log(` ${chalk.cyan('rigour check --ci')} ā enforce in CI/CD pipeline`);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
console.log(chalk.green.bold('ā This repo is clean. Add it to CI to keep it that way:'));
|
|
244
|
+
console.log(` ${chalk.cyan('rigour init')} ā write quality gates to rigour.yml + CI config`);
|
|
245
|
+
}
|
|
203
246
|
}
|
|
204
247
|
function renderCoverageWarnings(stackSignals) {
|
|
205
248
|
const gaps = [];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rigour settings` ā manage ~/.rigour/settings.json
|
|
3
|
+
*
|
|
4
|
+
* Like Claude Code's settings.json or Gemini CLI's config.
|
|
5
|
+
* Stores API keys, default provider, multi-agent config, CLI preferences.
|
|
6
|
+
*/
|
|
7
|
+
export declare function settingsShowCommand(): Promise<void>;
|
|
8
|
+
export declare function settingsSetKeyCommand(provider: string, apiKey: string): Promise<void>;
|
|
9
|
+
export declare function settingsRemoveKeyCommand(provider: string): Promise<void>;
|
|
10
|
+
export declare function settingsSetCommand(key: string, value: string): Promise<void>;
|
|
11
|
+
export declare function settingsGetCommand(key: string): Promise<void>;
|
|
12
|
+
export declare function settingsResetCommand(): Promise<void>;
|
|
13
|
+
export declare function settingsPathCommand(): Promise<void>;
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
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.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/fs-extra": "^11.0.4",
|