@rigour-labs/core 6.4.0 → 6.4.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/deep/changed-functions.d.ts +15 -0
- package/dist/deep/changed-functions.js +34 -0
- package/dist/deep/code-pass.d.ts +10 -0
- package/dist/deep/code-pass.js +37 -2
- package/dist/deep/code-pass.test.d.ts +1 -0
- package/dist/deep/code-pass.test.js +69 -0
- package/dist/deep/code-review-prompt.d.ts +1 -1
- package/dist/deep/code-review-prompt.js +3 -2
- package/dist/deep/diff-tests/calls.d.ts +8 -0
- package/dist/deep/diff-tests/calls.js +85 -0
- package/dist/deep/diff-tests/calls.test.d.ts +1 -0
- package/dist/deep/diff-tests/calls.test.js +33 -0
- package/dist/deep/diff-tests/run.d.ts +21 -0
- package/dist/deep/diff-tests/run.js +178 -0
- package/dist/deep/diff-tests/run.test.d.ts +1 -0
- package/dist/deep/diff-tests/run.test.js +58 -0
- package/dist/deep/reference-pack.d.ts +19 -0
- package/dist/deep/reference-pack.js +101 -0
- package/dist/deep/reference-pack.test.d.ts +1 -0
- package/dist/deep/reference-pack.test.js +46 -0
- package/dist/deep/review-context-export.d.ts +11 -0
- package/dist/deep/review-context-export.js +31 -0
- package/dist/deep/review-context-export.test.d.ts +1 -0
- package/dist/deep/review-context-export.test.js +32 -0
- package/dist/deep/self-check.d.ts +21 -0
- package/dist/deep/self-check.js +49 -0
- package/dist/firewall/trusted-control.d.ts +1 -2
- package/dist/gates/deep-analysis.d.ts +2 -0
- package/dist/gates/deep-analysis.js +12 -0
- package/dist/gates/deep-runner.js +2 -1
- package/dist/gates/semantic-bugs.js +4 -3
- package/dist/gates/semantic-bugs.test.js +6 -0
- package/dist/hooks/checker.d.ts +1 -2
- package/dist/hooks/index.d.ts +2 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.js +4 -5
- package/dist/inference/index.d.ts +1 -1
- package/dist/inference/index.js +3 -5
- package/dist/inference/local-model.test.d.ts +1 -0
- package/dist/inference/local-model.test.js +23 -0
- package/dist/inference/sidecar-provider.d.ts +10 -1
- package/dist/inference/sidecar-provider.js +28 -6
- package/dist/inference/types.d.ts +8 -1
- package/dist/inference/types.js +14 -0
- package/dist/inference/types.test.d.ts +1 -0
- package/dist/inference/types.test.js +19 -0
- package/dist/review/diff-test-findings.d.ts +3 -0
- package/dist/review/diff-test-findings.js +41 -0
- package/dist/review/review.d.ts +4 -2
- package/dist/review/review.js +5 -2
- package/dist/semantic/benchmark.js +2 -2
- package/dist/semantic/benchmark.test.js +5 -1
- package/dist/semantic/engine.d.ts +3 -0
- package/dist/semantic/engine.js +8 -2
- package/dist/semantic/failure-handling.d.ts +12 -0
- package/dist/semantic/failure-handling.js +41 -0
- package/dist/semantic/intent/parallel-reads.js +2 -30
- package/dist/semantic/project-facts.d.ts +25 -0
- package/dist/semantic/project-facts.js +104 -0
- package/dist/semantic/project-facts.test.d.ts +1 -0
- package/dist/semantic/project-facts.test.js +45 -0
- package/dist/semantic/rules/ecosystem/deps-codegen-undeclared-import.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/deps-codegen-undeclared-import.js +71 -0
- package/dist/semantic/rules/ecosystem/deps-internal-symbol.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/deps-internal-symbol.js +36 -0
- package/dist/semantic/rules/ecosystem/dom-self-query-in-component.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/dom-self-query-in-component.js +60 -0
- package/dist/semantic/rules/ecosystem/env-bare-browser-global.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/env-bare-browser-global.js +57 -0
- package/dist/semantic/rules/ecosystem/exports-condition-parity.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/exports-condition-parity.js +57 -0
- package/dist/semantic/rules/ecosystem/exports-forgotten-type.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/exports-forgotten-type.js +128 -0
- package/dist/semantic/rules/ecosystem/imports-barrel-cycle.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/imports-barrel-cycle.js +78 -0
- package/dist/semantic/rules/ecosystem/index.d.ts +15 -0
- package/dist/semantic/rules/ecosystem/index.js +22 -0
- package/dist/semantic/rules/ecosystem/paths-unnormalized-module-key.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/paths-unnormalized-module-key.js +87 -0
- package/dist/semantic/rules/ecosystem/react-inline-html-object.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/react-inline-html-object.js +30 -0
- package/dist/semantic/rules/ecosystem/shared.d.ts +18 -0
- package/dist/semantic/rules/ecosystem/shared.js +43 -0
- package/dist/semantic/rules/ecosystem/solid-jsx-and-conditional.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/solid-jsx-and-conditional.js +36 -0
- package/dist/semantic/rules/ecosystem/ts-internal-in-public-signature.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/ts-internal-in-public-signature.js +66 -0
- package/dist/semantic/rules/ecosystem/vite-rollup-only-hook-field.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/vite-rollup-only-hook-field.js +31 -0
- package/dist/semantic/rules/ecosystem/vue-static-computed.d.ts +2 -0
- package/dist/semantic/rules/ecosystem/vue-static-computed.js +51 -0
- package/dist/semantic/sites/call-sites.d.ts +25 -0
- package/dist/semantic/sites/call-sites.js +69 -0
- package/dist/semantic/sites/call-sites.test.d.ts +1 -0
- package/dist/semantic/sites/call-sites.test.js +46 -0
- package/dist/semantic/sites/export.d.ts +2 -0
- package/dist/semantic/sites/export.js +22 -0
- package/dist/semantic/types.d.ts +4 -0
- package/dist/services/engineering-knowledge-graph.d.ts +1 -2
- package/dist/templates/universal-config.js +1 -0
- package/dist/types/index.d.ts +31 -8
- package/dist/types/index.js +2 -1
- package/dist/utils/diff-removed.test.d.ts +1 -0
- package/dist/utils/diff-removed.test.js +29 -0
- package/dist/utils/diff.d.ts +12 -0
- package/dist/utils/diff.js +26 -0
- package/package.json +6 -6
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference material for reviewing a changed file: what the change means,
|
|
3
|
+
* beyond the file itself.
|
|
4
|
+
*
|
|
5
|
+
* Most bugs reviewers miss need facts outside the changed lines: a guard the
|
|
6
|
+
* change deleted, what a called function actually does, who calls a changed
|
|
7
|
+
* export, what the PR says it intends. The pack carries, within a character
|
|
8
|
+
* budget and in this priority:
|
|
9
|
+
* 1. the PR description,
|
|
10
|
+
* 2. lines the change removed from this file,
|
|
11
|
+
* 3. definitions of functions the changed code calls (resolved by the type checker),
|
|
12
|
+
* 4. call sites of changed exported functions elsewhere in the repository.
|
|
13
|
+
*
|
|
14
|
+
* It is reference only: findings must still cite a line of the reviewed file.
|
|
15
|
+
* Its source joins the identifier check, so a finding may name a callee.
|
|
16
|
+
*/
|
|
17
|
+
import { execFileSync } from 'child_process';
|
|
18
|
+
import path from 'path';
|
|
19
|
+
import ts from 'typescript';
|
|
20
|
+
import { calledFunction, forEachNode, lineOf } from '../semantic/ast.js';
|
|
21
|
+
import { changedFunctions, functionName, isExported } from './changed-functions.js';
|
|
22
|
+
import { loadProjectConfig, programBatches } from '../semantic/program.js';
|
|
23
|
+
const PR_BODY_CHARS = 1500;
|
|
24
|
+
const MAX_CALLEES = 6;
|
|
25
|
+
const CALLEE_LINES = 40;
|
|
26
|
+
const MAX_CALLERS = 5;
|
|
27
|
+
const TS_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/i;
|
|
28
|
+
export function buildReferencePack(input) {
|
|
29
|
+
const sections = [];
|
|
30
|
+
const sources = [];
|
|
31
|
+
let budget = input.maxChars;
|
|
32
|
+
const add = (title, body, source = body) => {
|
|
33
|
+
const block = `${title}\n${body}`;
|
|
34
|
+
if (!body.trim() || block.length > budget)
|
|
35
|
+
return;
|
|
36
|
+
sections.push(block);
|
|
37
|
+
sources.push(source);
|
|
38
|
+
budget -= block.length + 2;
|
|
39
|
+
};
|
|
40
|
+
if (input.prBody?.trim())
|
|
41
|
+
add('PR DESCRIPTION (what the author intends):', input.prBody.trim().slice(0, PR_BODY_CHARS));
|
|
42
|
+
for (const block of input.removed ?? []) {
|
|
43
|
+
add(`REMOVED by this change, just before line ${block.line} of ${input.file}:`, block.text.map(l => `- ${l}`).join('\n'), block.text.join('\n'));
|
|
44
|
+
}
|
|
45
|
+
const change = changeOf(input);
|
|
46
|
+
if (change) {
|
|
47
|
+
for (const callee of calleeDefinitions(input.cwd, change))
|
|
48
|
+
add(`CALLED: ${callee.label}`, callee.text);
|
|
49
|
+
for (const caller of callersOfChangedExports(input.cwd, input.file, change))
|
|
50
|
+
add(`CALLER of ${caller.name}:`, caller.text);
|
|
51
|
+
}
|
|
52
|
+
return { text: sections.join('\n\n'), source: sources.join('\n'), sections };
|
|
53
|
+
}
|
|
54
|
+
function changeOf(input) {
|
|
55
|
+
const focus = input.focusLines ?? [];
|
|
56
|
+
if (focus.length === 0 || !TS_FILE.test(input.file))
|
|
57
|
+
return undefined;
|
|
58
|
+
const absolute = path.resolve(input.cwd, input.file);
|
|
59
|
+
const [program] = programBatches([absolute], loadProjectConfig(input.cwd).options, 1);
|
|
60
|
+
const sourceFile = program?.getSourceFile(absolute);
|
|
61
|
+
if (!program || !sourceFile)
|
|
62
|
+
return undefined;
|
|
63
|
+
return { sourceFile, checker: program.getTypeChecker(), functions: changedFunctions(sourceFile, focus) };
|
|
64
|
+
}
|
|
65
|
+
/** Definitions, in other files, of functions called from the changed functions. */
|
|
66
|
+
function calleeDefinitions(cwd, change) {
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
const snippets = [];
|
|
69
|
+
for (const fn of change.functions) {
|
|
70
|
+
forEachNode(fn, (node) => {
|
|
71
|
+
if (snippets.length >= MAX_CALLEES || !ts.isCallExpression(node))
|
|
72
|
+
return;
|
|
73
|
+
const target = calledFunction(change.checker, node);
|
|
74
|
+
const where = target?.getSourceFile();
|
|
75
|
+
if (!target || !where || seen.has(target) || where === change.sourceFile || where.isDeclarationFile)
|
|
76
|
+
return;
|
|
77
|
+
seen.add(target);
|
|
78
|
+
const lines = target.getText(where).split('\n');
|
|
79
|
+
const text = lines.slice(0, CALLEE_LINES).join('\n') + (lines.length > CALLEE_LINES ? `\n… [${lines.length - CALLEE_LINES} more lines]` : '');
|
|
80
|
+
snippets.push({ label: `${path.relative(cwd, where.fileName).split(path.sep).join('/')}:${lineOf(target)}`, text });
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return snippets;
|
|
84
|
+
}
|
|
85
|
+
/** Call sites, outside this file, of exported functions the change touched. */
|
|
86
|
+
function callersOfChangedExports(cwd, file, change) {
|
|
87
|
+
const names = change.functions.filter(isExported).map(functionName).filter((n) => !!n);
|
|
88
|
+
return names.map(name => ({ name, text: grepCallers(cwd, file, name) })).filter(c => c.text);
|
|
89
|
+
}
|
|
90
|
+
function grepCallers(cwd, file, name) {
|
|
91
|
+
try {
|
|
92
|
+
const out = execFileSync('git', ['grep', '-n', '-E', '-e', `(^|[^A-Za-z0-9_$])${name}\\(`, '--', '*.ts', '*.tsx', '*.js', '*.jsx', '*.mjs', `:!${file}`], {
|
|
93
|
+
cwd, encoding: 'utf8', maxBuffer: 8 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'],
|
|
94
|
+
});
|
|
95
|
+
return out.split('\n').filter(Boolean).filter(l => !/\.(?:test|spec)\./.test(l)).slice(0, MAX_CALLERS)
|
|
96
|
+
.map(l => l.length > 200 ? `${l.slice(0, 200)}…` : l).join('\n');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
import { buildReferencePack } from './reference-pack.js';
|
|
7
|
+
let repo;
|
|
8
|
+
afterEach(() => { if (repo)
|
|
9
|
+
fs.rmSync(repo, { recursive: true, force: true }); repo = undefined; });
|
|
10
|
+
function project() {
|
|
11
|
+
repo = fs.mkdtempSync(path.join(os.tmpdir(), 'reference-pack-'));
|
|
12
|
+
const files = {
|
|
13
|
+
'src/paths.ts': "export function cleanPath(p: string): string {\n return p.replace(/\\/+/g, '/');\n}\n",
|
|
14
|
+
'src/routes.ts': "import { cleanPath } from './paths';\nexport function routePath(dir: string, route: string): string {\n return cleanPath(`/${dir}${route}`);\n}\n",
|
|
15
|
+
'src/generator.ts': "import { routePath } from './routes';\nexport const home = routePath('.', '/');\n",
|
|
16
|
+
};
|
|
17
|
+
for (const [name, text] of Object.entries(files)) {
|
|
18
|
+
fs.mkdirSync(path.dirname(path.join(repo, name)), { recursive: true });
|
|
19
|
+
fs.writeFileSync(path.join(repo, name), text);
|
|
20
|
+
}
|
|
21
|
+
execFileSync('git', ['init', '-q'], { cwd: repo });
|
|
22
|
+
execFileSync('git', ['add', '-A'], { cwd: repo });
|
|
23
|
+
return repo;
|
|
24
|
+
}
|
|
25
|
+
describe('buildReferencePack', () => {
|
|
26
|
+
it('carries the intent, removed lines, callee definitions and callers of a changed export', () => {
|
|
27
|
+
const cwd = project();
|
|
28
|
+
const pack = buildReferencePack({
|
|
29
|
+
cwd, file: 'src/routes.ts', focusLines: [3], maxChars: 10_000,
|
|
30
|
+
prBody: 'Normalize virtual route paths.',
|
|
31
|
+
removed: [{ line: 3, text: [" return `/${dir}${route}`;"] }],
|
|
32
|
+
});
|
|
33
|
+
expect(pack.text).toContain('PR DESCRIPTION (what the author intends):\nNormalize virtual route paths.');
|
|
34
|
+
expect(pack.text).toContain('REMOVED by this change, just before line 3 of src/routes.ts:\n- return `/${dir}${route}`;');
|
|
35
|
+
expect(pack.text).toContain('CALLED: src/paths.ts:1\nexport function cleanPath');
|
|
36
|
+
expect(pack.text).toContain("CALLER of routePath:\nsrc/generator.ts:2:export const home = routePath('.', '/');");
|
|
37
|
+
expect(pack.source).toContain('cleanPath');
|
|
38
|
+
});
|
|
39
|
+
it('stays within its budget, keeping the highest-priority sections', () => {
|
|
40
|
+
const cwd = project();
|
|
41
|
+
const pack = buildReferencePack({ cwd, file: 'src/routes.ts', focusLines: [3], maxChars: 80, prBody: 'Normalize virtual route paths.' });
|
|
42
|
+
expect(pack.text).toContain('PR DESCRIPTION');
|
|
43
|
+
expect(pack.text).not.toContain('CALLED');
|
|
44
|
+
expect(pack.text.length).toBeLessThanOrEqual(80);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ReviewContextExport {
|
|
2
|
+
file: string;
|
|
3
|
+
focusLines: number[];
|
|
4
|
+
prompt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ReviewContextOptions {
|
|
7
|
+
prBody?: string;
|
|
8
|
+
maxSourceChars?: number;
|
|
9
|
+
maxReferenceChars?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function exportReviewContexts(cwd: string, diff: string, options?: ReviewContextOptions): Promise<ReviewContextExport[]>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The exact prompt the max tier would review for each changed file of a diff.
|
|
3
|
+
*
|
|
4
|
+
* The driftbench review miner pairs these prompts with what the later fix
|
|
5
|
+
* changed, so a fine-tuned model learns from the input it will get at runtime,
|
|
6
|
+
* built by the same code (numbered source, focus segments, reference pack).
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { changedLinesByFile, parseDiff, removedByFile } from '../utils/diff.js';
|
|
11
|
+
import { buildCodeContext } from './code-context.js';
|
|
12
|
+
import { buildCodeReviewPrompt } from './code-review-prompt.js';
|
|
13
|
+
import { extractFacts } from './fact-extractor.js';
|
|
14
|
+
import { buildReferencePack } from './reference-pack.js';
|
|
15
|
+
export async function exportReviewContexts(cwd, diff, options = {}) {
|
|
16
|
+
const focus = changedLinesByFile(parseDiff(diff));
|
|
17
|
+
const removed = removedByFile(diff);
|
|
18
|
+
const files = Object.keys(focus).filter(f => focus[f].length > 0 && fs.existsSync(path.join(cwd, f)));
|
|
19
|
+
if (files.length === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const facts = await extractFacts(cwd, [], files);
|
|
22
|
+
return facts.map(fileFacts => {
|
|
23
|
+
const content = fs.readFileSync(path.join(cwd, fileFacts.path), 'utf-8');
|
|
24
|
+
const context = buildCodeContext(fileFacts, content, { maxChars: options.maxSourceChars ?? 36_000, focusLines: focus[fileFacts.path] });
|
|
25
|
+
const pack = buildReferencePack({
|
|
26
|
+
cwd, file: fileFacts.path, focusLines: focus[fileFacts.path], removed: removed[fileFacts.path],
|
|
27
|
+
prBody: options.prBody, maxChars: options.maxReferenceChars ?? 12_000,
|
|
28
|
+
});
|
|
29
|
+
return { file: fileFacts.path, focusLines: focus[fileFacts.path], prompt: buildCodeReviewPrompt(context, pack.text) };
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { buildCodeReviewPrompt } from './code-review-prompt.js';
|
|
6
|
+
import { exportReviewContexts } from './review-context-export.js';
|
|
7
|
+
let dir;
|
|
8
|
+
afterEach(() => { if (dir)
|
|
9
|
+
fs.rmSync(dir, { recursive: true, force: true }); dir = undefined; });
|
|
10
|
+
const DIFF = `diff --git a/src/total.ts b/src/total.ts
|
|
11
|
+
--- a/src/total.ts
|
|
12
|
+
+++ b/src/total.ts
|
|
13
|
+
@@ -2,2 +2,2 @@
|
|
14
|
+
let sum = 0;
|
|
15
|
+
- for (let i = 0; i < items.length; i++) sum += items[i];
|
|
16
|
+
+ for (let i = 0; i <= items.length; i++) sum += items[i];
|
|
17
|
+
`;
|
|
18
|
+
describe('exportReviewContexts', () => {
|
|
19
|
+
it('emits the review prompt for each changed file, with its focus lines and what the change removed', async () => {
|
|
20
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'review-context-'));
|
|
21
|
+
fs.mkdirSync(path.join(dir, 'src'));
|
|
22
|
+
fs.writeFileSync(path.join(dir, 'src/total.ts'), 'export function total(items: number[]) {\n let sum = 0;\n for (let i = 0; i <= items.length; i++) sum += items[i];\n return sum;\n}\n');
|
|
23
|
+
const [context, ...rest] = await exportReviewContexts(dir, DIFF, { prBody: 'Sum the basket.' });
|
|
24
|
+
expect(rest).toEqual([]);
|
|
25
|
+
expect(context.file).toBe('src/total.ts');
|
|
26
|
+
expect(context.focusLines).toEqual([3]);
|
|
27
|
+
expect(context.prompt.startsWith(buildCodeReviewPrompt({ file: '', language: '', text: '', ranges: [], source: '' }).slice(0, 60))).toBe(true);
|
|
28
|
+
expect(context.prompt).toContain('3| for (let i = 0; i <= items.length; i++) sum += items[i];');
|
|
29
|
+
expect(context.prompt).toContain('- for (let i = 0; i < items.length; i++) sum += items[i];');
|
|
30
|
+
expect(context.prompt).toContain('Sum the basket.');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-check: the model re-reads each finding against the code and confirms
|
|
3
|
+
* or withdraws it.
|
|
4
|
+
*
|
|
5
|
+
* Two review passes with the reference material in different orders raise
|
|
6
|
+
* recall (a finding one ordering misses, the other catches); asking again,
|
|
7
|
+
* finding by finding, whether it would misbehave at runtime keeps that extra
|
|
8
|
+
* recall from arriving as noise. A check that cannot run keeps the finding:
|
|
9
|
+
* an unavailable model is not evidence against it.
|
|
10
|
+
*/
|
|
11
|
+
import type { DeepFinding, InferenceOptions, InferenceProvider } from '../inference/types.js';
|
|
12
|
+
import type { CodeContext } from './code-context.js';
|
|
13
|
+
export interface SelfCheckResult {
|
|
14
|
+
kept: DeepFinding[];
|
|
15
|
+
withdrawn: number;
|
|
16
|
+
failed: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function selfCheck(provider: InferenceProvider, context: CodeContext, reference: string, findings: DeepFinding[], inference: InferenceOptions): Promise<SelfCheckResult>;
|
|
19
|
+
export declare function checkPrompt(context: CodeContext, reference: string, finding: DeepFinding): string;
|
|
20
|
+
/** true, false, or undefined when the reply is not a verdict. */
|
|
21
|
+
export declare function parseVerdict(reply: string): boolean | undefined;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const MAX_CHECKED = 8;
|
|
2
|
+
const VERDICT_SCHEMA = {
|
|
3
|
+
type: 'object',
|
|
4
|
+
properties: { real: { type: 'boolean' }, reason: { type: 'string' } },
|
|
5
|
+
required: ['real'],
|
|
6
|
+
};
|
|
7
|
+
export async function selfCheck(provider, context, reference, findings, inference) {
|
|
8
|
+
const result = { kept: [], withdrawn: 0, failed: 0 };
|
|
9
|
+
for (const [index, finding] of findings.entries()) {
|
|
10
|
+
if (index >= MAX_CHECKED) {
|
|
11
|
+
result.kept.push(finding);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const reply = await provider.analyze(checkPrompt(context, reference, finding), { ...inference, jsonSchema: VERDICT_SCHEMA });
|
|
16
|
+
if (parseVerdict(reply) === false)
|
|
17
|
+
result.withdrawn++;
|
|
18
|
+
else
|
|
19
|
+
result.kept.push(finding);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
result.failed++;
|
|
23
|
+
result.kept.push(finding);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
export function checkPrompt(context, reference, finding) {
|
|
29
|
+
return [
|
|
30
|
+
'You reported a defect in a code review. Check it against the code before it is posted.',
|
|
31
|
+
`SOURCE (line numbers on the left):\n${context.text}`,
|
|
32
|
+
reference ? `REFERENCE (not under review):\n${reference}` : '',
|
|
33
|
+
`REPORTED at ${context.file}:${finding.line}: ${finding.description}`,
|
|
34
|
+
'Is this a real defect: would this code misbehave at runtime or in production as described? '
|
|
35
|
+
+ 'Answer false if it is style, speculation about unseen callers, or already handled in the code shown. '
|
|
36
|
+
+ 'Respond ONLY with JSON: {"real": true|false, "reason": "..."}.',
|
|
37
|
+
].filter(Boolean).join('\n\n');
|
|
38
|
+
}
|
|
39
|
+
/** true, false, or undefined when the reply is not a verdict. */
|
|
40
|
+
export function parseVerdict(reply) {
|
|
41
|
+
const json = reply.slice(reply.indexOf('{'), reply.lastIndexOf('}') + 1);
|
|
42
|
+
try {
|
|
43
|
+
const value = JSON.parse(json).real;
|
|
44
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -19,7 +19,7 @@ export declare function getGatewayPolicyHash(cwd: string, config: GatewayControl
|
|
|
19
19
|
export declare function validateGatewayConfig(value: unknown): GatewayControlConfig;
|
|
20
20
|
export declare function saveGatewayConfig(cwd: string, config: GatewayControlConfig, controlRoot?: string): Promise<string>;
|
|
21
21
|
export declare function loadGatewayConfig(cwd: string, controlRoot?: string): Promise<GatewayControlConfig | null>;
|
|
22
|
-
interface GrantInput {
|
|
22
|
+
export interface GrantInput {
|
|
23
23
|
issuerId: string;
|
|
24
24
|
subjectId: string;
|
|
25
25
|
taskId: string;
|
|
@@ -42,4 +42,3 @@ export declare function consumeTrustedGrant(cwd: string, input: {
|
|
|
42
42
|
reason: string;
|
|
43
43
|
grant?: CapabilityGrant;
|
|
44
44
|
}>;
|
|
45
|
-
export {};
|
|
@@ -47,6 +47,8 @@ export declare class DeepAnalysisGate extends Gate {
|
|
|
47
47
|
run(context: GateContext): Promise<Failure[]>;
|
|
48
48
|
private setupProvider;
|
|
49
49
|
private reviewCode;
|
|
50
|
+
/** The max and cloud tiers read reference material and review twice; the small models do not. */
|
|
51
|
+
private referenceOptions;
|
|
50
52
|
private analyzeFacts;
|
|
51
53
|
private recordPass;
|
|
52
54
|
private localMemoryFindings;
|
|
@@ -32,6 +32,9 @@ const CLOUD_SETUP_TIMEOUT_MS = 120_000;
|
|
|
32
32
|
*/
|
|
33
33
|
const LOCAL_SOURCE_CHARS = 36_000;
|
|
34
34
|
const CLOUD_SOURCE_CHARS = 60_000;
|
|
35
|
+
/** Reference material (removed lines, callees, callers, PR intent) for the max and cloud tiers. */
|
|
36
|
+
const LOCAL_REFERENCE_CHARS = 12_000;
|
|
37
|
+
const CLOUD_REFERENCE_CHARS = 24_000;
|
|
35
38
|
export class DeepAnalysisGate extends Gate {
|
|
36
39
|
config;
|
|
37
40
|
provider = null;
|
|
@@ -104,11 +107,20 @@ export class DeepAnalysisGate extends Gate {
|
|
|
104
107
|
inference: inferenceOptions(this.config),
|
|
105
108
|
maxSourceChars: isCloud(this.config.options) ? CLOUD_SOURCE_CHARS : LOCAL_SOURCE_CHARS,
|
|
106
109
|
focusLines: this.config.options.focusLines,
|
|
110
|
+
reference: this.referenceOptions(),
|
|
107
111
|
onProgress: this.config.onProgress,
|
|
108
112
|
});
|
|
109
113
|
this.recordPass(result);
|
|
110
114
|
return verifyCodeFindings(result.findings, result.contexts);
|
|
111
115
|
}
|
|
116
|
+
/** The max and cloud tiers read reference material and review twice; the small models do not. */
|
|
117
|
+
referenceOptions() {
|
|
118
|
+
const options = this.config.options;
|
|
119
|
+
const cloud = isCloud(options);
|
|
120
|
+
if (!cloud && !options.max)
|
|
121
|
+
return undefined;
|
|
122
|
+
return { maxChars: cloud ? CLOUD_REFERENCE_CHARS : LOCAL_REFERENCE_CHARS, removed: options.removedLines, prBody: options.prBody };
|
|
123
|
+
}
|
|
112
124
|
async analyzeFacts(cwd, facts) {
|
|
113
125
|
this.config.onProgress?.(` Found ${facts.length} files to analyze.`);
|
|
114
126
|
const memory = await this.localMemoryFindings(cwd, facts);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* and failures, derived from the deep gate's outcome.
|
|
4
4
|
*/
|
|
5
5
|
import { DeepAnalysisGate } from './deep-analysis.js';
|
|
6
|
+
import { localTier } from '../inference/types.js';
|
|
6
7
|
import { Logger } from '../utils/logger.js';
|
|
7
8
|
/**
|
|
8
9
|
* Run the deep gate and turn its outcome into summary, stats and failures.
|
|
@@ -37,7 +38,7 @@ export async function runDeepAnalysis(config, context, deepOptions) {
|
|
|
37
38
|
enabled: true,
|
|
38
39
|
status: outcome.status,
|
|
39
40
|
mode: outcome.mode,
|
|
40
|
-
tier: isLocal ? (deepOptions
|
|
41
|
+
tier: isLocal ? localTier(deepOptions) : 'cloud',
|
|
41
42
|
model: outcome.model,
|
|
42
43
|
model_fallback: outcome.modelFallback,
|
|
43
44
|
total_ms: Date.now() - start,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { Gate } from './base.js';
|
|
9
9
|
import { FileScanner } from '../utils/scanner.js';
|
|
10
10
|
import { Logger } from '../utils/logger.js';
|
|
11
|
-
import { analyzeFiles, BUILT_IN_RULES } from '../semantic/engine.js';
|
|
11
|
+
import { ALL_RULES, analyzeFiles, BUILT_IN_RULES } from '../semantic/engine.js';
|
|
12
12
|
import { compileLearnedRule, LEARNED_PREFIX } from '../semantic/learn/compile.js';
|
|
13
13
|
import { loadLearnedRules } from '../semantic/learn/store.js';
|
|
14
14
|
const SOURCE_PATTERNS = ['**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}'];
|
|
@@ -36,9 +36,10 @@ export class SemanticBugsGate extends Gate {
|
|
|
36
36
|
}
|
|
37
37
|
/** Built-in rules plus the repository's learned rules (`.rigour/rules/`), filtered by config. */
|
|
38
38
|
selectRules(cwd) {
|
|
39
|
-
const
|
|
39
|
+
const learned = loadLearnedRules(cwd).map(compileLearnedRule);
|
|
40
40
|
const wanted = this.config.rules;
|
|
41
|
-
|
|
41
|
+
// Named rules may include opt-in candidates; unnamed, only the default set runs.
|
|
42
|
+
return wanted?.length ? [...ALL_RULES, ...learned].filter(rule => wanted.includes(rule.id)) : [...BUILT_IN_RULES, ...learned];
|
|
42
43
|
}
|
|
43
44
|
toFailure(finding) {
|
|
44
45
|
const failure = this.createFailure(`${finding.message}\n${finding.evidence.map(e => ` at ${e}`).join('\n')}`, [finding.file], finding.hint, `[${finding.rule}] ${finding.message.split('. ')[0]}`.slice(0, 120), finding.line, undefined, finding.severity);
|
|
@@ -18,6 +18,12 @@ describe('SemanticBugsGate', () => {
|
|
|
18
18
|
fs.mkdirSync(path.dirname(path.join(cwd, rel)), { recursive: true });
|
|
19
19
|
fs.writeFileSync(path.join(cwd, rel), body);
|
|
20
20
|
}
|
|
21
|
+
it('runs an unvalidated candidate rule only when it is named', async () => {
|
|
22
|
+
write('src/scroll.ts', "export function setup(fn: () => void) {\n window.addEventListener('a', fn);\n addEventListener('b', fn);\n}\n");
|
|
23
|
+
expect(await new SemanticBugsGate().run({ cwd })).toEqual([]);
|
|
24
|
+
const named = await new SemanticBugsGate({ rules: ['env/bare-browser-global'] }).run({ cwd });
|
|
25
|
+
expect(named.map(f => [f.category, f.line])).toEqual([['env/bare-browser-global', 3]]);
|
|
26
|
+
});
|
|
21
27
|
it('reports a proven finding with its evidence, rule and verified metadata', async () => {
|
|
22
28
|
write('src/notify.ts', LEAKY);
|
|
23
29
|
const [failure, ...rest] = await new SemanticBugsGate().run({ cwd });
|
package/dist/hooks/checker.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
*/
|
|
10
10
|
import type { HookCheckerResult } from './types.js';
|
|
11
|
-
interface CheckerOptions {
|
|
11
|
+
export interface CheckerOptions {
|
|
12
12
|
cwd: string;
|
|
13
13
|
files: string[];
|
|
14
14
|
timeout_ms?: number;
|
|
@@ -21,4 +21,3 @@ interface CheckerOptions {
|
|
|
21
21
|
* Returns structured JSON for hook consumers.
|
|
22
22
|
*/
|
|
23
23
|
export declare function runHookChecker(options: CheckerOptions): Promise<HookCheckerResult>;
|
|
24
|
-
export {};
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
*/
|
|
5
5
|
export { runHookChecker } from './checker.js';
|
|
6
|
+
export type { CheckerOptions } from './checker.js';
|
|
6
7
|
export { generateHookFiles } from './templates.js';
|
|
8
|
+
export type { GeneratedHookFile } from './templates.js';
|
|
7
9
|
export type { HookTool, HookConfig, HookCheckerResult } from './types.js';
|
|
8
10
|
export { DEFAULT_HOOK_CONFIG, FAST_GATE_IDS } from './types.js';
|
|
9
11
|
export { scanInputForCredentials, formatDLPAlert, createDLPAuditEntry } from './input-validator.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type { RigourSettings, ResolvedDeepOptions, CLIDeepOptions } from './sett
|
|
|
25
25
|
export { DeepAnalysisGate } from './gates/deep-analysis.js';
|
|
26
26
|
export { createProvider } from './inference/index.js';
|
|
27
27
|
export type { InferenceProvider, DeepFinding, DeepAnalysisResult, ModelTier } from './inference/types.js';
|
|
28
|
-
export { MODELS } from './inference/types.js';
|
|
28
|
+
export { MODELS, localTier } from './inference/types.js';
|
|
29
29
|
export { isModelCached, getModelsDir, getModelInfo, getCachedModel, ensureModel } from './inference/model-manager.js';
|
|
30
30
|
export { installLlamaEngine, probeBinary, managedEnginePath, LLAMA_RELEASE_TAG } from './inference/llama-engine.js';
|
|
31
31
|
export { SidecarProvider } from './inference/sidecar-provider.js';
|
|
@@ -56,8 +56,27 @@ export * from './services/system-health.js';
|
|
|
56
56
|
export * from './services/agent-history.js';
|
|
57
57
|
export * from './services/engineering-knowledge-graph.js';
|
|
58
58
|
export * from './firewall/index.js';
|
|
59
|
+
export { exportCallSites } from './semantic/sites/export.js';
|
|
60
|
+
export { ALL_RULES, analyzeFiles, BUILT_IN_RULES } from './semantic/engine.js';
|
|
61
|
+
export { exportReviewContexts, type ReviewContextExport, type ReviewContextOptions } from './deep/review-context-export.js';
|
|
62
|
+
export type { CallSite, HandledBy } from './semantic/sites/call-sites.js';
|
|
59
63
|
export { learnFromFix, learnFromFileChange, type LearnReport, type Rejection } from './semantic/learn/learn.js';
|
|
60
64
|
export { extractFixTrees, type FixTrees } from './semantic/learn/git-trees.js';
|
|
61
65
|
export { saveLearnedRule, loadLearnedRules, LEARNED_RULES_DIR } from './semantic/learn/store.js';
|
|
62
66
|
export type { LearnedRule, LearnedPattern } from './semantic/learn/types.js';
|
|
63
67
|
export { recordContextEvent, recordModelUsage, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics, } from './storage/index.js';
|
|
68
|
+
export type { ModelInfo } from './inference/types.js';
|
|
69
|
+
export type { HttpGet } from './inference/http-download.js';
|
|
70
|
+
export type { FileFacts } from './deep/fact-extractor.js';
|
|
71
|
+
export type { ScanRecord } from './storage/scans.js';
|
|
72
|
+
export type { QualityTrend } from './services/adaptive-thresholds.js';
|
|
73
|
+
export type { EngineOptions } from './semantic/engine.js';
|
|
74
|
+
export type { LearnInput } from './semantic/learn/learn.js';
|
|
75
|
+
export type { ContextEvent } from './storage/index.js';
|
|
76
|
+
export type { CachedModel } from './inference/model-manager.js';
|
|
77
|
+
export type { ProbeResult } from './inference/llama-engine.js';
|
|
78
|
+
export type { PatternRecord } from './storage/patterns.js';
|
|
79
|
+
export type { SemanticFinding } from './semantic/types.js';
|
|
80
|
+
export type { ModelUsage } from './storage/index.js';
|
|
81
|
+
export type { CheckpointMetric } from './storage/index.js';
|
|
82
|
+
export type { CursorUsageSyncOptions } from './services/cursor-usage-client.js';
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export { loadSettings, saveSettings, getSettingsPath, resolveDeepOptions, getPro
|
|
|
25
25
|
// Deep Analysis Pipeline (v4.0+)
|
|
26
26
|
export { DeepAnalysisGate } from './gates/deep-analysis.js';
|
|
27
27
|
export { createProvider } from './inference/index.js';
|
|
28
|
-
export { MODELS } from './inference/types.js';
|
|
28
|
+
export { MODELS, localTier } from './inference/types.js';
|
|
29
29
|
export { isModelCached, getModelsDir, getModelInfo, getCachedModel, ensureModel } from './inference/model-manager.js';
|
|
30
30
|
export { installLlamaEngine, probeBinary, managedEnginePath, LLAMA_RELEASE_TAG } from './inference/llama-engine.js';
|
|
31
31
|
export { SidecarProvider } from './inference/sidecar-provider.js';
|
|
@@ -55,11 +55,10 @@ export * from './services/system-health.js';
|
|
|
55
55
|
export * from './services/agent-history.js';
|
|
56
56
|
export * from './services/engineering-knowledge-graph.js';
|
|
57
57
|
export * from './firewall/index.js';
|
|
58
|
+
export { exportCallSites } from './semantic/sites/export.js';
|
|
59
|
+
export { ALL_RULES, analyzeFiles, BUILT_IN_RULES } from './semantic/engine.js';
|
|
60
|
+
export { exportReviewContexts } from './deep/review-context-export.js';
|
|
58
61
|
export { learnFromFix, learnFromFileChange } from './semantic/learn/learn.js';
|
|
59
62
|
export { extractFixTrees } from './semantic/learn/git-trees.js';
|
|
60
63
|
export { saveLearnedRule, loadLearnedRules, LEARNED_RULES_DIR } from './semantic/learn/store.js';
|
|
61
64
|
export { recordContextEvent, recordModelUsage, recordCheckpointMetric, getContextEvents, getModelUsages, getCheckpointMetrics, } from './storage/index.js';
|
|
62
|
-
// Pattern Index is intentionally NOT exported here to prevent
|
|
63
|
-
// native dependency issues (sharp/transformers) from leaking into
|
|
64
|
-
// non-AI parts of the system.
|
|
65
|
-
// Import from @rigour-labs/core/pattern-index instead.
|
|
@@ -10,7 +10,7 @@ export type { ProbeResult } from './llama-engine.js';
|
|
|
10
10
|
export { CloudProvider } from './cloud-provider.js';
|
|
11
11
|
export { ensureModel, isModelCached, getModelPath, getModelInfo, downloadModel, getModelsDir, getCachedModel } from './model-manager.js';
|
|
12
12
|
export type { CachedModel } from './model-manager.js';
|
|
13
|
-
import type
|
|
13
|
+
import { type InferenceProvider } from './types.js';
|
|
14
14
|
import type { DeepOptions } from '../types/index.js';
|
|
15
15
|
/**
|
|
16
16
|
* Create the appropriate inference provider based on options.
|
package/dist/inference/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { SidecarProvider } from './sidecar-provider.js';
|
|
|
3
3
|
export { installLlamaEngine, probeBinary, managedEnginePath, LLAMA_RELEASE_TAG } from './llama-engine.js';
|
|
4
4
|
export { CloudProvider } from './cloud-provider.js';
|
|
5
5
|
export { ensureModel, isModelCached, getModelPath, getModelInfo, downloadModel, getModelsDir, getCachedModel } from './model-manager.js';
|
|
6
|
+
import { localTier } from './types.js';
|
|
6
7
|
import { SidecarProvider } from './sidecar-provider.js';
|
|
7
8
|
import { CloudProvider } from './cloud-provider.js';
|
|
8
9
|
/**
|
|
@@ -18,9 +19,6 @@ export function createProvider(options) {
|
|
|
18
19
|
modelName: options.modelName,
|
|
19
20
|
});
|
|
20
21
|
}
|
|
21
|
-
// Default: local sidecar
|
|
22
|
-
|
|
23
|
-
// lite = Qwen2.5-Coder-0.5B (lightweight, default CLI sidecar)
|
|
24
|
-
const tier = options.pro ? 'deep' : 'lite';
|
|
25
|
-
return new SidecarProvider(tier);
|
|
22
|
+
// Default: local sidecar (lite 0.5B, deep 1.5B with --pro, max 7B with --max)
|
|
23
|
+
return new SidecarProvider(localTier(options), undefined, options.modelPath);
|
|
26
24
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { localModel } from './sidecar-provider.js';
|
|
6
|
+
let dir;
|
|
7
|
+
afterEach(() => { if (dir)
|
|
8
|
+
fs.rmSync(dir, { recursive: true, force: true }); dir = undefined; });
|
|
9
|
+
describe('a local GGUF for --model-path', () => {
|
|
10
|
+
it('is used as is, never reported as a fallback', async () => {
|
|
11
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'local-model-'));
|
|
12
|
+
const file = path.join(dir, 'rigour-max-candidate-q4_k_m.gguf');
|
|
13
|
+
fs.writeFileSync(file, Buffer.alloc(2_000_000));
|
|
14
|
+
expect(await localModel('max', file)).toEqual({
|
|
15
|
+
path: file, fallback: false,
|
|
16
|
+
info: { tier: 'max', name: 'rigour-max-candidate-q4_k_m.gguf (local)', filename: 'rigour-max-candidate-q4_k_m.gguf', url: '', sizeBytes: 2_000_000, sizeHuman: '2MB' },
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
it('fails clearly when the file is missing, rather than downloading something else', async () => {
|
|
20
|
+
const missing = path.resolve('/nonexistent/model.gguf'); // D:\\nonexistent\\model.gguf on Windows
|
|
21
|
+
await expect(localModel('max', missing)).rejects.toThrow(`Model file not found: ${missing}`);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import type { InferenceProvider, InferenceOptions, ModelTier } from './types.js';
|
|
2
|
+
import { type CachedModel } from './model-manager.js';
|
|
2
3
|
export interface ActiveModel {
|
|
3
4
|
name: string;
|
|
4
5
|
filename: string;
|
|
5
6
|
fallback: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare class SidecarProvider implements InferenceProvider {
|
|
9
|
+
private readonly modelPath?;
|
|
8
10
|
readonly name = "sidecar";
|
|
9
11
|
private binaryPath;
|
|
10
12
|
private model;
|
|
11
13
|
private schemaPath;
|
|
12
14
|
private tier;
|
|
13
15
|
private threads;
|
|
14
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @param modelPath a local GGUF to load instead of the tier's published model:
|
|
18
|
+
* how a fine-tune candidate is measured before it is published.
|
|
19
|
+
*/
|
|
20
|
+
constructor(tier?: ModelTier, threads?: number, modelPath?: string | undefined);
|
|
15
21
|
/** True when a llama-cli that actually runs is installed. */
|
|
16
22
|
isAvailable(): Promise<boolean>;
|
|
17
23
|
/** The llama-cli this provider would use and its version, or null if none runs. */
|
|
@@ -22,6 +28,7 @@ export declare class SidecarProvider implements InferenceProvider {
|
|
|
22
28
|
/** Install the engine and model for this tier without running inference. */
|
|
23
29
|
prepare(onProgress?: (message: string) => void): Promise<void>;
|
|
24
30
|
setup(onProgress?: (message: string) => void): Promise<void>;
|
|
31
|
+
private publishedModel;
|
|
25
32
|
/** The model file setup() loaded, or null before setup. */
|
|
26
33
|
getActiveModel(): ActiveModel | null;
|
|
27
34
|
analyze(prompt: string, options?: InferenceOptions): Promise<string>;
|
|
@@ -30,3 +37,5 @@ export declare class SidecarProvider implements InferenceProvider {
|
|
|
30
37
|
private resolveBinaryPath;
|
|
31
38
|
private candidateBinaries;
|
|
32
39
|
}
|
|
40
|
+
/** A GGUF on disk, used as is: no download, no version check. */
|
|
41
|
+
export declare function localModel(tier: ModelTier, modelPath: string): Promise<CachedModel>;
|