@rigour-labs/core 5.2.5 → 5.2.6
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.
|
@@ -13,5 +13,11 @@ export declare class SidecarProvider implements InferenceProvider {
|
|
|
13
13
|
private getPlatformKey;
|
|
14
14
|
private getPlatformPackageName;
|
|
15
15
|
private resolveBinaryPath;
|
|
16
|
+
/**
|
|
17
|
+
* Download llama-cli directly from llama.cpp GitHub releases.
|
|
18
|
+
* Extracts the binary to ~/.rigour/bin/llama-cli
|
|
19
|
+
*/
|
|
20
|
+
private downloadLlamaCli;
|
|
21
|
+
/** Legacy: install via npm brain package */
|
|
16
22
|
private installSidecarBinary;
|
|
17
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sidecar Binary Provider — runs inference via pre-compiled llama.cpp binary.
|
|
3
|
-
*
|
|
4
|
-
* Falls back to PATH lookup for development/manual installs.
|
|
3
|
+
* Auto-downloads llama-cli from GitHub releases on first use.
|
|
4
|
+
* Falls back to npm packages or PATH lookup for development/manual installs.
|
|
5
5
|
*/
|
|
6
6
|
import { execFile } from 'child_process';
|
|
7
7
|
import { promisify } from 'util';
|
|
@@ -13,7 +13,8 @@ import { ensureModel, isModelCached, getModelInfo } from './model-manager.js';
|
|
|
13
13
|
import { ensureExecutableBinary } from './executable.js';
|
|
14
14
|
const execFileAsync = promisify(execFile);
|
|
15
15
|
const SIDECAR_INSTALL_DIR = path.join(os.homedir(), '.rigour', 'sidecar');
|
|
16
|
-
|
|
16
|
+
const BINARY_DIR = path.join(os.homedir(), '.rigour', 'bin');
|
|
17
|
+
/** Platform → npm package mapping (legacy, still checked) */
|
|
17
18
|
const PLATFORM_PACKAGES = {
|
|
18
19
|
'darwin-arm64': '@rigour-labs/brain-darwin-arm64',
|
|
19
20
|
'darwin-x64': '@rigour-labs/brain-darwin-x64',
|
|
@@ -21,6 +22,16 @@ const PLATFORM_PACKAGES = {
|
|
|
21
22
|
'linux-arm64': '@rigour-labs/brain-linux-arm64',
|
|
22
23
|
'win32-x64': '@rigour-labs/brain-win-x64',
|
|
23
24
|
};
|
|
25
|
+
const LLAMA_RELEASE_TAG = 'b5604';
|
|
26
|
+
const LLAMA_RELEASE_BASE = `https://github.com/ggml-org/llama.cpp/releases/download/${LLAMA_RELEASE_TAG}`;
|
|
27
|
+
/** Platform → llama.cpp release asset name */
|
|
28
|
+
const LLAMA_RELEASE_ASSETS = {
|
|
29
|
+
'darwin-arm64': `llama-${LLAMA_RELEASE_TAG}-bin-macos-arm64.zip`,
|
|
30
|
+
'darwin-x64': `llama-${LLAMA_RELEASE_TAG}-bin-macos-x64.zip`,
|
|
31
|
+
'linux-x64': `llama-${LLAMA_RELEASE_TAG}-bin-ubuntu-x64.zip`,
|
|
32
|
+
'win32-x64': `llama-${LLAMA_RELEASE_TAG}-bin-win-cpu-x64.zip`,
|
|
33
|
+
// linux-arm64 not published by llama.cpp — users must build from source or use cloud provider
|
|
34
|
+
};
|
|
24
35
|
export class SidecarProvider {
|
|
25
36
|
name = 'sidecar';
|
|
26
37
|
binaryPath = null;
|
|
@@ -36,26 +47,35 @@ export class SidecarProvider {
|
|
|
36
47
|
return binary !== null;
|
|
37
48
|
}
|
|
38
49
|
async setup(onProgress) {
|
|
39
|
-
const packageName = this.getPlatformPackageName();
|
|
40
50
|
// 1. Check/resolve binary
|
|
41
51
|
this.binaryPath = await this.resolveBinaryPath();
|
|
42
|
-
// Auto-bootstrap
|
|
43
|
-
if (!this.binaryPath
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
52
|
+
// Auto-bootstrap: download llama-cli directly from GitHub releases
|
|
53
|
+
if (!this.binaryPath) {
|
|
54
|
+
const downloaded = await this.downloadLlamaCli(onProgress);
|
|
55
|
+
if (downloaded) {
|
|
46
56
|
this.binaryPath = await this.resolveBinaryPath();
|
|
47
57
|
}
|
|
48
58
|
}
|
|
59
|
+
// Legacy fallback: try npm package install
|
|
60
|
+
if (!this.binaryPath) {
|
|
61
|
+
const packageName = this.getPlatformPackageName();
|
|
62
|
+
if (packageName) {
|
|
63
|
+
const installed = await this.installSidecarBinary(packageName, onProgress);
|
|
64
|
+
if (installed) {
|
|
65
|
+
this.binaryPath = await this.resolveBinaryPath();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
49
69
|
if (!this.binaryPath) {
|
|
50
|
-
onProgress?.('⚠ Inference engine not found.
|
|
51
|
-
|
|
52
|
-
throw new Error(`Sidecar binary not found. Run: npm install ${installHint}`);
|
|
70
|
+
onProgress?.('⚠ Inference engine not found. Rigour will auto-download on next attempt.');
|
|
71
|
+
throw new Error(`Sidecar binary not found. Check network connection and retry.`);
|
|
53
72
|
}
|
|
54
73
|
let executableCheck = ensureExecutableBinary(this.binaryPath);
|
|
55
74
|
// If the discovered binary is not executable, try a managed reinstall once.
|
|
56
|
-
|
|
75
|
+
const retryPackage = this.getPlatformPackageName();
|
|
76
|
+
if (!executableCheck.ok && retryPackage) {
|
|
57
77
|
onProgress?.('⚠ Inference engine is present but not executable. Reinstalling managed sidecar...');
|
|
58
|
-
const installed = await this.installSidecarBinary(
|
|
78
|
+
const installed = await this.installSidecarBinary(retryPackage, onProgress);
|
|
59
79
|
if (installed) {
|
|
60
80
|
const refreshedPath = await this.resolveBinaryPath();
|
|
61
81
|
if (refreshedPath) {
|
|
@@ -172,6 +192,12 @@ export class SidecarProvider {
|
|
|
172
192
|
}
|
|
173
193
|
async resolveBinaryPath() {
|
|
174
194
|
const platformKey = this.getPlatformKey();
|
|
195
|
+
// Strategy 0: Check ~/.rigour/bin/llama-cli (auto-downloaded from GitHub releases)
|
|
196
|
+
const binaryName = os.platform() === 'win32' ? 'llama-cli.exe' : 'llama-cli';
|
|
197
|
+
const autoDownloadedPath = path.join(BINARY_DIR, binaryName);
|
|
198
|
+
if (await fs.pathExists(autoDownloadedPath)) {
|
|
199
|
+
return autoDownloadedPath;
|
|
200
|
+
}
|
|
175
201
|
// Strategy 1: Check @rigour-labs/brain-{platform} optional dependency
|
|
176
202
|
const packageName = PLATFORM_PACKAGES[platformKey];
|
|
177
203
|
if (packageName) {
|
|
@@ -264,8 +290,73 @@ export class SidecarProvider {
|
|
|
264
290
|
}
|
|
265
291
|
return null;
|
|
266
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Download llama-cli directly from llama.cpp GitHub releases.
|
|
295
|
+
* Extracts the binary to ~/.rigour/bin/llama-cli
|
|
296
|
+
*/
|
|
297
|
+
async downloadLlamaCli(onProgress) {
|
|
298
|
+
const platformKey = this.getPlatformKey();
|
|
299
|
+
const assetName = LLAMA_RELEASE_ASSETS[platformKey];
|
|
300
|
+
if (!assetName)
|
|
301
|
+
return false;
|
|
302
|
+
const url = `${LLAMA_RELEASE_BASE}/${assetName}`;
|
|
303
|
+
const zipPath = path.join(BINARY_DIR, assetName);
|
|
304
|
+
const binaryName = os.platform() === 'win32' ? 'llama-cli.exe' : 'llama-cli';
|
|
305
|
+
const destPath = path.join(BINARY_DIR, binaryName);
|
|
306
|
+
// Already downloaded
|
|
307
|
+
if (await fs.pathExists(destPath))
|
|
308
|
+
return true;
|
|
309
|
+
onProgress?.(`⬇ Downloading inference engine (llama.cpp ${LLAMA_RELEASE_TAG})...`);
|
|
310
|
+
try {
|
|
311
|
+
await fs.ensureDir(BINARY_DIR);
|
|
312
|
+
// Download zip
|
|
313
|
+
const response = await fetch(url, { redirect: 'follow' });
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
316
|
+
}
|
|
317
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
318
|
+
await fs.writeFile(zipPath, buffer);
|
|
319
|
+
onProgress?.(' Extracting...');
|
|
320
|
+
// Extract llama-cli from zip
|
|
321
|
+
if (os.platform() === 'win32') {
|
|
322
|
+
await execFileAsync('powershell', [
|
|
323
|
+
'-Command',
|
|
324
|
+
`Expand-Archive -Path "${zipPath}" -DestinationPath "${BINARY_DIR}/llama-extract" -Force`,
|
|
325
|
+
], { timeout: 60000 });
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
await execFileAsync('unzip', ['-o', zipPath, '-d', path.join(BINARY_DIR, 'llama-extract')], {
|
|
329
|
+
timeout: 60000,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// Find llama-cli in extracted files
|
|
333
|
+
const extractDir = path.join(BINARY_DIR, 'llama-extract');
|
|
334
|
+
const llamaBin = await findFileRecursive(extractDir, binaryName);
|
|
335
|
+
if (!llamaBin) {
|
|
336
|
+
throw new Error(`${binaryName} not found in release archive`);
|
|
337
|
+
}
|
|
338
|
+
await fs.copy(llamaBin, destPath);
|
|
339
|
+
if (os.platform() !== 'win32') {
|
|
340
|
+
await fs.chmod(destPath, 0o755);
|
|
341
|
+
}
|
|
342
|
+
// Cleanup
|
|
343
|
+
await fs.remove(zipPath);
|
|
344
|
+
await fs.remove(extractDir);
|
|
345
|
+
onProgress?.(`✓ Inference engine ready (${LLAMA_RELEASE_TAG})`);
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
const reason = typeof error?.message === 'string' ? error.message : 'unknown error';
|
|
350
|
+
onProgress?.(`⚠ Download failed: ${reason}`);
|
|
351
|
+
// Cleanup partial downloads
|
|
352
|
+
await fs.remove(zipPath).catch(() => { });
|
|
353
|
+
await fs.remove(path.join(BINARY_DIR, 'llama-extract')).catch(() => { });
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/** Legacy: install via npm brain package */
|
|
267
358
|
async installSidecarBinary(packageName, onProgress) {
|
|
268
|
-
onProgress?.(`⬇
|
|
359
|
+
onProgress?.(`⬇ Trying npm fallback: ${packageName}`);
|
|
269
360
|
try {
|
|
270
361
|
await fs.ensureDir(SIDECAR_INSTALL_DIR);
|
|
271
362
|
await execFileAsync(os.platform() === 'win32' ? 'npm.cmd' : 'npm', ['install', '--no-save', '--no-package-lock', '--prefix', SIDECAR_INSTALL_DIR, packageName], {
|
|
@@ -276,7 +367,7 @@ export class SidecarProvider {
|
|
|
276
367
|
}
|
|
277
368
|
catch (error) {
|
|
278
369
|
const reason = typeof error?.message === 'string' ? error.message : 'unknown install error';
|
|
279
|
-
onProgress?.(`⚠
|
|
370
|
+
onProgress?.(`⚠ npm install failed: ${reason}`);
|
|
280
371
|
return false;
|
|
281
372
|
}
|
|
282
373
|
onProgress?.(`✓ Installed ${packageName}`);
|
|
@@ -286,3 +377,19 @@ export class SidecarProvider {
|
|
|
286
377
|
function quoteCmdArg(value) {
|
|
287
378
|
return `"${value.replace(/"/g, '\\"')}"`;
|
|
288
379
|
}
|
|
380
|
+
/** Recursively find a file by name in a directory */
|
|
381
|
+
async function findFileRecursive(dir, filename) {
|
|
382
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
383
|
+
for (const entry of entries) {
|
|
384
|
+
const fullPath = path.join(dir, entry.name);
|
|
385
|
+
if (entry.isDirectory()) {
|
|
386
|
+
const found = await findFileRecursive(fullPath, filename);
|
|
387
|
+
if (found)
|
|
388
|
+
return found;
|
|
389
|
+
}
|
|
390
|
+
else if (entry.name === filename) {
|
|
391
|
+
return fullPath;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.6",
|
|
4
4
|
"description": "AI-native quality gate engine with local Bayesian learning. AST analysis, drift detection, Fix Packet generation, and agent self-healing across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://rigour.run",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"@xenova/transformers": "^2.17.2",
|
|
67
67
|
"sqlite3": "^5.1.7",
|
|
68
68
|
"openai": "^4.104.0",
|
|
69
|
-
"@rigour-labs/brain-darwin-
|
|
70
|
-
"@rigour-labs/brain-
|
|
71
|
-
"@rigour-labs/brain-
|
|
72
|
-
"@rigour-labs/brain-
|
|
73
|
-
"@rigour-labs/brain-
|
|
69
|
+
"@rigour-labs/brain-darwin-x64": "5.2.6",
|
|
70
|
+
"@rigour-labs/brain-linux-x64": "5.2.6",
|
|
71
|
+
"@rigour-labs/brain-darwin-arm64": "5.2.6",
|
|
72
|
+
"@rigour-labs/brain-win-x64": "5.2.6",
|
|
73
|
+
"@rigour-labs/brain-linux-arm64": "5.2.6"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@types/fs-extra": "^11.0.4",
|