@rigour-labs/core 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/deep/fact-extractor.d.ts +80 -0
- package/dist/deep/fact-extractor.js +626 -0
- package/dist/deep/index.d.ts +14 -0
- package/dist/deep/index.js +12 -0
- package/dist/deep/prompts.d.ts +22 -0
- package/dist/deep/prompts.js +374 -0
- package/dist/deep/verifier.d.ts +16 -0
- package/dist/deep/verifier.js +388 -0
- package/dist/gates/deep-analysis.d.ts +28 -0
- package/dist/gates/deep-analysis.js +302 -0
- package/dist/gates/deprecated-apis-rules-lang.d.ts +21 -0
- package/dist/gates/deprecated-apis-rules-lang.js +311 -0
- package/dist/gates/deprecated-apis-rules-node.d.ts +19 -0
- package/dist/gates/deprecated-apis-rules-node.js +199 -0
- package/dist/gates/deprecated-apis-rules.d.ts +6 -0
- package/dist/gates/deprecated-apis-rules.js +6 -0
- package/dist/gates/deprecated-apis.js +1 -502
- package/dist/gates/hallucinated-imports-lang.d.ts +16 -0
- package/dist/gates/hallucinated-imports-lang.js +374 -0
- package/dist/gates/hallucinated-imports-stdlib.d.ts +12 -0
- package/dist/gates/hallucinated-imports-stdlib.js +228 -0
- package/dist/gates/hallucinated-imports.d.ts +0 -98
- package/dist/gates/hallucinated-imports.js +10 -678
- package/dist/gates/phantom-apis-data.d.ts +33 -0
- package/dist/gates/phantom-apis-data.js +398 -0
- package/dist/gates/phantom-apis.js +1 -393
- package/dist/gates/phantom-apis.test.js +52 -0
- package/dist/gates/promise-safety-helpers.d.ts +19 -0
- package/dist/gates/promise-safety-helpers.js +101 -0
- package/dist/gates/promise-safety-rules.d.ts +7 -0
- package/dist/gates/promise-safety-rules.js +19 -0
- package/dist/gates/promise-safety.d.ts +1 -21
- package/dist/gates/promise-safety.js +51 -257
- package/dist/gates/runner.d.ts +4 -2
- package/dist/gates/runner.js +46 -1
- package/dist/gates/test-quality-lang.d.ts +30 -0
- package/dist/gates/test-quality-lang.js +188 -0
- package/dist/gates/test-quality.d.ts +0 -14
- package/dist/gates/test-quality.js +13 -186
- package/dist/index.d.ts +10 -0
- package/dist/index.js +12 -2
- package/dist/inference/cloud-provider.d.ts +34 -0
- package/dist/inference/cloud-provider.js +126 -0
- package/dist/inference/index.d.ts +17 -0
- package/dist/inference/index.js +23 -0
- package/dist/inference/model-manager.d.ts +26 -0
- package/dist/inference/model-manager.js +106 -0
- package/dist/inference/sidecar-provider.d.ts +15 -0
- package/dist/inference/sidecar-provider.js +153 -0
- package/dist/inference/types.d.ts +77 -0
- package/dist/inference/types.js +19 -0
- package/dist/pattern-index/indexer-helpers.d.ts +38 -0
- package/dist/pattern-index/indexer-helpers.js +111 -0
- package/dist/pattern-index/indexer-lang.d.ts +13 -0
- package/dist/pattern-index/indexer-lang.js +244 -0
- package/dist/pattern-index/indexer-ts.d.ts +22 -0
- package/dist/pattern-index/indexer-ts.js +258 -0
- package/dist/pattern-index/indexer.d.ts +4 -106
- package/dist/pattern-index/indexer.js +58 -707
- package/dist/pattern-index/staleness-data.d.ts +6 -0
- package/dist/pattern-index/staleness-data.js +262 -0
- package/dist/pattern-index/staleness.js +1 -258
- package/dist/settings.d.ts +104 -0
- package/dist/settings.js +186 -0
- package/dist/storage/db.d.ts +16 -0
- package/dist/storage/db.js +132 -0
- package/dist/storage/findings.d.ts +14 -0
- package/dist/storage/findings.js +38 -0
- package/dist/storage/index.d.ts +9 -0
- package/dist/storage/index.js +8 -0
- package/dist/storage/patterns.d.ts +35 -0
- package/dist/storage/patterns.js +62 -0
- package/dist/storage/scans.d.ts +42 -0
- package/dist/storage/scans.js +55 -0
- package/dist/templates/index.d.ts +12 -16
- package/dist/templates/index.js +11 -527
- package/dist/templates/paradigms.d.ts +2 -0
- package/dist/templates/paradigms.js +46 -0
- package/dist/templates/presets.d.ts +14 -0
- package/dist/templates/presets.js +227 -0
- package/dist/templates/universal-config.d.ts +2 -0
- package/dist/templates/universal-config.js +190 -0
- package/dist/types/index.d.ts +438 -15
- package/dist/types/index.js +41 -1
- package/package.json +6 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { MODELS } from './types.js';
|
|
2
|
+
export { SidecarProvider } from './sidecar-provider.js';
|
|
3
|
+
export { CloudProvider } from './cloud-provider.js';
|
|
4
|
+
export { ensureModel, isModelCached, getModelPath, getModelInfo, downloadModel, getModelsDir } from './model-manager.js';
|
|
5
|
+
import { SidecarProvider } from './sidecar-provider.js';
|
|
6
|
+
import { CloudProvider } from './cloud-provider.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create the appropriate inference provider based on options.
|
|
9
|
+
*
|
|
10
|
+
* - No API key → SidecarProvider (local llama.cpp binary)
|
|
11
|
+
* - API key + any provider → CloudProvider (no restrictions, user's key, user's choice)
|
|
12
|
+
*/
|
|
13
|
+
export function createProvider(options) {
|
|
14
|
+
if (options.apiKey && options.provider && options.provider !== 'local') {
|
|
15
|
+
return new CloudProvider(options.provider, options.apiKey, {
|
|
16
|
+
baseUrl: options.apiBaseUrl,
|
|
17
|
+
modelName: options.modelName,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
// Default: local sidecar
|
|
21
|
+
const tier = options.pro ? 'pro' : 'deep';
|
|
22
|
+
return new SidecarProvider(tier);
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ModelTier, type ModelInfo } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a model is already downloaded and valid.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isModelCached(tier: ModelTier): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Get the path to a cached model.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getModelPath(tier: ModelTier): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get model info for a tier.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getModelInfo(tier: ModelTier): ModelInfo;
|
|
14
|
+
/**
|
|
15
|
+
* Download a model from HuggingFace CDN.
|
|
16
|
+
* Calls onProgress with status updates.
|
|
17
|
+
*/
|
|
18
|
+
export declare function downloadModel(tier: ModelTier, onProgress?: (message: string, percent?: number) => void): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Ensure a model is available, downloading if needed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureModel(tier: ModelTier, onProgress?: (message: string, percent?: number) => void): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Get the models directory path.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getModelsDir(): string;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Manager — handles downloading, caching, and verifying GGUF models.
|
|
3
|
+
* Models cached at ~/.rigour/models/
|
|
4
|
+
*/
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import { RIGOUR_DIR } from '../storage/db.js';
|
|
8
|
+
import { MODELS } from './types.js';
|
|
9
|
+
const MODELS_DIR = path.join(RIGOUR_DIR, 'models');
|
|
10
|
+
/**
|
|
11
|
+
* Check if a model is already downloaded and valid.
|
|
12
|
+
*/
|
|
13
|
+
export function isModelCached(tier) {
|
|
14
|
+
const model = MODELS[tier];
|
|
15
|
+
const modelPath = path.join(MODELS_DIR, model.filename);
|
|
16
|
+
if (!fs.existsSync(modelPath))
|
|
17
|
+
return false;
|
|
18
|
+
// Basic size check (within 10% tolerance)
|
|
19
|
+
const stat = fs.statSync(modelPath);
|
|
20
|
+
const tolerance = model.sizeBytes * 0.1;
|
|
21
|
+
return stat.size > model.sizeBytes - tolerance;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the path to a cached model.
|
|
25
|
+
*/
|
|
26
|
+
export function getModelPath(tier) {
|
|
27
|
+
return path.join(MODELS_DIR, MODELS[tier].filename);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get model info for a tier.
|
|
31
|
+
*/
|
|
32
|
+
export function getModelInfo(tier) {
|
|
33
|
+
return MODELS[tier];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Download a model from HuggingFace CDN.
|
|
37
|
+
* Calls onProgress with status updates.
|
|
38
|
+
*/
|
|
39
|
+
export async function downloadModel(tier, onProgress) {
|
|
40
|
+
const model = MODELS[tier];
|
|
41
|
+
const destPath = path.join(MODELS_DIR, model.filename);
|
|
42
|
+
const tempPath = destPath + '.download';
|
|
43
|
+
fs.ensureDirSync(MODELS_DIR);
|
|
44
|
+
// Already cached
|
|
45
|
+
if (isModelCached(tier)) {
|
|
46
|
+
onProgress?.(`Model ${model.name} already cached`, 100);
|
|
47
|
+
return destPath;
|
|
48
|
+
}
|
|
49
|
+
onProgress?.(`Downloading ${model.name} (${model.sizeHuman})...`, 0);
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetch(model.url);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
54
|
+
}
|
|
55
|
+
const contentLength = parseInt(response.headers.get('content-length') || '0', 10);
|
|
56
|
+
const reader = response.body?.getReader();
|
|
57
|
+
if (!reader)
|
|
58
|
+
throw new Error('No response body');
|
|
59
|
+
const writeStream = fs.createWriteStream(tempPath);
|
|
60
|
+
let downloaded = 0;
|
|
61
|
+
let lastProgressPercent = 0;
|
|
62
|
+
while (true) {
|
|
63
|
+
const { done, value } = await reader.read();
|
|
64
|
+
if (done)
|
|
65
|
+
break;
|
|
66
|
+
writeStream.write(Buffer.from(value));
|
|
67
|
+
downloaded += value.length;
|
|
68
|
+
if (contentLength > 0) {
|
|
69
|
+
const percent = Math.round((downloaded / contentLength) * 100);
|
|
70
|
+
if (percent >= lastProgressPercent + 5) { // Report every 5%
|
|
71
|
+
lastProgressPercent = percent;
|
|
72
|
+
onProgress?.(`Downloading ${model.name}: ${percent}%`, percent);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
writeStream.end();
|
|
77
|
+
await new Promise((resolve, reject) => {
|
|
78
|
+
writeStream.on('finish', resolve);
|
|
79
|
+
writeStream.on('error', reject);
|
|
80
|
+
});
|
|
81
|
+
// Atomic rename
|
|
82
|
+
fs.renameSync(tempPath, destPath);
|
|
83
|
+
onProgress?.(`Model ${model.name} ready`, 100);
|
|
84
|
+
return destPath;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Clean up temp file on failure
|
|
88
|
+
fs.removeSync(tempPath);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Ensure a model is available, downloading if needed.
|
|
94
|
+
*/
|
|
95
|
+
export async function ensureModel(tier, onProgress) {
|
|
96
|
+
if (isModelCached(tier)) {
|
|
97
|
+
return getModelPath(tier);
|
|
98
|
+
}
|
|
99
|
+
return downloadModel(tier, onProgress);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get the models directory path.
|
|
103
|
+
*/
|
|
104
|
+
export function getModelsDir() {
|
|
105
|
+
return MODELS_DIR;
|
|
106
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { InferenceProvider, InferenceOptions, ModelTier } from './types.js';
|
|
2
|
+
export declare class SidecarProvider implements InferenceProvider {
|
|
3
|
+
readonly name = "sidecar";
|
|
4
|
+
private binaryPath;
|
|
5
|
+
private modelPath;
|
|
6
|
+
private tier;
|
|
7
|
+
private threads;
|
|
8
|
+
constructor(tier?: ModelTier, threads?: number);
|
|
9
|
+
isAvailable(): Promise<boolean>;
|
|
10
|
+
setup(onProgress?: (message: string) => void): Promise<void>;
|
|
11
|
+
analyze(prompt: string, options?: InferenceOptions): Promise<string>;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
private getPlatformKey;
|
|
14
|
+
private resolveBinaryPath;
|
|
15
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar Binary Provider — runs inference via pre-compiled llama.cpp binary.
|
|
3
|
+
* Binary ships as @rigour/brain-{platform} optional npm dependency.
|
|
4
|
+
* Falls back to PATH lookup for development/manual installs.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import fs from 'fs-extra';
|
|
11
|
+
import { ensureModel, isModelCached, getModelInfo } from './model-manager.js';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
/** Platform → npm package mapping */
|
|
14
|
+
const PLATFORM_PACKAGES = {
|
|
15
|
+
'darwin-arm64': '@rigour/brain-darwin-arm64',
|
|
16
|
+
'darwin-x64': '@rigour/brain-darwin-x64',
|
|
17
|
+
'linux-x64': '@rigour/brain-linux-x64',
|
|
18
|
+
'linux-arm64': '@rigour/brain-linux-arm64',
|
|
19
|
+
'win32-x64': '@rigour/brain-win-x64',
|
|
20
|
+
};
|
|
21
|
+
export class SidecarProvider {
|
|
22
|
+
name = 'sidecar';
|
|
23
|
+
binaryPath = null;
|
|
24
|
+
modelPath = null;
|
|
25
|
+
tier;
|
|
26
|
+
threads;
|
|
27
|
+
constructor(tier = 'deep', threads = 4) {
|
|
28
|
+
this.tier = tier;
|
|
29
|
+
this.threads = threads;
|
|
30
|
+
}
|
|
31
|
+
async isAvailable() {
|
|
32
|
+
const binary = await this.resolveBinaryPath();
|
|
33
|
+
return binary !== null;
|
|
34
|
+
}
|
|
35
|
+
async setup(onProgress) {
|
|
36
|
+
// 1. Check/resolve binary
|
|
37
|
+
this.binaryPath = await this.resolveBinaryPath();
|
|
38
|
+
if (this.binaryPath) {
|
|
39
|
+
onProgress?.('✓ Inference engine ready');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
onProgress?.('⚠ Inference engine not found. Install @rigour/brain-* or add llama-cli to PATH');
|
|
43
|
+
throw new Error('Sidecar binary not found. Run: npm install @rigour/brain-' + this.getPlatformKey());
|
|
44
|
+
}
|
|
45
|
+
// 2. Ensure model is downloaded
|
|
46
|
+
if (!isModelCached(this.tier)) {
|
|
47
|
+
const modelInfo = getModelInfo(this.tier);
|
|
48
|
+
onProgress?.(`⬇ Downloading analysis model (${modelInfo.sizeHuman})...`);
|
|
49
|
+
}
|
|
50
|
+
this.modelPath = await ensureModel(this.tier, (msg, percent) => {
|
|
51
|
+
if (percent !== undefined && percent < 100) {
|
|
52
|
+
onProgress?.(` ${msg}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
onProgress?.('✓ Model ready');
|
|
56
|
+
}
|
|
57
|
+
async analyze(prompt, options) {
|
|
58
|
+
if (!this.binaryPath || !this.modelPath) {
|
|
59
|
+
throw new Error('Provider not set up. Call setup() first.');
|
|
60
|
+
}
|
|
61
|
+
const args = [
|
|
62
|
+
'--model', this.modelPath,
|
|
63
|
+
'--prompt', prompt,
|
|
64
|
+
'--n-predict', String(options?.maxTokens || 512),
|
|
65
|
+
'--threads', String(this.threads),
|
|
66
|
+
'--temp', String(options?.temperature || 0.1),
|
|
67
|
+
'--no-display-prompt', // Don't echo the prompt
|
|
68
|
+
'--log-disable', // Suppress llama.cpp logging
|
|
69
|
+
];
|
|
70
|
+
// JSON grammar constraint if available
|
|
71
|
+
if (options?.jsonMode) {
|
|
72
|
+
args.push('--json');
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const { stdout, stderr } = await execFileAsync(this.binaryPath, args, {
|
|
76
|
+
timeout: options?.timeout || 60000,
|
|
77
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
78
|
+
env: { ...process.env, LLAMA_LOG_DISABLE: '1' },
|
|
79
|
+
});
|
|
80
|
+
// llama.cpp sometimes outputs to stderr for diagnostics — ignore
|
|
81
|
+
return stdout.trim();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error.killed) {
|
|
85
|
+
throw new Error(`Inference timed out after ${(options?.timeout || 60000) / 1000}s`);
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Inference failed: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
dispose() {
|
|
91
|
+
// No persistent process to clean up
|
|
92
|
+
this.binaryPath = null;
|
|
93
|
+
this.modelPath = null;
|
|
94
|
+
}
|
|
95
|
+
getPlatformKey() {
|
|
96
|
+
return `${os.platform()}-${os.arch()}`;
|
|
97
|
+
}
|
|
98
|
+
async resolveBinaryPath() {
|
|
99
|
+
const platformKey = this.getPlatformKey();
|
|
100
|
+
// Strategy 1: Check @rigour/brain-{platform} optional dependency
|
|
101
|
+
const packageName = PLATFORM_PACKAGES[platformKey];
|
|
102
|
+
if (packageName) {
|
|
103
|
+
try {
|
|
104
|
+
// Try to resolve from node_modules
|
|
105
|
+
const possiblePaths = [
|
|
106
|
+
// From rigour-core node_modules
|
|
107
|
+
path.join(__dirname, '..', '..', '..', 'node_modules', ...packageName.split('/'), 'bin', 'rigour-brain'),
|
|
108
|
+
// From global node_modules
|
|
109
|
+
path.join(os.homedir(), '.npm-global', 'lib', 'node_modules', ...packageName.split('/'), 'bin', 'rigour-brain'),
|
|
110
|
+
];
|
|
111
|
+
for (const p of possiblePaths) {
|
|
112
|
+
const binPath = os.platform() === 'win32' ? p + '.exe' : p;
|
|
113
|
+
if (await fs.pathExists(binPath)) {
|
|
114
|
+
return binPath;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Package not installed
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Strategy 2: Check ~/.rigour/bin/
|
|
123
|
+
const localBin = path.join(os.homedir(), '.rigour', 'bin', 'rigour-brain');
|
|
124
|
+
const localBinPath = os.platform() === 'win32' ? localBin + '.exe' : localBin;
|
|
125
|
+
if (await fs.pathExists(localBinPath)) {
|
|
126
|
+
return localBinPath;
|
|
127
|
+
}
|
|
128
|
+
// Strategy 3: Check PATH for llama-cli (llama.cpp CLI)
|
|
129
|
+
try {
|
|
130
|
+
const { stdout } = await execFileAsync('which', ['llama-cli']);
|
|
131
|
+
const llamaPath = stdout.trim();
|
|
132
|
+
if (llamaPath && await fs.pathExists(llamaPath)) {
|
|
133
|
+
return llamaPath;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Not in PATH
|
|
138
|
+
}
|
|
139
|
+
// Strategy 4: Check for llama.cpp server-style binary names
|
|
140
|
+
const altNames = ['llama-cli', 'llama', 'main'];
|
|
141
|
+
for (const name of altNames) {
|
|
142
|
+
try {
|
|
143
|
+
const { stdout } = await execFileAsync('which', [name]);
|
|
144
|
+
if (stdout.trim())
|
|
145
|
+
return stdout.trim();
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Continue
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inference provider interface for Rigour deep analysis.
|
|
3
|
+
* Supports sidecar binary (local llama.cpp), cloud APIs (Claude/OpenAI).
|
|
4
|
+
*/
|
|
5
|
+
import type { Severity } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Abstract inference provider — all backends implement this.
|
|
8
|
+
*/
|
|
9
|
+
export interface InferenceProvider {
|
|
10
|
+
/** Provider name for logging/reporting */
|
|
11
|
+
readonly name: string;
|
|
12
|
+
/** Check if this provider is available (binary exists, API key valid, etc.) */
|
|
13
|
+
isAvailable(): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* One-time setup: download model, verify binary, etc.
|
|
16
|
+
* Should show progress to user via callback.
|
|
17
|
+
*/
|
|
18
|
+
setup(onProgress?: (message: string) => void): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Run inference on a prompt. Returns raw text response.
|
|
21
|
+
* Provider handles tokenization, temperature, etc.
|
|
22
|
+
*/
|
|
23
|
+
analyze(prompt: string, options?: InferenceOptions): Promise<string>;
|
|
24
|
+
/** Clean up resources (kill process, close connection) */
|
|
25
|
+
dispose(): void;
|
|
26
|
+
}
|
|
27
|
+
export interface InferenceOptions {
|
|
28
|
+
maxTokens?: number;
|
|
29
|
+
temperature?: number;
|
|
30
|
+
timeout?: number;
|
|
31
|
+
jsonMode?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A single finding from deep LLM analysis.
|
|
35
|
+
*/
|
|
36
|
+
export interface DeepFinding {
|
|
37
|
+
/** Category like 'srp_violation', 'god_function', 'dry_violation' */
|
|
38
|
+
category: string;
|
|
39
|
+
/** Severity level */
|
|
40
|
+
severity: Severity;
|
|
41
|
+
/** Relative file path */
|
|
42
|
+
file: string;
|
|
43
|
+
/** Line number (if available) */
|
|
44
|
+
line?: number;
|
|
45
|
+
/** Human-readable description of the issue */
|
|
46
|
+
description: string;
|
|
47
|
+
/** Actionable suggestion for how to fix */
|
|
48
|
+
suggestion: string;
|
|
49
|
+
/** LLM confidence score 0.0-1.0 */
|
|
50
|
+
confidence: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Result of a deep analysis batch.
|
|
54
|
+
*/
|
|
55
|
+
export interface DeepAnalysisResult {
|
|
56
|
+
findings: DeepFinding[];
|
|
57
|
+
model: string;
|
|
58
|
+
tokensUsed?: number;
|
|
59
|
+
durationMs: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Available model tiers.
|
|
63
|
+
*/
|
|
64
|
+
export type ModelTier = 'deep' | 'pro';
|
|
65
|
+
/**
|
|
66
|
+
* Model info for download/caching.
|
|
67
|
+
*/
|
|
68
|
+
export interface ModelInfo {
|
|
69
|
+
tier: ModelTier;
|
|
70
|
+
name: string;
|
|
71
|
+
filename: string;
|
|
72
|
+
url: string;
|
|
73
|
+
sizeBytes: number;
|
|
74
|
+
sizeHuman: string;
|
|
75
|
+
}
|
|
76
|
+
/** All supported model definitions */
|
|
77
|
+
export declare const MODELS: Record<ModelTier, ModelInfo>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** All supported model definitions */
|
|
2
|
+
export const MODELS = {
|
|
3
|
+
deep: {
|
|
4
|
+
tier: 'deep',
|
|
5
|
+
name: 'Qwen2.5-Coder-0.5B-Instruct',
|
|
6
|
+
filename: 'qwen2.5-coder-0.5b-instruct-q4_k_m.gguf',
|
|
7
|
+
url: 'https://huggingface.co/Qwen/Qwen2.5-Coder-0.5B-Instruct-GGUF/resolve/main/qwen2.5-coder-0.5b-instruct-q4_k_m.gguf',
|
|
8
|
+
sizeBytes: 350_000_000,
|
|
9
|
+
sizeHuman: '350MB',
|
|
10
|
+
},
|
|
11
|
+
pro: {
|
|
12
|
+
tier: 'pro',
|
|
13
|
+
name: 'Qwen2.5-Coder-1.5B-Instruct',
|
|
14
|
+
filename: 'qwen2.5-coder-1.5b-instruct-q4_k_m.gguf',
|
|
15
|
+
url: 'https://huggingface.co/Qwen/Qwen2.5-Coder-1.5B-Instruct-GGUF/resolve/main/qwen2.5-coder-1.5b-instruct-q4_k_m.gguf',
|
|
16
|
+
sizeBytes: 900_000_000,
|
|
17
|
+
sizeHuman: '900MB',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Indexer — Pure Utility Helpers
|
|
3
|
+
*
|
|
4
|
+
* Standalone pure functions shared across language extractors and the main
|
|
5
|
+
* indexer class. No class state is referenced here.
|
|
6
|
+
*/
|
|
7
|
+
import type { PatternEntry, PatternType } from './types.js';
|
|
8
|
+
/** SHA-256 of `content`, truncated to 16 hex chars. */
|
|
9
|
+
export declare function hashContent(content: string): string;
|
|
10
|
+
export interface PatternEntryParams {
|
|
11
|
+
type: PatternType;
|
|
12
|
+
name: string;
|
|
13
|
+
file: string;
|
|
14
|
+
line: number;
|
|
15
|
+
endLine: number;
|
|
16
|
+
signature: string;
|
|
17
|
+
description: string;
|
|
18
|
+
keywords: string[];
|
|
19
|
+
content: string;
|
|
20
|
+
exported: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Build a complete PatternEntry from constituent parts. */
|
|
23
|
+
export declare function createPatternEntry(params: PatternEntryParams): PatternEntry;
|
|
24
|
+
/** Split camelCase / PascalCase / snake_case names into unique lowercase words. */
|
|
25
|
+
export declare function extractKeywords(name: string): string[];
|
|
26
|
+
/** Walk forward from `startIndex` and return the line index after the closing brace. */
|
|
27
|
+
export declare function findBraceBlockEnd(lines: string[], startIndex: number): number;
|
|
28
|
+
/** Return the source lines for a brace-delimited block starting at `startIndex`. */
|
|
29
|
+
export declare function getBraceBlockContent(lines: string[], startIndex: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* Collect consecutive `//` comments immediately above `startIndex` (Go / Rust style).
|
|
32
|
+
* Walks upward until a non-comment line is encountered.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getCOMLineComments(lines: string[], startIndex: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Extract the first JavaDoc `/** … *\/` comment block found above `startIndex`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getJavaDoc(lines: string[], startIndex: number): string;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Indexer — Pure Utility Helpers
|
|
3
|
+
*
|
|
4
|
+
* Standalone pure functions shared across language extractors and the main
|
|
5
|
+
* indexer class. No class state is referenced here.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Hashing / ID generation
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/** SHA-256 of `content`, truncated to 16 hex chars. */
|
|
12
|
+
export function hashContent(content) {
|
|
13
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
14
|
+
}
|
|
15
|
+
/** Build a complete PatternEntry from constituent parts. */
|
|
16
|
+
export function createPatternEntry(params) {
|
|
17
|
+
const id = hashContent(`${params.file}:${params.name}:${params.line}`);
|
|
18
|
+
const hash = hashContent(params.content);
|
|
19
|
+
return {
|
|
20
|
+
id,
|
|
21
|
+
type: params.type,
|
|
22
|
+
name: params.name,
|
|
23
|
+
file: params.file,
|
|
24
|
+
line: params.line,
|
|
25
|
+
endLine: params.endLine,
|
|
26
|
+
signature: params.signature,
|
|
27
|
+
description: params.description,
|
|
28
|
+
keywords: params.keywords,
|
|
29
|
+
hash,
|
|
30
|
+
exported: params.exported,
|
|
31
|
+
usageCount: 0,
|
|
32
|
+
indexedAt: new Date().toISOString(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Keyword extraction
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/** Split camelCase / PascalCase / snake_case names into unique lowercase words. */
|
|
39
|
+
export function extractKeywords(name) {
|
|
40
|
+
const words = name
|
|
41
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
42
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.split(/[\s_-]+/)
|
|
45
|
+
.filter(w => w.length > 1);
|
|
46
|
+
return [...new Set(words)];
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Brace-based block helpers (Go, Rust, JVM, C-style)
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
/** Walk forward from `startIndex` and return the line index after the closing brace. */
|
|
52
|
+
export function findBraceBlockEnd(lines, startIndex) {
|
|
53
|
+
let braceCount = 0;
|
|
54
|
+
let started = false;
|
|
55
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
56
|
+
const line = lines[i];
|
|
57
|
+
if (line.includes('{')) {
|
|
58
|
+
braceCount += (line.match(/\{/g) || []).length;
|
|
59
|
+
started = true;
|
|
60
|
+
}
|
|
61
|
+
if (line.includes('}')) {
|
|
62
|
+
braceCount -= (line.match(/\}/g) || []).length;
|
|
63
|
+
}
|
|
64
|
+
if (started && braceCount === 0)
|
|
65
|
+
return i + 1;
|
|
66
|
+
}
|
|
67
|
+
return lines.length;
|
|
68
|
+
}
|
|
69
|
+
/** Return the source lines for a brace-delimited block starting at `startIndex`. */
|
|
70
|
+
export function getBraceBlockContent(lines, startIndex) {
|
|
71
|
+
const end = findBraceBlockEnd(lines, startIndex);
|
|
72
|
+
return lines.slice(startIndex, end).join('\n');
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Comment extraction helpers
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
/**
|
|
78
|
+
* Collect consecutive `//` comments immediately above `startIndex` (Go / Rust style).
|
|
79
|
+
* Walks upward until a non-comment line is encountered.
|
|
80
|
+
*/
|
|
81
|
+
export function getCOMLineComments(lines, startIndex) {
|
|
82
|
+
const comments = [];
|
|
83
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
84
|
+
const line = lines[i].trim();
|
|
85
|
+
if (line.startsWith('//')) {
|
|
86
|
+
comments.unshift(line.replace('//', '').trim());
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return comments.join(' ');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extract the first JavaDoc `/** … *\/` comment block found above `startIndex`.
|
|
96
|
+
*/
|
|
97
|
+
export function getJavaDoc(lines, startIndex) {
|
|
98
|
+
const comments = [];
|
|
99
|
+
let inDoc = false;
|
|
100
|
+
for (let i = startIndex; i >= 0; i--) {
|
|
101
|
+
const line = lines[i].trim();
|
|
102
|
+
if (line.endsWith('*/'))
|
|
103
|
+
inDoc = true;
|
|
104
|
+
if (inDoc) {
|
|
105
|
+
comments.unshift(line.replace('/**', '').replace('*/', '').replace(/^\*/, '').trim());
|
|
106
|
+
}
|
|
107
|
+
if (line.startsWith('/**'))
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
return comments.join(' ');
|
|
111
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Indexer — Language-Specific Extractors
|
|
3
|
+
*
|
|
4
|
+
* Standalone extraction functions for Go, Rust, JVM (Java/Kotlin/C#),
|
|
5
|
+
* Python, and a generic C-style fallback. Each function is pure and
|
|
6
|
+
* receives all required context as parameters.
|
|
7
|
+
*/
|
|
8
|
+
import type { PatternEntry } from './types.js';
|
|
9
|
+
export declare function extractGoPatterns(filePath: string, content: string, rootDir: string): PatternEntry[];
|
|
10
|
+
export declare function extractRustPatterns(filePath: string, content: string, rootDir: string): PatternEntry[];
|
|
11
|
+
export declare function extractJVMStylePatterns(filePath: string, content: string, rootDir: string): PatternEntry[];
|
|
12
|
+
export declare function extractGenericCPatterns(_filePath: string, _content: string): PatternEntry[];
|
|
13
|
+
export declare function extractPythonPatterns(filePath: string, content: string, rootDir: string, minNameLength: number): PatternEntry[];
|