ghagga-core 2.8.0 → 2.9.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/acp/adapter.d.ts +91 -0
- package/dist/acp/adapter.d.ts.map +1 -0
- package/dist/acp/adapter.js +315 -0
- package/dist/acp/adapter.js.map +1 -0
- package/dist/acp/index.d.ts +4 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/index.js +2 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/types.d.ts +142 -0
- package/dist/acp/types.d.ts.map +1 -0
- package/dist/acp/types.js +13 -0
- package/dist/acp/types.js.map +1 -0
- package/dist/adversarial-qa.d.ts +60 -0
- package/dist/adversarial-qa.d.ts.map +1 -0
- package/dist/adversarial-qa.js +85 -0
- package/dist/adversarial-qa.js.map +1 -0
- package/dist/agents/audit.d.ts +18 -0
- package/dist/agents/audit.d.ts.map +1 -0
- package/dist/agents/audit.js +78 -0
- package/dist/agents/audit.js.map +1 -0
- package/dist/agents/consensus.d.ts +1 -1
- package/dist/agents/consensus.d.ts.map +1 -1
- package/dist/agents/consensus.js +10 -8
- package/dist/agents/consensus.js.map +1 -1
- package/dist/agents/diagnostic.d.ts.map +1 -1
- package/dist/agents/diagnostic.js +22 -20
- package/dist/agents/diagnostic.js.map +1 -1
- package/dist/agents/fan-out-lenses.d.ts +41 -0
- package/dist/agents/fan-out-lenses.d.ts.map +1 -1
- package/dist/agents/fan-out-lenses.js +117 -3
- package/dist/agents/fan-out-lenses.js.map +1 -1
- package/dist/agents/prompts.d.ts +12 -0
- package/dist/agents/prompts.d.ts.map +1 -1
- package/dist/agents/prompts.js +31 -0
- package/dist/agents/prompts.js.map +1 -1
- package/dist/agents/simple.d.ts +1 -1
- package/dist/agents/simple.d.ts.map +1 -1
- package/dist/agents/simple.js +10 -6
- package/dist/agents/simple.js.map +1 -1
- package/dist/agents/workflow.d.ts +1 -1
- package/dist/agents/workflow.d.ts.map +1 -1
- package/dist/agents/workflow.js +9 -8
- package/dist/agents/workflow.js.map +1 -1
- package/dist/aisvs.d.ts +44 -0
- package/dist/aisvs.d.ts.map +1 -0
- package/dist/aisvs.js +189 -0
- package/dist/aisvs.js.map +1 -0
- package/dist/checklist/context.d.ts.map +1 -1
- package/dist/checklist/context.js +2 -8
- package/dist/checklist/context.js.map +1 -1
- package/dist/checklist/defaults.d.ts.map +1 -1
- package/dist/checklist/defaults.js.map +1 -1
- package/dist/checklist/scorer.d.ts.map +1 -1
- package/dist/checklist/scorer.js +105 -12
- package/dist/checklist/scorer.js.map +1 -1
- package/dist/code-intel/client.d.ts +30 -0
- package/dist/code-intel/client.d.ts.map +1 -0
- package/dist/code-intel/client.js +91 -0
- package/dist/code-intel/client.js.map +1 -0
- package/dist/code-intel/context.d.ts +21 -0
- package/dist/code-intel/context.d.ts.map +1 -0
- package/dist/code-intel/context.js +72 -0
- package/dist/code-intel/context.js.map +1 -0
- package/dist/code-intel/index.d.ts +10 -0
- package/dist/code-intel/index.d.ts.map +1 -0
- package/dist/code-intel/index.js +11 -0
- package/dist/code-intel/index.js.map +1 -0
- package/dist/code-intel/types.d.ts +63 -0
- package/dist/code-intel/types.d.ts.map +1 -0
- package/dist/code-intel/types.js +9 -0
- package/dist/code-intel/types.js.map +1 -0
- package/dist/compress/index.d.ts +55 -0
- package/dist/compress/index.d.ts.map +1 -0
- package/dist/compress/index.js +166 -0
- package/dist/compress/index.js.map +1 -0
- package/dist/cost-footer.d.ts +38 -0
- package/dist/cost-footer.d.ts.map +1 -0
- package/dist/cost-footer.js +95 -0
- package/dist/cost-footer.js.map +1 -0
- package/dist/critique/critique.d.ts +40 -0
- package/dist/critique/critique.d.ts.map +1 -0
- package/dist/critique/critique.js +194 -0
- package/dist/critique/critique.js.map +1 -0
- package/dist/critique/cross-model.d.ts +123 -0
- package/dist/critique/cross-model.d.ts.map +1 -0
- package/dist/critique/cross-model.js +267 -0
- package/dist/critique/cross-model.js.map +1 -0
- package/dist/critique/index.d.ts +8 -0
- package/dist/critique/index.d.ts.map +1 -0
- package/dist/critique/index.js +6 -0
- package/dist/critique/index.js.map +1 -0
- package/dist/critique/prompts.d.ts +11 -0
- package/dist/critique/prompts.d.ts.map +1 -0
- package/dist/critique/prompts.js +66 -0
- package/dist/critique/prompts.js.map +1 -0
- package/dist/critique/types.d.ts +84 -0
- package/dist/critique/types.d.ts.map +1 -0
- package/dist/critique/types.js +13 -0
- package/dist/critique/types.js.map +1 -0
- package/dist/doc-validation/index.d.ts +9 -0
- package/dist/doc-validation/index.d.ts.map +1 -0
- package/dist/doc-validation/index.js +9 -0
- package/dist/doc-validation/index.js.map +1 -0
- package/dist/doc-validation/scanner.d.ts +40 -0
- package/dist/doc-validation/scanner.d.ts.map +1 -0
- package/dist/doc-validation/scanner.js +163 -0
- package/dist/doc-validation/scanner.js.map +1 -0
- package/dist/doc-validation/types.d.ts +27 -0
- package/dist/doc-validation/types.d.ts.map +1 -0
- package/dist/doc-validation/types.js +8 -0
- package/dist/doc-validation/types.js.map +1 -0
- package/dist/embed.d.ts +27 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +47 -0
- package/dist/embed.js.map +1 -0
- package/dist/enhance/enhance.d.ts.map +1 -1
- package/dist/enhance/enhance.js +7 -25
- package/dist/enhance/enhance.js.map +1 -1
- package/dist/enhance/types.d.ts +5 -0
- package/dist/enhance/types.d.ts.map +1 -1
- package/dist/exploitability/analyzer.d.ts +42 -0
- package/dist/exploitability/analyzer.d.ts.map +1 -1
- package/dist/exploitability/analyzer.js +225 -0
- package/dist/exploitability/analyzer.js.map +1 -1
- package/dist/exploitability/index.d.ts +3 -2
- package/dist/exploitability/index.d.ts.map +1 -1
- package/dist/exploitability/index.js +1 -2
- package/dist/exploitability/index.js.map +1 -1
- package/dist/exploitability/types.d.ts +27 -0
- package/dist/exploitability/types.d.ts.map +1 -1
- package/dist/fetch-fix.d.ts +60 -0
- package/dist/fetch-fix.d.ts.map +1 -0
- package/dist/fetch-fix.js +137 -0
- package/dist/fetch-fix.js.map +1 -0
- package/dist/flood/index.d.ts +34 -0
- package/dist/flood/index.d.ts.map +1 -0
- package/dist/flood/index.js +67 -0
- package/dist/flood/index.js.map +1 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +6 -1
- package/dist/format.js.map +1 -1
- package/dist/graph/blast-radius.js +2 -2
- package/dist/graph/blast-radius.js.map +1 -1
- package/dist/graph/call-chain.d.ts +36 -0
- package/dist/graph/call-chain.d.ts.map +1 -0
- package/dist/graph/call-chain.js +291 -0
- package/dist/graph/call-chain.js.map +1 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +2 -0
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/reverse-deps.d.ts +37 -0
- package/dist/graph/reverse-deps.d.ts.map +1 -0
- package/dist/graph/reverse-deps.js +136 -0
- package/dist/graph/reverse-deps.js.map +1 -0
- package/dist/index.d.ts +50 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -7
- package/dist/index.js.map +1 -1
- package/dist/injection-corpus.d.ts +41 -0
- package/dist/injection-corpus.d.ts.map +1 -0
- package/dist/injection-corpus.js +181 -0
- package/dist/injection-corpus.js.map +1 -0
- package/dist/latent-comms.d.ts +31 -0
- package/dist/latent-comms.d.ts.map +1 -0
- package/dist/latent-comms.js +139 -0
- package/dist/latent-comms.js.map +1 -0
- package/dist/memory/pageindex/chunker.d.ts +33 -0
- package/dist/memory/pageindex/chunker.d.ts.map +1 -0
- package/dist/memory/pageindex/chunker.js +112 -0
- package/dist/memory/pageindex/chunker.js.map +1 -0
- package/dist/memory/pageindex/example.d.ts +22 -0
- package/dist/memory/pageindex/example.d.ts.map +1 -0
- package/dist/memory/pageindex/example.js +94 -0
- package/dist/memory/pageindex/example.js.map +1 -0
- package/dist/memory/pageindex/index.d.ts +15 -0
- package/dist/memory/pageindex/index.d.ts.map +1 -0
- package/dist/memory/pageindex/index.js +17 -0
- package/dist/memory/pageindex/index.js.map +1 -0
- package/dist/memory/pageindex/service.d.ts +53 -0
- package/dist/memory/pageindex/service.d.ts.map +1 -0
- package/dist/memory/pageindex/service.js +229 -0
- package/dist/memory/pageindex/service.js.map +1 -0
- package/dist/memory/pageindex/types.d.ts +67 -0
- package/dist/memory/pageindex/types.d.ts.map +1 -0
- package/dist/memory/pageindex/types.js +14 -0
- package/dist/memory/pageindex/types.js.map +1 -0
- package/dist/memory/persist.d.ts.map +1 -1
- package/dist/memory/persist.js +6 -2
- package/dist/memory/persist.js.map +1 -1
- package/dist/memory/sqlite.d.ts +69 -2
- package/dist/memory/sqlite.d.ts.map +1 -1
- package/dist/memory/sqlite.js +312 -5
- package/dist/memory/sqlite.js.map +1 -1
- package/dist/memory/taxonomy.d.ts +34 -0
- package/dist/memory/taxonomy.d.ts.map +1 -0
- package/dist/memory/taxonomy.js +189 -0
- package/dist/memory/taxonomy.js.map +1 -0
- package/dist/memory/versioning.d.ts.map +1 -1
- package/dist/memory/versioning.js.map +1 -1
- package/dist/negative.d.ts +23 -0
- package/dist/negative.d.ts.map +1 -0
- package/dist/negative.js +40 -0
- package/dist/negative.js.map +1 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +455 -46
- package/dist/pipeline.js.map +1 -1
- package/dist/prompt-intel.d.ts +39 -0
- package/dist/prompt-intel.d.ts.map +1 -0
- package/dist/prompt-intel.js +148 -0
- package/dist/prompt-intel.js.map +1 -0
- package/dist/providers/cli-bridge.d.ts +4 -0
- package/dist/providers/cli-bridge.d.ts.map +1 -1
- package/dist/providers/cli-bridge.js +4 -0
- package/dist/providers/cli-bridge.js.map +1 -1
- package/dist/providers/generate-fn.d.ts +3 -15
- package/dist/providers/generate-fn.d.ts.map +1 -1
- package/dist/providers/generate-fn.js +3 -30
- package/dist/providers/generate-fn.js.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.d.ts +15 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +30 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/ranking/index.d.ts +9 -0
- package/dist/ranking/index.d.ts.map +1 -0
- package/dist/ranking/index.js +82 -0
- package/dist/ranking/index.js.map +1 -0
- package/dist/recursive/circuit-breaker.d.ts +36 -0
- package/dist/recursive/circuit-breaker.d.ts.map +1 -0
- package/dist/recursive/circuit-breaker.js +62 -0
- package/dist/recursive/circuit-breaker.js.map +1 -0
- package/dist/recursive/index.d.ts +4 -0
- package/dist/recursive/index.d.ts.map +1 -1
- package/dist/recursive/index.js +18 -1
- package/dist/recursive/index.js.map +1 -1
- package/dist/recursive/types.d.ts +2 -0
- package/dist/recursive/types.d.ts.map +1 -1
- package/dist/recursive/types.js +1 -0
- package/dist/recursive/types.js.map +1 -1
- package/dist/scope/diff-mapper.js.map +1 -1
- package/dist/scope/entity-diff.d.ts +58 -0
- package/dist/scope/entity-diff.d.ts.map +1 -0
- package/dist/scope/entity-diff.js +224 -0
- package/dist/scope/entity-diff.js.map +1 -0
- package/dist/scope/extractor.d.ts.map +1 -1
- package/dist/scope/extractor.js.map +1 -1
- package/dist/scope/index.d.ts +3 -1
- package/dist/scope/index.d.ts.map +1 -1
- package/dist/scope/index.js +3 -0
- package/dist/scope/index.js.map +1 -1
- package/dist/scope/parser.d.ts +1 -1
- package/dist/scope/parser.d.ts.map +1 -1
- package/dist/scope/parser.js.map +1 -1
- package/dist/scope/types.d.ts +32 -0
- package/dist/scope/types.d.ts.map +1 -1
- package/dist/scope/types.js +7 -1
- package/dist/scope/types.js.map +1 -1
- package/dist/search/index.d.ts +11 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +10 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/indexer.d.ts +67 -0
- package/dist/search/indexer.d.ts.map +1 -0
- package/dist/search/indexer.js +196 -0
- package/dist/search/indexer.js.map +1 -0
- package/dist/search/searcher.d.ts +34 -0
- package/dist/search/searcher.d.ts.map +1 -0
- package/dist/search/searcher.js +101 -0
- package/dist/search/searcher.js.map +1 -0
- package/dist/search/types.d.ts +81 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +8 -0
- package/dist/search/types.js.map +1 -0
- package/dist/self-improve/index.d.ts +53 -0
- package/dist/self-improve/index.d.ts.map +1 -0
- package/dist/self-improve/index.js +136 -0
- package/dist/self-improve/index.js.map +1 -0
- package/dist/semantic-diff/index.d.ts +31 -0
- package/dist/semantic-diff/index.d.ts.map +1 -0
- package/dist/semantic-diff/index.js +215 -0
- package/dist/semantic-diff/index.js.map +1 -0
- package/dist/testing/index.d.ts +67 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +76 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/vitest-helpers.d.ts +26 -0
- package/dist/testing/vitest-helpers.d.ts.map +1 -0
- package/dist/testing/vitest-helpers.js +37 -0
- package/dist/testing/vitest-helpers.js.map +1 -0
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/remote-query.d.ts +40 -0
- package/dist/tools/remote-query.d.ts.map +1 -0
- package/dist/tools/remote-query.js +71 -0
- package/dist/tools/remote-query.js.map +1 -0
- package/dist/tracing/index.d.ts +39 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +70 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/trajectory.d.ts +65 -0
- package/dist/trajectory.d.ts.map +1 -0
- package/dist/trajectory.js +126 -0
- package/dist/trajectory.js.map +1 -0
- package/dist/trust/index.d.ts +34 -0
- package/dist/trust/index.d.ts.map +1 -0
- package/dist/trust/index.js +78 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/types.d.ts +144 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -11
- package/dist/types.js.map +1 -1
- package/package.json +1 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context compression for static analysis tool output.
|
|
3
|
+
*
|
|
4
|
+
* Static analysis tools often return redundant, verbose output.
|
|
5
|
+
* This module compresses tool findings BEFORE sending to the LLM
|
|
6
|
+
* to reduce token usage while preserving the most important information.
|
|
7
|
+
*/
|
|
8
|
+
export interface CompressionResult {
|
|
9
|
+
original: string;
|
|
10
|
+
compressed: string;
|
|
11
|
+
reductionPercent: number;
|
|
12
|
+
droppedCount: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolFinding {
|
|
15
|
+
tool: string;
|
|
16
|
+
file: string;
|
|
17
|
+
line?: number;
|
|
18
|
+
message: string;
|
|
19
|
+
severity?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CompressOptions {
|
|
22
|
+
/** Max findings per file (default: 5) */
|
|
23
|
+
maxPerFile?: number;
|
|
24
|
+
/** Max findings per tool (default: 20) */
|
|
25
|
+
maxPerTool?: number;
|
|
26
|
+
/** Deduplicate by message prefix (default: true) */
|
|
27
|
+
deduplicateMessages?: boolean;
|
|
28
|
+
/** Rough token budget — 1 token ≈ 4 chars (default: 4000) */
|
|
29
|
+
maxTotalTokens?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Compress a list of tool findings using deduplication, per-tool and per-file caps,
|
|
33
|
+
* and a total token budget guard.
|
|
34
|
+
*
|
|
35
|
+
* @param findings - Raw findings from static analysis tools
|
|
36
|
+
* @param opts - Compression options
|
|
37
|
+
* @returns Compressed finding list + stats
|
|
38
|
+
*/
|
|
39
|
+
export declare function compressToolFindings(findings: ToolFinding[], opts?: CompressOptions): {
|
|
40
|
+
findings: ToolFinding[];
|
|
41
|
+
stats: CompressionResult;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Compress a raw static analysis block (string output from a tool).
|
|
45
|
+
*
|
|
46
|
+
* Finds repeated patterns — lines that are identical except for line numbers —
|
|
47
|
+
* and collapses them into "... and N similar issues". Returns a compressed string
|
|
48
|
+
* with reduction stats.
|
|
49
|
+
*
|
|
50
|
+
* @param rawOutput - Raw string output from a static analysis tool
|
|
51
|
+
* @param maxTokens - Max token budget (1 token ≈ 4 chars). Default: 4000
|
|
52
|
+
* @returns Compression result with original, compressed, and stats
|
|
53
|
+
*/
|
|
54
|
+
export declare function compressStaticAnalysisBlock(rawOutput: string, maxTokens?: number): CompressionResult;
|
|
55
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compress/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAsBD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,WAAW,EAAE,EACvB,IAAI,CAAC,EAAE,eAAe,GACrB;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,CA8EvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,SAAS,SAAO,GACf,iBAAiB,CAyDnB"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context compression for static analysis tool output.
|
|
3
|
+
*
|
|
4
|
+
* Static analysis tools often return redundant, verbose output.
|
|
5
|
+
* This module compresses tool findings BEFORE sending to the LLM
|
|
6
|
+
* to reduce token usage while preserving the most important information.
|
|
7
|
+
*/
|
|
8
|
+
// ─── Severity ordering ───────────────────────────────────────────
|
|
9
|
+
const SEVERITY_ORDER = {
|
|
10
|
+
critical: 0,
|
|
11
|
+
error: 1,
|
|
12
|
+
high: 2,
|
|
13
|
+
medium: 3,
|
|
14
|
+
warning: 4,
|
|
15
|
+
low: 5,
|
|
16
|
+
info: 6,
|
|
17
|
+
note: 7,
|
|
18
|
+
};
|
|
19
|
+
function severityRank(severity) {
|
|
20
|
+
if (!severity)
|
|
21
|
+
return 99;
|
|
22
|
+
return SEVERITY_ORDER[severity.toLowerCase()] ?? 99;
|
|
23
|
+
}
|
|
24
|
+
// ─── Core Functions ──────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Compress a list of tool findings using deduplication, per-tool and per-file caps,
|
|
27
|
+
* and a total token budget guard.
|
|
28
|
+
*
|
|
29
|
+
* @param findings - Raw findings from static analysis tools
|
|
30
|
+
* @param opts - Compression options
|
|
31
|
+
* @returns Compressed finding list + stats
|
|
32
|
+
*/
|
|
33
|
+
export function compressToolFindings(findings, opts) {
|
|
34
|
+
const maxPerFile = opts?.maxPerFile ?? 5;
|
|
35
|
+
const maxPerTool = opts?.maxPerTool ?? 20;
|
|
36
|
+
const dedup = opts?.deduplicateMessages ?? true;
|
|
37
|
+
const maxTotalTokens = opts?.maxTotalTokens ?? 4000;
|
|
38
|
+
const maxTotalChars = maxTotalTokens * 4;
|
|
39
|
+
const originalCount = findings.length;
|
|
40
|
+
// ── Step 1: Group by tool ──────────────────────────────────
|
|
41
|
+
const byTool = new Map();
|
|
42
|
+
for (const finding of findings) {
|
|
43
|
+
const list = byTool.get(finding.tool) ?? [];
|
|
44
|
+
list.push(finding);
|
|
45
|
+
byTool.set(finding.tool, list);
|
|
46
|
+
}
|
|
47
|
+
const compressed = [];
|
|
48
|
+
for (const [, toolFindings] of byTool) {
|
|
49
|
+
// ── Step 2: Deduplicate by message prefix (first 60 chars) ──
|
|
50
|
+
let deduped = toolFindings;
|
|
51
|
+
if (dedup) {
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
deduped = toolFindings.filter((f) => {
|
|
54
|
+
const prefix = f.message.slice(0, 60);
|
|
55
|
+
if (seen.has(prefix))
|
|
56
|
+
return false;
|
|
57
|
+
seen.add(prefix);
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// ── Step 3: Sort by severity (highest first) then cap per tool ──
|
|
62
|
+
const sorted = [...deduped].sort((a, b) => severityRank(a.severity) - severityRank(b.severity));
|
|
63
|
+
const cappedByTool = sorted.slice(0, maxPerTool);
|
|
64
|
+
// ── Step 4: Cap per file within remaining findings ──────────
|
|
65
|
+
const byFile = new Map();
|
|
66
|
+
for (const finding of cappedByTool) {
|
|
67
|
+
const list = byFile.get(finding.file) ?? [];
|
|
68
|
+
list.push(finding);
|
|
69
|
+
byFile.set(finding.file, list);
|
|
70
|
+
}
|
|
71
|
+
for (const fileFindings of byFile.values()) {
|
|
72
|
+
compressed.push(...fileFindings.slice(0, maxPerFile));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ── Step 5: Token budget guard ──────────────────────────────
|
|
76
|
+
const roughSize = (f) => (f.tool + f.file + (f.message ?? '')).length + 30;
|
|
77
|
+
let totalChars = 0;
|
|
78
|
+
const budgeted = [];
|
|
79
|
+
for (const f of compressed) {
|
|
80
|
+
const size = roughSize(f);
|
|
81
|
+
if (totalChars + size > maxTotalChars)
|
|
82
|
+
break;
|
|
83
|
+
budgeted.push(f);
|
|
84
|
+
totalChars += size;
|
|
85
|
+
}
|
|
86
|
+
const droppedCount = originalCount - budgeted.length;
|
|
87
|
+
const originalStr = JSON.stringify(findings);
|
|
88
|
+
const compressedStr = JSON.stringify(budgeted);
|
|
89
|
+
const reductionPercent = originalStr.length > 0
|
|
90
|
+
? Math.round(((originalStr.length - compressedStr.length) / originalStr.length) * 100)
|
|
91
|
+
: 0;
|
|
92
|
+
return {
|
|
93
|
+
findings: budgeted,
|
|
94
|
+
stats: {
|
|
95
|
+
original: originalStr,
|
|
96
|
+
compressed: compressedStr,
|
|
97
|
+
reductionPercent,
|
|
98
|
+
droppedCount,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Compress a raw static analysis block (string output from a tool).
|
|
104
|
+
*
|
|
105
|
+
* Finds repeated patterns — lines that are identical except for line numbers —
|
|
106
|
+
* and collapses them into "... and N similar issues". Returns a compressed string
|
|
107
|
+
* with reduction stats.
|
|
108
|
+
*
|
|
109
|
+
* @param rawOutput - Raw string output from a static analysis tool
|
|
110
|
+
* @param maxTokens - Max token budget (1 token ≈ 4 chars). Default: 4000
|
|
111
|
+
* @returns Compression result with original, compressed, and stats
|
|
112
|
+
*/
|
|
113
|
+
export function compressStaticAnalysisBlock(rawOutput, maxTokens = 4000) {
|
|
114
|
+
const lines = rawOutput.split('\n');
|
|
115
|
+
// Strip line-number references to find structurally similar lines.
|
|
116
|
+
// E.g. "src/foo.ts:123: unused variable 'x'" → "src/foo.ts:XX: unused variable 'x'"
|
|
117
|
+
const normalize = (line) => line.replace(/:\d+/g, ':XX').replace(/\b\d+\b/g, 'N');
|
|
118
|
+
// Group consecutive similar lines
|
|
119
|
+
const groups = [];
|
|
120
|
+
for (const line of lines) {
|
|
121
|
+
const key = normalize(line);
|
|
122
|
+
const last = groups[groups.length - 1];
|
|
123
|
+
if (last && last.canonical === key) {
|
|
124
|
+
last.lines.push(line);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
groups.push({ canonical: key, lines: [line] });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Collapse groups with multiple similar lines
|
|
131
|
+
const compressedLines = [];
|
|
132
|
+
for (const group of groups) {
|
|
133
|
+
if (group.lines.length === 1) {
|
|
134
|
+
const first = group.lines[0];
|
|
135
|
+
if (first !== undefined)
|
|
136
|
+
compressedLines.push(first);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const first = group.lines[0];
|
|
140
|
+
if (first !== undefined) {
|
|
141
|
+
compressedLines.push(first);
|
|
142
|
+
compressedLines.push(` ... and ${group.lines.length - 1} similar issue(s)`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
let compressed = compressedLines.join('\n');
|
|
147
|
+
// Hard-cap to token budget
|
|
148
|
+
const maxChars = maxTokens * 4;
|
|
149
|
+
if (compressed.length > maxChars) {
|
|
150
|
+
const cutoff = compressed.lastIndexOf('\n', maxChars);
|
|
151
|
+
compressed =
|
|
152
|
+
(cutoff > 0 ? compressed.slice(0, cutoff) : compressed.slice(0, maxChars)) +
|
|
153
|
+
'\n[... output truncated to fit token budget ...]';
|
|
154
|
+
}
|
|
155
|
+
const droppedCount = lines.length - compressedLines.length;
|
|
156
|
+
const reductionPercent = rawOutput.length > 0
|
|
157
|
+
? Math.round(((rawOutput.length - compressed.length) / rawOutput.length) * 100)
|
|
158
|
+
: 0;
|
|
159
|
+
return {
|
|
160
|
+
original: rawOutput,
|
|
161
|
+
compressed,
|
|
162
|
+
reductionPercent,
|
|
163
|
+
droppedCount,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compress/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost footer — calculates and formats review cost from token usage
|
|
3
|
+
* and model pricing. Appended to PR review comments so teams can
|
|
4
|
+
* track AI review spend.
|
|
5
|
+
*/
|
|
6
|
+
export interface ModelPricing {
|
|
7
|
+
inputPerMTok: number;
|
|
8
|
+
outputPerMTok: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Approximate pricing per model family. Input/output split is estimated
|
|
12
|
+
* at 70/30 when only total tokens are available.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MODEL_PRICING: Record<string, ModelPricing>;
|
|
15
|
+
export declare function getModelPricing(model: string): ModelPricing | null;
|
|
16
|
+
export interface ReviewCost {
|
|
17
|
+
totalTokens: number;
|
|
18
|
+
estimatedInputTokens: number;
|
|
19
|
+
estimatedOutputTokens: number;
|
|
20
|
+
costUSD: number;
|
|
21
|
+
model: string;
|
|
22
|
+
pricingFound: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Estimate cost from total token count and model.
|
|
26
|
+
* When only total tokens are known (no input/output split),
|
|
27
|
+
* we estimate 70% input / 30% output based on typical review patterns.
|
|
28
|
+
*/
|
|
29
|
+
export declare function calculateReviewCost(totalTokens: number, model: string, options?: {
|
|
30
|
+
inputTokens?: number;
|
|
31
|
+
outputTokens?: number;
|
|
32
|
+
}): ReviewCost;
|
|
33
|
+
/**
|
|
34
|
+
* Format cost as a compact footer line for PR comments.
|
|
35
|
+
* Returns empty string when tokens are 0 (static-only review).
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatCostFooter(cost: ReviewCost): string;
|
|
38
|
+
//# sourceMappingURL=cost-footer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-footer.d.ts","sourceRoot":"","sources":["../src/cost-footer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAiBtD,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAYlE;AAID,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,UAAU,CA6BZ;AAUD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAgBzD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost footer — calculates and formats review cost from token usage
|
|
3
|
+
* and model pricing. Appended to PR review comments so teams can
|
|
4
|
+
* track AI review spend.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Approximate pricing per model family. Input/output split is estimated
|
|
8
|
+
* at 70/30 when only total tokens are available.
|
|
9
|
+
*/
|
|
10
|
+
export const MODEL_PRICING = {
|
|
11
|
+
// Anthropic
|
|
12
|
+
'claude-opus-4': { inputPerMTok: 15, outputPerMTok: 75 },
|
|
13
|
+
'claude-sonnet-4': { inputPerMTok: 3, outputPerMTok: 15 },
|
|
14
|
+
'claude-haiku-4': { inputPerMTok: 0.8, outputPerMTok: 4 },
|
|
15
|
+
'claude-3.5-sonnet': { inputPerMTok: 3, outputPerMTok: 15 },
|
|
16
|
+
'claude-3-haiku': { inputPerMTok: 0.25, outputPerMTok: 1.25 },
|
|
17
|
+
// OpenAI
|
|
18
|
+
'gpt-4o': { inputPerMTok: 2.5, outputPerMTok: 10 },
|
|
19
|
+
'gpt-4o-mini': { inputPerMTok: 0.15, outputPerMTok: 0.6 },
|
|
20
|
+
'gpt-4-turbo': { inputPerMTok: 10, outputPerMTok: 30 },
|
|
21
|
+
// Google
|
|
22
|
+
'gemini-2.5-pro': { inputPerMTok: 1.25, outputPerMTok: 10 },
|
|
23
|
+
'gemini-2.5-flash': { inputPerMTok: 0.15, outputPerMTok: 0.6 },
|
|
24
|
+
// Groq (free tier — cost is effectively 0)
|
|
25
|
+
'llama-3': { inputPerMTok: 0, outputPerMTok: 0 },
|
|
26
|
+
mixtral: { inputPerMTok: 0, outputPerMTok: 0 },
|
|
27
|
+
};
|
|
28
|
+
export function getModelPricing(model) {
|
|
29
|
+
// Direct match
|
|
30
|
+
if (MODEL_PRICING[model])
|
|
31
|
+
return MODEL_PRICING[model];
|
|
32
|
+
// Prefix match (handles version suffixes like claude-sonnet-4-20250514)
|
|
33
|
+
for (const [key, pricing] of Object.entries(MODEL_PRICING)) {
|
|
34
|
+
if (model.includes(key) || key.includes(model.split('-').slice(0, -1).join('-'))) {
|
|
35
|
+
return pricing;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Estimate cost from total token count and model.
|
|
42
|
+
* When only total tokens are known (no input/output split),
|
|
43
|
+
* we estimate 70% input / 30% output based on typical review patterns.
|
|
44
|
+
*/
|
|
45
|
+
export function calculateReviewCost(totalTokens, model, options) {
|
|
46
|
+
const pricing = getModelPricing(model);
|
|
47
|
+
const inputTokens = options?.inputTokens ?? Math.round(totalTokens * 0.7);
|
|
48
|
+
const outputTokens = options?.outputTokens ?? Math.round(totalTokens * 0.3);
|
|
49
|
+
if (!pricing) {
|
|
50
|
+
return {
|
|
51
|
+
totalTokens,
|
|
52
|
+
estimatedInputTokens: inputTokens,
|
|
53
|
+
estimatedOutputTokens: outputTokens,
|
|
54
|
+
costUSD: 0,
|
|
55
|
+
model,
|
|
56
|
+
pricingFound: false,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const cost = (inputTokens / 1_000_000) * pricing.inputPerMTok +
|
|
60
|
+
(outputTokens / 1_000_000) * pricing.outputPerMTok;
|
|
61
|
+
return {
|
|
62
|
+
totalTokens,
|
|
63
|
+
estimatedInputTokens: inputTokens,
|
|
64
|
+
estimatedOutputTokens: outputTokens,
|
|
65
|
+
costUSD: Math.round(cost * 10000) / 10000,
|
|
66
|
+
model,
|
|
67
|
+
pricingFound: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ── Formatting ──
|
|
71
|
+
function formatTokens(n) {
|
|
72
|
+
if (n >= 1_000_000)
|
|
73
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
74
|
+
if (n >= 1_000)
|
|
75
|
+
return `${(n / 1_000).toFixed(0)}K`;
|
|
76
|
+
return String(n);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Format cost as a compact footer line for PR comments.
|
|
80
|
+
* Returns empty string when tokens are 0 (static-only review).
|
|
81
|
+
*/
|
|
82
|
+
export function formatCostFooter(cost) {
|
|
83
|
+
if (cost.totalTokens === 0)
|
|
84
|
+
return '';
|
|
85
|
+
const tokens = formatTokens(cost.totalTokens);
|
|
86
|
+
if (!cost.pricingFound) {
|
|
87
|
+
return `\n<sub>📊 ${tokens} tokens · \`${cost.model}\` · pricing unavailable</sub>\n`;
|
|
88
|
+
}
|
|
89
|
+
if (cost.costUSD === 0) {
|
|
90
|
+
return `\n<sub>📊 ${tokens} tokens · \`${cost.model}\` · free tier</sub>\n`;
|
|
91
|
+
}
|
|
92
|
+
const dollars = cost.costUSD >= 1 ? `$${cost.costUSD.toFixed(2)}` : `$${cost.costUSD.toFixed(4)}`;
|
|
93
|
+
return `\n<sub>📊 ${tokens} tokens · ${dollars} · \`${cost.model}\`</sub>\n`;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=cost-footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-footer.js","sourceRoot":"","sources":["../src/cost-footer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dual-critique review loop implementation.
|
|
3
|
+
*
|
|
4
|
+
* 3-agent pattern: initial review → self-critique → refined review.
|
|
5
|
+
* The self-critique step catches overreactions, false positives, and
|
|
6
|
+
* vague findings, producing a higher-quality final review.
|
|
7
|
+
*/
|
|
8
|
+
import type { GenerateTextFn } from '../providers/generate-fn.js';
|
|
9
|
+
import type { ProgressCallback, ReviewFinding, ReviewResult } from '../types.js';
|
|
10
|
+
import type { CritiqueResult, DualCritiqueInput, DualCritiqueResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Parse the self-critique agent's structured response.
|
|
13
|
+
*
|
|
14
|
+
* Extracts OVERALL_ASSESSMENT and individual CRITIQUES with
|
|
15
|
+
* FINDING_INDEX, VERDICT, REASONING, and optional SUGGESTED_SEVERITY.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseCritiqueResponse(text: string): CritiqueResult;
|
|
18
|
+
/**
|
|
19
|
+
* Apply critique verdicts to the initial findings.
|
|
20
|
+
* Returns the filtered and adjusted findings.
|
|
21
|
+
*/
|
|
22
|
+
export declare function applyCritique(findings: ReviewFinding[], critique: CritiqueResult): {
|
|
23
|
+
refined: ReviewFinding[];
|
|
24
|
+
removedCount: number;
|
|
25
|
+
adjustedCount: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Run the dual-critique review loop.
|
|
29
|
+
*
|
|
30
|
+
* Takes an already-completed initial review and runs it through
|
|
31
|
+
* the self-critique → refined review pipeline.
|
|
32
|
+
*
|
|
33
|
+
* @param initialReview - The initial review result from any agent mode
|
|
34
|
+
* @param input - Context needed for the critique agents
|
|
35
|
+
* @param generateFn - LLM generation function
|
|
36
|
+
* @param onProgress - Optional progress callback
|
|
37
|
+
* @returns DualCritiqueResult with refined findings
|
|
38
|
+
*/
|
|
39
|
+
export declare function runDualCritique(initialReview: ReviewResult, input: DualCritiqueInput, generateFn: GenerateTextFn, onProgress?: ProgressCallback): Promise<DualCritiqueResult>;
|
|
40
|
+
//# sourceMappingURL=critique.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"critique.d.ts","sourceRoot":"","sources":["../../src/critique/critique.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAmB,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAElG,OAAO,KAAK,EACV,cAAc,EAGd,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAiBpB;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAwClE;AAoBD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EAAE,EACzB,QAAQ,EAAE,cAAc,GACvB;IACD,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB,CA6CA;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,YAAY,EAC3B,KAAK,EAAE,iBAAiB,EACxB,UAAU,EAAE,cAAc,EAC1B,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAqF7B"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dual-critique review loop implementation.
|
|
3
|
+
*
|
|
4
|
+
* 3-agent pattern: initial review → self-critique → refined review.
|
|
5
|
+
* The self-critique step catches overreactions, false positives, and
|
|
6
|
+
* vague findings, producing a higher-quality final review.
|
|
7
|
+
*/
|
|
8
|
+
import { REFINED_REVIEW_SYSTEM, SELF_CRITIQUE_SYSTEM } from './prompts.js';
|
|
9
|
+
import { DEFAULT_DUAL_CRITIQUE_CONFIG } from './types.js';
|
|
10
|
+
// ─── Constants ─────────────────────────────────────────────────
|
|
11
|
+
const VALID_VERDICTS = new Set([
|
|
12
|
+
'valid',
|
|
13
|
+
'false-positive',
|
|
14
|
+
'overreaction',
|
|
15
|
+
'vague',
|
|
16
|
+
'redundant',
|
|
17
|
+
]);
|
|
18
|
+
const VALID_SEVERITIES = new Set(['critical', 'high', 'medium', 'low', 'info']);
|
|
19
|
+
// ─── Critique Parser ───────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Parse the self-critique agent's structured response.
|
|
22
|
+
*
|
|
23
|
+
* Extracts OVERALL_ASSESSMENT and individual CRITIQUES with
|
|
24
|
+
* FINDING_INDEX, VERDICT, REASONING, and optional SUGGESTED_SEVERITY.
|
|
25
|
+
*/
|
|
26
|
+
export function parseCritiqueResponse(text) {
|
|
27
|
+
// Extract overall assessment
|
|
28
|
+
const assessmentMatch = /OVERALL_ASSESSMENT:\s*(.+?)(?:\n\s*CRITIQUES:|$)/is.exec(text);
|
|
29
|
+
const overallAssessment = assessmentMatch?.[1]?.trim() ?? 'Assessment could not be parsed.';
|
|
30
|
+
// Extract individual critiques
|
|
31
|
+
const critiques = [];
|
|
32
|
+
const critiquePattern = /- FINDING_INDEX:\s*(\d+)\s*\n\s*VERDICT:\s*(\S+)\s*\n\s*REASONING:\s*(.+?)(?:\n\s*SUGGESTED_SEVERITY:\s*(\S+))?(?=\n\s*- FINDING_INDEX:|\n*$)/gis;
|
|
33
|
+
let match = critiquePattern.exec(text);
|
|
34
|
+
while (match !== null) {
|
|
35
|
+
const findingIndex = parseInt(match[1], 10);
|
|
36
|
+
const rawVerdict = match[2]?.toLowerCase();
|
|
37
|
+
const verdict = VALID_VERDICTS.has(rawVerdict) ? rawVerdict : 'valid';
|
|
38
|
+
const reasoning = match[3]?.trim() ?? '';
|
|
39
|
+
const critique = { findingIndex, verdict, reasoning };
|
|
40
|
+
if (verdict === 'overreaction' && match[4]) {
|
|
41
|
+
const rawSeverity = match[4].toLowerCase();
|
|
42
|
+
if (VALID_SEVERITIES.has(rawSeverity)) {
|
|
43
|
+
critique.suggestedSeverity = rawSeverity;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
critiques.push(critique);
|
|
47
|
+
match = critiquePattern.exec(text);
|
|
48
|
+
}
|
|
49
|
+
const falsePositiveCount = critiques.filter((c) => c.verdict === 'false-positive').length;
|
|
50
|
+
const overreactionCount = critiques.filter((c) => c.verdict === 'overreaction').length;
|
|
51
|
+
return {
|
|
52
|
+
critiques,
|
|
53
|
+
overallAssessment,
|
|
54
|
+
falsePositiveCount,
|
|
55
|
+
overreactionCount,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// ─── Finding Serializer ────────────────────────────────────────
|
|
59
|
+
/**
|
|
60
|
+
* Serialize findings into a text block for the critique agent.
|
|
61
|
+
*/
|
|
62
|
+
function serializeFindingsForCritique(findings) {
|
|
63
|
+
if (findings.length === 0)
|
|
64
|
+
return '(no findings)';
|
|
65
|
+
return findings
|
|
66
|
+
.map((f, i) => `[${i}] ${f.severity.toUpperCase()} | ${f.category} | ${f.file}:${f.line ?? 'N/A'}\n ${f.message}${f.suggestion ? `\n Suggestion: ${f.suggestion}` : ''}`)
|
|
67
|
+
.join('\n\n');
|
|
68
|
+
}
|
|
69
|
+
// ─── Apply Critique ────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Apply critique verdicts to the initial findings.
|
|
72
|
+
* Returns the filtered and adjusted findings.
|
|
73
|
+
*/
|
|
74
|
+
export function applyCritique(findings, critique) {
|
|
75
|
+
// Build a map of critique by finding index
|
|
76
|
+
const critiqueMap = new Map();
|
|
77
|
+
for (const c of critique.critiques) {
|
|
78
|
+
critiqueMap.set(c.findingIndex, c);
|
|
79
|
+
}
|
|
80
|
+
const refined = [];
|
|
81
|
+
let removedCount = 0;
|
|
82
|
+
let adjustedCount = 0;
|
|
83
|
+
for (let i = 0; i < findings.length; i++) {
|
|
84
|
+
const finding = findings[i];
|
|
85
|
+
const crit = critiqueMap.get(i);
|
|
86
|
+
if (!crit) {
|
|
87
|
+
// No critique for this finding — keep as-is
|
|
88
|
+
refined.push(finding);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
switch (crit.verdict) {
|
|
92
|
+
case 'false-positive':
|
|
93
|
+
case 'redundant':
|
|
94
|
+
removedCount++;
|
|
95
|
+
break;
|
|
96
|
+
case 'overreaction':
|
|
97
|
+
if (crit.suggestedSeverity) {
|
|
98
|
+
refined.push({ ...finding, severity: crit.suggestedSeverity });
|
|
99
|
+
adjustedCount++;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
refined.push(finding);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case 'vague':
|
|
106
|
+
case 'valid':
|
|
107
|
+
default:
|
|
108
|
+
refined.push(finding);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { refined, removedCount, adjustedCount };
|
|
113
|
+
}
|
|
114
|
+
// ─── Main Function ─────────────────────────────────────────────
|
|
115
|
+
/**
|
|
116
|
+
* Run the dual-critique review loop.
|
|
117
|
+
*
|
|
118
|
+
* Takes an already-completed initial review and runs it through
|
|
119
|
+
* the self-critique → refined review pipeline.
|
|
120
|
+
*
|
|
121
|
+
* @param initialReview - The initial review result from any agent mode
|
|
122
|
+
* @param input - Context needed for the critique agents
|
|
123
|
+
* @param generateFn - LLM generation function
|
|
124
|
+
* @param onProgress - Optional progress callback
|
|
125
|
+
* @returns DualCritiqueResult with refined findings
|
|
126
|
+
*/
|
|
127
|
+
export async function runDualCritique(initialReview, input, generateFn, onProgress) {
|
|
128
|
+
const emit = onProgress ?? (() => { });
|
|
129
|
+
const config = {
|
|
130
|
+
...DEFAULT_DUAL_CRITIQUE_CONFIG,
|
|
131
|
+
...input.config,
|
|
132
|
+
};
|
|
133
|
+
const initialFindings = initialReview.findings.filter((f) => f.source === 'ai');
|
|
134
|
+
// Short-circuit: not enough findings to justify critique
|
|
135
|
+
if (initialFindings.length < config.minFindingsForCritique) {
|
|
136
|
+
emit({
|
|
137
|
+
step: 'dual-critique',
|
|
138
|
+
message: `Skipping critique — only ${initialFindings.length} AI finding(s) (min: ${config.minFindingsForCritique})`,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
status: initialReview.status,
|
|
142
|
+
summary: initialReview.summary,
|
|
143
|
+
findings: initialReview.findings,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// ── Step 1: Self-Critique ────────────────────────────────────
|
|
147
|
+
emit({
|
|
148
|
+
step: 'dual-critique',
|
|
149
|
+
message: `Running self-critique on ${initialFindings.length} AI finding(s)...`,
|
|
150
|
+
});
|
|
151
|
+
const critiquePrompt = `Here is the code diff:\n\n${input.diff}\n\nHere is the initial review with ${initialFindings.length} findings:\n\n${serializeFindingsForCritique(initialFindings)}\n\nPlease critique each finding.`;
|
|
152
|
+
const critiqueResponse = await generateFn(SELF_CRITIQUE_SYSTEM, critiquePrompt);
|
|
153
|
+
const critiqueResult = parseCritiqueResponse(critiqueResponse.text);
|
|
154
|
+
emit({
|
|
155
|
+
step: 'dual-critique',
|
|
156
|
+
message: `Critique complete: ${critiqueResult.falsePositiveCount} false positive(s), ${critiqueResult.overreactionCount} overreaction(s)`,
|
|
157
|
+
});
|
|
158
|
+
// ── Step 2: Apply Critique (deterministic) ───────────────────
|
|
159
|
+
// Apply the critique verdicts to filter/adjust findings
|
|
160
|
+
const { refined, removedCount, adjustedCount } = applyCritique(initialFindings, critiqueResult);
|
|
161
|
+
// Merge back non-AI findings (static analysis) untouched
|
|
162
|
+
const nonAiFindings = initialReview.findings.filter((f) => f.source !== 'ai');
|
|
163
|
+
const allRefinedFindings = [...refined, ...nonAiFindings];
|
|
164
|
+
emit({
|
|
165
|
+
step: 'dual-critique',
|
|
166
|
+
message: `Refined: ${removedCount} removed, ${adjustedCount} adjusted, ${refined.length} kept`,
|
|
167
|
+
});
|
|
168
|
+
// ── Step 3: Refined Summary ──────────────────────────────────
|
|
169
|
+
// Ask the LLM to produce a refined summary based on the surviving findings
|
|
170
|
+
const refinedPrompt = `Here is the code diff:\n\n${input.diff}\n\nInitial review summary: ${initialReview.summary}\n\nSelf-critique assessment: ${critiqueResult.overallAssessment}\n\nRemaining findings after critique (${refined.length}):\n${serializeFindingsForCritique(refined)}\n\nPlease produce the refined review.`;
|
|
171
|
+
const refinedResponse = await generateFn(REFINED_REVIEW_SYSTEM, refinedPrompt);
|
|
172
|
+
// Extract refined status and summary from response
|
|
173
|
+
const statusMatch = /STATUS:\s*(PASSED|FAILED|NEEDS_HUMAN_REVIEW|SKIPPED)/i.exec(refinedResponse.text);
|
|
174
|
+
const refinedStatus = statusMatch?.[1]?.toUpperCase() ?? initialReview.status;
|
|
175
|
+
const summaryMatch = /SUMMARY:\s*(.+?)(?:\n(?:FINDINGS:|$))/is.exec(refinedResponse.text);
|
|
176
|
+
const refinedSummary = summaryMatch?.[1]?.trim() ?? initialReview.summary;
|
|
177
|
+
// Build result
|
|
178
|
+
const result = {
|
|
179
|
+
status: refinedStatus,
|
|
180
|
+
summary: refinedSummary,
|
|
181
|
+
findings: allRefinedFindings,
|
|
182
|
+
};
|
|
183
|
+
if (config.includeCritiqueMetadata) {
|
|
184
|
+
result.critiqueMetadata = {
|
|
185
|
+
initialFindingCount: initialFindings.length,
|
|
186
|
+
finalFindingCount: refined.length,
|
|
187
|
+
removedAsFalsePositive: removedCount,
|
|
188
|
+
severityAdjusted: adjustedCount,
|
|
189
|
+
critiqueResult,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=critique.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"critique.js","sourceRoot":"","sources":["../../src/critique/critique.ts"],"names":[],"mappings":"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"}
|