review-council 1.0.0 → 1.4.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/README.md +4 -4
- package/dist/ci.d.ts +14 -0
- package/dist/ci.js +25 -0
- package/dist/ci.js.map +1 -0
- package/dist/config/defaults.d.ts +13 -1
- package/dist/config/defaults.js +17 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +9 -1
- package/dist/config/loader.js +48 -27
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.js +1 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/consensus/deduper.d.ts +26 -2
- package/dist/consensus/deduper.js +225 -62
- package/dist/consensus/deduper.js.map +1 -1
- package/dist/consensus/parser.js +67 -28
- package/dist/consensus/parser.js.map +1 -1
- package/dist/consensus/types.d.ts +2 -1
- package/dist/consensus/voter.d.ts +26 -1
- package/dist/consensus/voter.js +198 -78
- package/dist/consensus/voter.js.map +1 -1
- package/dist/dispatch/adapter.d.ts +0 -5
- package/dist/dispatch/adapter.js +1 -23
- package/dist/dispatch/adapter.js.map +1 -1
- package/dist/dispatch/anthropic.js +93 -82
- package/dist/dispatch/anthropic.js.map +1 -1
- package/dist/dispatch/google.js +67 -48
- package/dist/dispatch/google.js.map +1 -1
- package/dist/dispatch/merge.d.ts +12 -0
- package/dist/dispatch/merge.js +54 -0
- package/dist/dispatch/merge.js.map +1 -0
- package/dist/dispatch/openai-compat.js +62 -44
- package/dist/dispatch/openai-compat.js.map +1 -1
- package/dist/dispatch/openai.js +59 -46
- package/dist/dispatch/openai.js.map +1 -1
- package/dist/dispatch/runner.d.ts +3 -0
- package/dist/dispatch/runner.js +50 -38
- package/dist/dispatch/runner.js.map +1 -1
- package/dist/dispatch/utils.d.ts +10 -1
- package/dist/dispatch/utils.js +18 -2
- package/dist/dispatch/utils.js.map +1 -1
- package/dist/help/environment.d.ts +4 -0
- package/dist/help/environment.js +67 -0
- package/dist/help/environment.js.map +1 -0
- package/dist/index.js +49 -22
- package/dist/index.js.map +1 -1
- package/dist/output/github.d.ts +11 -2
- package/dist/output/github.js +126 -26
- package/dist/output/github.js.map +1 -1
- package/dist/output/markdown.js +4 -3
- package/dist/output/markdown.js.map +1 -1
- package/dist/output/sanitize.d.ts +18 -0
- package/dist/output/sanitize.js +46 -0
- package/dist/output/sanitize.js.map +1 -0
- package/dist/output/terminal.js +4 -1
- package/dist/output/terminal.js.map +1 -1
- package/dist/prepare/chunker.js +9 -2
- package/dist/prepare/chunker.js.map +1 -1
- package/dist/prepare/prompt-builder.d.ts +0 -1
- package/dist/prepare/prompt-builder.js +22 -7
- package/dist/prepare/prompt-builder.js.map +1 -1
- package/dist/prompts/hardening.d.ts +9 -0
- package/dist/prompts/hardening.js +24 -2
- package/dist/prompts/hardening.js.map +1 -1
- package/dist/resolver/github.d.ts +2 -1
- package/dist/resolver/github.js +9 -7
- package/dist/resolver/github.js.map +1 -1
- package/dist/roles/builtin.js +92 -0
- package/dist/roles/builtin.js.map +1 -1
- package/dist/roles/dispatcher.d.ts +4 -3
- package/dist/roles/dispatcher.js +17 -10
- package/dist/roles/dispatcher.js.map +1 -1
- package/dist/roles/loader.js +36 -15
- package/dist/roles/loader.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -150,7 +150,7 @@ thresholds:
|
|
|
150
150
|
minConsensusScore: 0.4 # 0–1; findings below this are dropped
|
|
151
151
|
minConfidence: 0.2
|
|
152
152
|
dedupeLineWindow: 5 # lines within which findings are merged
|
|
153
|
-
jaccardThreshold: 0.3 #
|
|
153
|
+
jaccardThreshold: 0.3 # weighted title+description similarity threshold for dedup
|
|
154
154
|
|
|
155
155
|
# Output defaults
|
|
156
156
|
output:
|
|
@@ -182,9 +182,9 @@ Supported config file names: `.review-council.yml`, `.review-council.yaml`, `.re
|
|
|
182
182
|
|
|
183
183
|
When multiple models and roles review the same diff, their findings are:
|
|
184
184
|
|
|
185
|
-
1. **Deduplicated** — findings on the same file
|
|
186
|
-
2. **Scored** — each group receives a consensus score based on three dimensions: reviewer diversity (how many distinct models and roles flagged it), role relevance (whether
|
|
187
|
-
3. **Classified** — groups are assigned a confidence band (Very High → Minimal) and a final severity
|
|
185
|
+
1. **Deduplicated** — findings on the same file and overlapping line range are grouped by weighted title+description token similarity; findings in different categories can still merge, but need stronger similarity (models disagree on category boundaries constantly). Repeats within a single review are collapsed first. Findings that clearly reach opposite conclusions are kept as separate, disputed findings; subtler contradictions merge but are flagged as disputed.
|
|
186
|
+
2. **Scored** — each group receives a consensus score based on three dimensions: reviewer diversity (how many distinct models and roles flagged it, saturating at half the fleet so large configurations aren't penalized), role relevance (whether a role specialised in that finding type confirmed it), and isolation (what fraction of relevant reviewers flagged it).
|
|
187
|
+
3. **Classified** — groups are assigned a confidence band (Very High → Minimal) and a final severity. Severity is the most common rating across reviewers; when reviewers disagree, high-confidence agreement elevates it, but only to a severity at least two reviewers independently assigned — a lone outlier rating is surfaced as a dispute instead.
|
|
188
188
|
4. **Filtered** — groups below `minConsensusScore` or `minConfidence` are dropped.
|
|
189
189
|
|
|
190
190
|
The result is a ranked list of findings that rewards agreement across independent reviewers and penalises noise from a single model.
|
package/dist/ci.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReviewResult } from './consensus/types.js';
|
|
2
|
+
export interface CiVerdict {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
message?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Decide the CI exit status for a completed review.
|
|
8
|
+
*
|
|
9
|
+
* A run where every reviewer errored produces zero findings — which without
|
|
10
|
+
* this check looks identical to "clean" and exits 0, greenlighting code that
|
|
11
|
+
* was never actually reviewed. That case fails first; blocking findings fail
|
|
12
|
+
* second.
|
|
13
|
+
*/
|
|
14
|
+
export declare function evaluateCiGate(result: ReviewResult): CiVerdict;
|
package/dist/ci.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decide the CI exit status for a completed review.
|
|
3
|
+
*
|
|
4
|
+
* A run where every reviewer errored produces zero findings — which without
|
|
5
|
+
* this check looks identical to "clean" and exits 0, greenlighting code that
|
|
6
|
+
* was never actually reviewed. That case fails first; blocking findings fail
|
|
7
|
+
* second.
|
|
8
|
+
*/
|
|
9
|
+
export function evaluateCiGate(result) {
|
|
10
|
+
if (result.stats.successfulReviews === 0) {
|
|
11
|
+
return {
|
|
12
|
+
exitCode: 1,
|
|
13
|
+
message: `CI: 0/${result.stats.totalReviews} reviewers succeeded — nothing was reviewed. Exiting with code 1.`,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const blocking = result.findings.filter((f) => f.severity === 'critical' || f.severity === 'important');
|
|
17
|
+
if (blocking.length > 0) {
|
|
18
|
+
return {
|
|
19
|
+
exitCode: 1,
|
|
20
|
+
message: `CI: ${blocking.length} blocking finding(s) found. Exiting with code 1.`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { exitCode: 0 };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=ci.js.map
|
package/dist/ci.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,SAAS,MAAM,CAAC,KAAK,CAAC,YAAY,mEAAmE;SAC/G,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,WAAW,CAC/D,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,QAAQ,CAAC,MAAM,kDAAkD;SAClF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/** SOTA models — run the general role + participate in specialized round-robin */
|
|
2
|
+
export declare const DEFAULT_MODELS: readonly ["anthropic/claude-fable-5", "openai/gpt-5.5", "google/gemini-3.5-flash"];
|
|
3
|
+
/** Previous-gen models — specialized round-robin only, no general role */
|
|
4
|
+
export declare const DEFAULT_SECONDARY_MODELS: readonly ["anthropic/claude-opus-4-8", "openai/gpt-5.4", "google/gemini-2.5-pro"];
|
|
2
5
|
export declare const DEFAULT_THRESHOLDS: {
|
|
3
6
|
readonly minConsensusScore: 0.4;
|
|
4
7
|
readonly minConfidence: 0.2;
|
|
5
8
|
readonly dedupeLineWindow: 5;
|
|
9
|
+
/**
|
|
10
|
+
* Threshold for the weighted title+description similarity
|
|
11
|
+
* (0.6 * title + 0.4 * description). Calibrated against the fixture
|
|
12
|
+
* corpus: genuine cross-model duplicates score 0.29-0.55 (descriptions
|
|
13
|
+
* diverge heavily across models), so higher thresholds split real
|
|
14
|
+
* duplicates. The strictness gain over the old max(title, desc) check
|
|
15
|
+
* comes from the formula: a title-only match now needs 0.5+ title
|
|
16
|
+
* overlap to merge instead of 0.3.
|
|
17
|
+
*/
|
|
6
18
|
readonly jaccardThreshold: 0.3;
|
|
7
19
|
};
|
|
8
20
|
export declare const DEFAULT_TIMEOUT_MS = 120000;
|
package/dist/config/defaults.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
/** SOTA models — run the general role + participate in specialized round-robin */
|
|
1
2
|
export const DEFAULT_MODELS = [
|
|
2
|
-
'anthropic/claude-
|
|
3
|
+
'anthropic/claude-fable-5',
|
|
4
|
+
'openai/gpt-5.5',
|
|
5
|
+
'google/gemini-3.5-flash',
|
|
6
|
+
];
|
|
7
|
+
/** Previous-gen models — specialized round-robin only, no general role */
|
|
8
|
+
export const DEFAULT_SECONDARY_MODELS = [
|
|
9
|
+
'anthropic/claude-opus-4-8',
|
|
3
10
|
'openai/gpt-5.4',
|
|
4
11
|
'google/gemini-2.5-pro',
|
|
5
12
|
];
|
|
@@ -7,6 +14,15 @@ export const DEFAULT_THRESHOLDS = {
|
|
|
7
14
|
minConsensusScore: 0.4,
|
|
8
15
|
minConfidence: 0.2,
|
|
9
16
|
dedupeLineWindow: 5,
|
|
17
|
+
/**
|
|
18
|
+
* Threshold for the weighted title+description similarity
|
|
19
|
+
* (0.6 * title + 0.4 * description). Calibrated against the fixture
|
|
20
|
+
* corpus: genuine cross-model duplicates score 0.29-0.55 (descriptions
|
|
21
|
+
* diverge heavily across models), so higher thresholds split real
|
|
22
|
+
* duplicates. The strictness gain over the old max(title, desc) check
|
|
23
|
+
* comes from the formula: a title-only match now needs 0.5+ title
|
|
24
|
+
* overlap to merge instead of 0.3.
|
|
25
|
+
*/
|
|
10
26
|
jaccardThreshold: 0.3,
|
|
11
27
|
};
|
|
12
28
|
export const DEFAULT_TIMEOUT_MS = 120_000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,2BAA2B;IAC3B,gBAAgB;IAChB,uBAAuB;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,iBAAiB,EAAE,GAAG;IACtB,aAAa,EAAE,GAAG;IAClB,gBAAgB,EAAE,CAAC;IACnB,gBAAgB,EAAE,GAAG;CACb,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,UAAU;IACV,WAAW;IACX,OAAO;IACP,SAAS;CACD,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,QAAQ,EAAE,GAAG;IACb,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;IACX,GAAG,EAAE,GAAG;CACA,CAAC"}
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,0BAA0B;IAC1B,gBAAgB;IAChB,yBAAyB;CACjB,CAAC;AAEX,0EAA0E;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,2BAA2B;IAC3B,gBAAgB;IAChB,uBAAuB;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,iBAAiB,EAAE,GAAG;IACtB,aAAa,EAAE,GAAG;IAClB,gBAAgB,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,GAAG;CACb,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,UAAU;IACV,WAAW;IACX,OAAO;IACP,SAAS;CACD,CAAC;AAEX,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,QAAQ,EAAE,GAAG;IACb,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;IACX,GAAG,EAAE,GAAG;CACA,CAAC"}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
import { type Config } from './schema.js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* A config file was found but could not be used. Never silently recover
|
|
4
|
+
* from this: falling back to defaults would send code to cloud providers
|
|
5
|
+
* the user may have explicitly configured away from.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConfigError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function loadConfig(configPath?: string, searchFrom?: string): Promise<Config>;
|
package/dist/config/loader.js
CHANGED
|
@@ -1,42 +1,62 @@
|
|
|
1
1
|
import { cosmiconfig } from 'cosmiconfig';
|
|
2
2
|
import { ConfigSchema } from './schema.js';
|
|
3
|
-
import { DEFAULT_MODELS, DEFAULT_THRESHOLDS, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_CONCURRENCY, } from './defaults.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
3
|
+
import { DEFAULT_MODELS, DEFAULT_SECONDARY_MODELS, DEFAULT_THRESHOLDS, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_CONCURRENCY, } from './defaults.js';
|
|
4
|
+
/**
|
|
5
|
+
* A config file was found but could not be used. Never silently recover
|
|
6
|
+
* from this: falling back to defaults would send code to cloud providers
|
|
7
|
+
* the user may have explicitly configured away from.
|
|
8
|
+
*/
|
|
9
|
+
export class ConfigError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'ConfigError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Declarative formats only. Executable config (.js/.cjs) is deliberately
|
|
16
|
+
// unsupported for discovery: rcl is routinely run inside untrusted
|
|
17
|
+
// checkouts, and search-loading attacker-controlled JS would execute it
|
|
18
|
+
// with the user's API keys in env.
|
|
19
|
+
const SEARCH_PLACES = [
|
|
20
|
+
'.review-council.yml',
|
|
21
|
+
'.review-council.yaml',
|
|
22
|
+
'.review-council.json',
|
|
23
|
+
];
|
|
24
|
+
export async function loadConfig(configPath, searchFrom) {
|
|
25
|
+
const cwd = searchFrom ?? process.cwd();
|
|
26
|
+
const explorer = cosmiconfig('review-council', {
|
|
27
|
+
searchPlaces: SEARCH_PLACES,
|
|
28
|
+
// 'none' searches only the starting directory — no parent-directory walk
|
|
29
|
+
// and no global (~/.config) dir, which would otherwise be probed with
|
|
30
|
+
// cosmiconfig's default executable-config loaders. (stopDir is rejected
|
|
31
|
+
// alongside a non-'global' strategy, and is unnecessary here.)
|
|
32
|
+
searchStrategy: 'none',
|
|
33
|
+
});
|
|
34
|
+
let result;
|
|
16
35
|
try {
|
|
17
|
-
|
|
36
|
+
result = configPath
|
|
18
37
|
? await explorer.load(configPath)
|
|
19
|
-
: await explorer.search();
|
|
20
|
-
if (!result || result.isEmpty) {
|
|
21
|
-
return buildDefaultConfig();
|
|
22
|
-
}
|
|
23
|
-
const parsed = ConfigSchema.safeParse(result.config);
|
|
24
|
-
if (!parsed.success) {
|
|
25
|
-
console.warn('Warning: config validation errors:', parsed.error.format());
|
|
26
|
-
return buildDefaultConfig();
|
|
27
|
-
}
|
|
28
|
-
return mergeWithDefaults(parsed.data);
|
|
38
|
+
: await explorer.search(cwd);
|
|
29
39
|
}
|
|
30
40
|
catch (err) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
const source = configPath ?? 'discovered config';
|
|
42
|
+
throw new ConfigError(`Failed to load config from ${source}: ${String(err)}`);
|
|
43
|
+
}
|
|
44
|
+
if (!result || result.isEmpty) {
|
|
34
45
|
return buildDefaultConfig();
|
|
35
46
|
}
|
|
47
|
+
const parsed = ConfigSchema.safeParse(result.config);
|
|
48
|
+
if (!parsed.success) {
|
|
49
|
+
const issues = parsed.error.issues
|
|
50
|
+
.map((issue) => ` ${issue.path.join('.') || '(root)'}: ${issue.message}`)
|
|
51
|
+
.join('\n');
|
|
52
|
+
throw new ConfigError(`Invalid config at ${result.filepath}:\n${issues}`);
|
|
53
|
+
}
|
|
54
|
+
return mergeWithDefaults(parsed.data);
|
|
36
55
|
}
|
|
37
56
|
function buildDefaultConfig() {
|
|
38
57
|
return {
|
|
39
58
|
models: [...DEFAULT_MODELS],
|
|
59
|
+
secondaryModels: [...DEFAULT_SECONDARY_MODELS],
|
|
40
60
|
thresholds: { ...DEFAULT_THRESHOLDS },
|
|
41
61
|
timeout: DEFAULT_TIMEOUT_MS,
|
|
42
62
|
maxRetries: DEFAULT_MAX_RETRIES,
|
|
@@ -46,6 +66,7 @@ function buildDefaultConfig() {
|
|
|
46
66
|
function mergeWithDefaults(config) {
|
|
47
67
|
return {
|
|
48
68
|
models: config.models ?? [...DEFAULT_MODELS],
|
|
69
|
+
secondaryModels: config.secondaryModels ?? (config.models ? [] : [...DEFAULT_SECONDARY_MODELS]),
|
|
49
70
|
roles: config.roles,
|
|
50
71
|
reviewers: config.reviewers,
|
|
51
72
|
customRoles: config.customRoles,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AACxD,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,MAAM,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare const OutputSchema: z.ZodObject<{
|
|
|
38
38
|
}, z.core.$strip>;
|
|
39
39
|
export declare const ConfigSchema: z.ZodObject<{
|
|
40
40
|
models: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
41
|
+
secondaryModels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
41
42
|
roles: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
43
|
reviewers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
43
44
|
model: z.ZodString;
|
package/dist/config/schema.js
CHANGED
|
@@ -33,6 +33,7 @@ export const OutputSchema = z.object({
|
|
|
33
33
|
});
|
|
34
34
|
export const ConfigSchema = z.object({
|
|
35
35
|
models: z.array(z.string()).optional(),
|
|
36
|
+
secondaryModels: z.array(z.string()).optional(),
|
|
36
37
|
roles: z.array(z.string()).optional(),
|
|
37
38
|
reviewers: z.array(ReviewerPairSchema).optional(),
|
|
38
39
|
customRoles: z.array(RoleConfigSchema).optional(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,30 @@
|
|
|
1
|
-
import type { ModelReview, DeduplicatedGroup } from './types.js';
|
|
1
|
+
import type { Finding, ModelReview, DeduplicatedGroup } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Compute Jaccard similarity between two strings (word-level tokenization)
|
|
3
|
+
* Compute Jaccard similarity between two strings (word-level tokenization).
|
|
4
|
+
* Single characters and stopwords are ignored; short signal tokens like
|
|
5
|
+
* "xss", "id", or "no" are kept.
|
|
4
6
|
*/
|
|
5
7
|
export declare function jaccardSimilarity(a: string, b: string): number;
|
|
8
|
+
/**
|
|
9
|
+
* Weighted title+description similarity. Both fields contribute, so a short
|
|
10
|
+
* generic title alone can no longer merge two unrelated findings, and a
|
|
11
|
+
* verbose description alone can't either.
|
|
12
|
+
*
|
|
13
|
+
* A field where either side has no usable tokens carries no signal and is
|
|
14
|
+
* excluded, with weights renormalized over the remaining fields — empty
|
|
15
|
+
* descriptions neither grant free similarity nor penalize a strong title
|
|
16
|
+
* match. If no field has usable tokens on both sides, similarity is 0.
|
|
17
|
+
*/
|
|
18
|
+
export declare function combinedSimilarity(a: Finding, b: Finding): number;
|
|
19
|
+
/**
|
|
20
|
+
* Detect findings that reach opposite conclusions. Word-boundary matching
|
|
21
|
+
* prevents substring traps ("unsafe" does not match "safe").
|
|
22
|
+
*
|
|
23
|
+
* With `specificOnly`, only high-precision pairs count — used for the merge
|
|
24
|
+
* veto, where a false positive fragments a genuine duplicate group. The
|
|
25
|
+
* default (all pairs) is for dispute flagging, where a false positive just
|
|
26
|
+
* adds a warning.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hasOpposingSentiment(a: Finding, b: Finding, specificOnly?: boolean): boolean;
|
|
29
|
+
export declare function linesOverlap(a: Finding, b: Finding, window: number): boolean;
|
|
6
30
|
export declare function deduplicateFindings(reviews: ModelReview[], jaccardThreshold?: number, lineWindow?: number): DeduplicatedGroup[];
|