tryassay 0.28.2 → 0.30.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/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/assess.js +4 -2
- package/dist/commands/assess.js.map +1 -1
- package/dist/commands/generate.js +1 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/harvest.d.ts +9 -0
- package/dist/commands/harvest.js +76 -0
- package/dist/commands/harvest.js.map +1 -0
- package/dist/lib/__tests__/learned-rules.test.d.ts +1 -0
- package/dist/lib/__tests__/learned-rules.test.js +260 -0
- package/dist/lib/__tests__/learned-rules.test.js.map +1 -0
- package/dist/lib/__tests__/pr-harvester-types.test.d.ts +1 -0
- package/dist/lib/__tests__/pr-harvester-types.test.js +43 -0
- package/dist/lib/__tests__/pr-harvester-types.test.js.map +1 -0
- package/dist/lib/__tests__/pr-harvester.test.d.ts +1 -0
- package/dist/lib/__tests__/pr-harvester.test.js +341 -0
- package/dist/lib/__tests__/pr-harvester.test.js.map +1 -0
- package/dist/lib/__tests__/rule-harvester.test.d.ts +1 -0
- package/dist/lib/__tests__/rule-harvester.test.js +526 -0
- package/dist/lib/__tests__/rule-harvester.test.js.map +1 -0
- package/dist/lib/claim-extractor.d.ts +1 -0
- package/dist/lib/claim-extractor.js +116 -15
- package/dist/lib/claim-extractor.js.map +1 -1
- package/dist/lib/code-verifier.d.ts +12 -1
- package/dist/lib/code-verifier.js +155 -12
- package/dist/lib/code-verifier.js.map +1 -1
- package/dist/lib/learned-rules/category-map.d.ts +28 -0
- package/dist/lib/learned-rules/category-map.js +110 -0
- package/dist/lib/learned-rules/category-map.js.map +1 -0
- package/dist/lib/learned-rules/index.d.ts +105 -0
- package/dist/lib/learned-rules/index.js +198 -0
- package/dist/lib/learned-rules/index.js.map +1 -0
- package/dist/lib/learned-rules/learned-catalog.d.ts +62 -0
- package/dist/lib/learned-rules/learned-catalog.js +161 -0
- package/dist/lib/learned-rules/learned-catalog.js.map +1 -0
- package/dist/lib/learned-rules/pattern-extractor.d.ts +25 -0
- package/dist/lib/learned-rules/pattern-extractor.js +351 -0
- package/dist/lib/learned-rules/pattern-extractor.js.map +1 -0
- package/dist/lib/learned-rules/rule-codifier.d.ts +41 -0
- package/dist/lib/learned-rules/rule-codifier.js +138 -0
- package/dist/lib/learned-rules/rule-codifier.js.map +1 -0
- package/dist/lib/learned-rules/starter-catalog.d.ts +16 -0
- package/dist/lib/learned-rules/starter-catalog.js +402 -0
- package/dist/lib/learned-rules/starter-catalog.js.map +1 -0
- package/dist/lib/learned-rules/types.d.ts +196 -0
- package/dist/lib/learned-rules/types.js +9 -0
- package/dist/lib/learned-rules/types.js.map +1 -0
- package/dist/lib/learned-rules/validation-harness.d.ts +26 -0
- package/dist/lib/learned-rules/validation-harness.js +260 -0
- package/dist/lib/learned-rules/validation-harness.js.map +1 -0
- package/dist/lib/llm-provider.d.ts +7 -0
- package/dist/lib/llm-provider.js +99 -6
- package/dist/lib/llm-provider.js.map +1 -1
- package/dist/lib/rule-harvester/diff-parser.d.ts +9 -0
- package/dist/lib/rule-harvester/diff-parser.js +77 -0
- package/dist/lib/rule-harvester/diff-parser.js.map +1 -0
- package/dist/lib/rule-harvester/file-selector.d.ts +10 -0
- package/dist/lib/rule-harvester/file-selector.js +59 -0
- package/dist/lib/rule-harvester/file-selector.js.map +1 -0
- package/dist/lib/rule-harvester/ground-truth.d.ts +19 -0
- package/dist/lib/rule-harvester/ground-truth.js +156 -0
- package/dist/lib/rule-harvester/ground-truth.js.map +1 -0
- package/dist/lib/rule-harvester/harvest.d.ts +26 -0
- package/dist/lib/rule-harvester/harvest.js +307 -0
- package/dist/lib/rule-harvester/harvest.js.map +1 -0
- package/dist/lib/rule-harvester/pr-discovery.d.ts +49 -0
- package/dist/lib/rule-harvester/pr-discovery.js +168 -0
- package/dist/lib/rule-harvester/pr-discovery.js.map +1 -0
- package/dist/lib/rule-harvester/pr-harvest.d.ts +53 -0
- package/dist/lib/rule-harvester/pr-harvest.js +326 -0
- package/dist/lib/rule-harvester/pr-harvest.js.map +1 -0
- package/dist/lib/rule-harvester/progress.d.ts +13 -0
- package/dist/lib/rule-harvester/progress.js +50 -0
- package/dist/lib/rule-harvester/progress.js.map +1 -0
- package/dist/lib/rule-harvester/reporter.d.ts +35 -0
- package/dist/lib/rule-harvester/reporter.js +46 -0
- package/dist/lib/rule-harvester/reporter.js.map +1 -0
- package/dist/lib/rule-harvester/rule-generalizer.d.ts +25 -0
- package/dist/lib/rule-harvester/rule-generalizer.js +135 -0
- package/dist/lib/rule-harvester/rule-generalizer.js.map +1 -0
- package/dist/lib/rule-harvester/scanner.d.ts +20 -0
- package/dist/lib/rule-harvester/scanner.js +37 -0
- package/dist/lib/rule-harvester/scanner.js.map +1 -0
- package/dist/runtime/types.d.ts +1 -1
- package/dist/sdk/forward-verify.d.ts +3 -1
- package/dist/sdk/forward-verify.js +68 -5
- package/dist/sdk/forward-verify.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +7 -5
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/types.d.ts +21 -0
- package/package.json +1 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { parsePatch } from './diff-parser.js';
|
|
3
|
+
// ── Constants ──────────────────────────────────────────────────
|
|
4
|
+
/** Default labels that indicate a bug-fix PR. Matched case-insensitively as substrings. */
|
|
5
|
+
export const DEFAULT_BUG_LABELS = [
|
|
6
|
+
'bug',
|
|
7
|
+
'fix',
|
|
8
|
+
'bugfix',
|
|
9
|
+
'hotfix',
|
|
10
|
+
'security',
|
|
11
|
+
'patch',
|
|
12
|
+
'defect',
|
|
13
|
+
'regression',
|
|
14
|
+
];
|
|
15
|
+
/** File extensions we mine patterns from. */
|
|
16
|
+
const TARGET_EXTENSIONS = /\.(tsx?|jsx?|py)$/;
|
|
17
|
+
/** Paths that indicate test files — excluded from mining. */
|
|
18
|
+
const TEST_PATH_PATTERNS = /\.(test|spec)\.[tj]sx?$|__tests__[/\\]|tests?[/\\]|_test\.py$|test_[^/\\]+\.py$/;
|
|
19
|
+
/** Declaration files — excluded from mining. */
|
|
20
|
+
const DECLARATION_PATTERN = /\.d\.ts$|\.pyi$/;
|
|
21
|
+
// ── Pure Filter Functions (unit-testable) ──────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Returns true if any label in the array contains a bug-related keyword.
|
|
24
|
+
* Matches case-insensitively. Accepts optional custom bug label list.
|
|
25
|
+
*/
|
|
26
|
+
export function matchesBugLabels(labels, bugLabels = DEFAULT_BUG_LABELS) {
|
|
27
|
+
const lower = labels.map((l) => l.toLowerCase());
|
|
28
|
+
return lower.some((label) => bugLabels.some((keyword) => label.includes(keyword)));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns true if the PR title matches common bug-fix prefixes.
|
|
32
|
+
* Looks for fix/bug/resolve/patch at the start or after a conventional commit prefix.
|
|
33
|
+
*/
|
|
34
|
+
export function matchesBugTitle(title) {
|
|
35
|
+
return /\b(fix|bug|resolve|hotfix|patch)\b/i.test(title);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns true if the file path is a TypeScript/JavaScript source file
|
|
39
|
+
* that is NOT a test file or declaration file.
|
|
40
|
+
*/
|
|
41
|
+
export function isTargetFile(path) {
|
|
42
|
+
if (!TARGET_EXTENSIONS.test(path))
|
|
43
|
+
return false;
|
|
44
|
+
if (TEST_PATH_PATTERNS.test(path))
|
|
45
|
+
return false;
|
|
46
|
+
if (DECLARATION_PATTERN.test(path))
|
|
47
|
+
return false;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Call the `gh api` CLI and return parsed JSON.
|
|
52
|
+
* Relies on gh's built-in auth and rate-limit handling.
|
|
53
|
+
*/
|
|
54
|
+
function ghApi(endpoint) {
|
|
55
|
+
const raw = execSync(`gh api "${endpoint}" --paginate`, {
|
|
56
|
+
encoding: 'utf-8',
|
|
57
|
+
maxBuffer: 50 * 1024 * 1024, // 50 MB — large repos can have big diffs
|
|
58
|
+
timeout: 60_000,
|
|
59
|
+
});
|
|
60
|
+
return JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fetch a single page from the GitHub API (no --paginate).
|
|
64
|
+
*/
|
|
65
|
+
function ghApiPage(endpoint) {
|
|
66
|
+
const raw = execSync(`gh api "${endpoint}"`, {
|
|
67
|
+
encoding: 'utf-8',
|
|
68
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
69
|
+
timeout: 60_000,
|
|
70
|
+
});
|
|
71
|
+
return JSON.parse(raw);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Discover merged bug-fix PRs from a GitHub repo.
|
|
75
|
+
*
|
|
76
|
+
* Flow:
|
|
77
|
+
* 1. Fetch closed PRs (paginated)
|
|
78
|
+
* 2. Filter to merged-only (merged_at !== null)
|
|
79
|
+
* 3. Filter by bug labels (with optional title fallback)
|
|
80
|
+
* 4. Optionally enrich with review comments
|
|
81
|
+
* 5. Collect changed file paths
|
|
82
|
+
*/
|
|
83
|
+
export function discoverBugFixPRs(owner, name, config = {}) {
|
|
84
|
+
const { perPage = 30, maxPages = 3, bugLabels = DEFAULT_BUG_LABELS, titleFallback = true, fetchComments = true, } = config;
|
|
85
|
+
const discovered = [];
|
|
86
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
87
|
+
const endpoint = `/repos/${owner}/${name}/pulls?state=closed&sort=updated&direction=desc&per_page=${perPage}&page=${page}`;
|
|
88
|
+
let prs;
|
|
89
|
+
try {
|
|
90
|
+
prs = ghApiPage(endpoint);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// If the API call fails (auth, network, etc.), stop pagination
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
if (!prs || prs.length === 0)
|
|
97
|
+
break;
|
|
98
|
+
for (const pr of prs) {
|
|
99
|
+
// Only merged PRs
|
|
100
|
+
if (!pr.merged_at || !pr.merge_commit_sha)
|
|
101
|
+
continue;
|
|
102
|
+
const labelNames = pr.labels.map((l) => l.name);
|
|
103
|
+
const hasBugLabel = matchesBugLabels(labelNames, bugLabels);
|
|
104
|
+
const hasBugTitle = titleFallback && matchesBugTitle(pr.title);
|
|
105
|
+
if (!hasBugLabel && !hasBugTitle)
|
|
106
|
+
continue;
|
|
107
|
+
// Fetch file list for this PR
|
|
108
|
+
let files = [];
|
|
109
|
+
try {
|
|
110
|
+
const prFiles = ghApi(`/repos/${owner}/${name}/pulls/${pr.number}/files`);
|
|
111
|
+
files = prFiles.map((f) => f.filename);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// If we can't get files, still include the PR with empty files
|
|
115
|
+
}
|
|
116
|
+
// Fetch review comments if requested
|
|
117
|
+
let reviewComments = [];
|
|
118
|
+
if (fetchComments) {
|
|
119
|
+
try {
|
|
120
|
+
const comments = ghApi(`/repos/${owner}/${name}/pulls/${pr.number}/comments`);
|
|
121
|
+
reviewComments = comments.map((c) => ({
|
|
122
|
+
body: c.body,
|
|
123
|
+
path: c.path,
|
|
124
|
+
line: c.line ?? c.original_line ?? null,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Review comments are optional enrichment
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
discovered.push({
|
|
132
|
+
repo: `${owner}/${name}`,
|
|
133
|
+
prNumber: pr.number,
|
|
134
|
+
title: pr.title,
|
|
135
|
+
labels: labelNames,
|
|
136
|
+
mergeCommit: pr.merge_commit_sha,
|
|
137
|
+
reviewComments,
|
|
138
|
+
files,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return discovered;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Fetch and parse diffs for a discovered PR.
|
|
146
|
+
*
|
|
147
|
+
* Calls the files endpoint, filters to target files,
|
|
148
|
+
* and parses each file's patch into typed DiffHunks.
|
|
149
|
+
*/
|
|
150
|
+
export function fetchPRDiffs(owner, name, pr) {
|
|
151
|
+
let allHunks = [];
|
|
152
|
+
try {
|
|
153
|
+
const files = ghApi(`/repos/${owner}/${name}/pulls/${pr.prNumber}/files`);
|
|
154
|
+
for (const file of files) {
|
|
155
|
+
if (!isTargetFile(file.filename))
|
|
156
|
+
continue;
|
|
157
|
+
if (!file.patch)
|
|
158
|
+
continue;
|
|
159
|
+
const hunks = parsePatch(file.filename, file.patch);
|
|
160
|
+
allHunks = allHunks.concat(hunks);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Return empty hunks if API call fails
|
|
165
|
+
}
|
|
166
|
+
return { pr, hunks: allHunks };
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=pr-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-discovery.js","sourceRoot":"","sources":["../../../src/lib/rule-harvester/pr-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Harvest Orchestrator — ties discovery -> extraction -> generalization -> catalog
|
|
3
|
+
* into a complete pipeline for mining bug-fix PRs from public GitHub repos.
|
|
4
|
+
*
|
|
5
|
+
* PR-sourced rules are validated through the validation harness before promotion.
|
|
6
|
+
* Fuzzy deduplication via Dice coefficient prevents near-duplicate rules.
|
|
7
|
+
*/
|
|
8
|
+
import type { LearnedRule } from '../learned-rules/types.js';
|
|
9
|
+
/** Per-repo set of processed PR numbers. */
|
|
10
|
+
export type PRProgress = Record<string, number[]>;
|
|
11
|
+
export declare function createPRProgress(): PRProgress;
|
|
12
|
+
export declare function markPRProcessed(progress: PRProgress, repo: string, prNumber: number): PRProgress;
|
|
13
|
+
export declare function isPRProcessed(progress: PRProgress, repo: string, prNumber: number): boolean;
|
|
14
|
+
export declare function getPRProgressStats(progress: PRProgress, repo: string): {
|
|
15
|
+
processedPRs: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function loadPRProgress(dir: string): Promise<PRProgress>;
|
|
18
|
+
export declare function savePRProgress(dir: string, progress: PRProgress): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Dice coefficient (bigram overlap) for fuzzy string similarity.
|
|
21
|
+
* Returns a value between 0 (no overlap) and 1 (identical).
|
|
22
|
+
*/
|
|
23
|
+
export declare function diceCoefficient(a: string, b: string): number;
|
|
24
|
+
/**
|
|
25
|
+
* Find the most similar existing rule by description, if above threshold.
|
|
26
|
+
*/
|
|
27
|
+
export declare function findFuzzyDuplicate(existingRules: LearnedRule[], description: string, category: string): LearnedRule | null;
|
|
28
|
+
export interface PRHarvestConfig {
|
|
29
|
+
/** List of repos to mine PRs from. */
|
|
30
|
+
repoList: Array<{
|
|
31
|
+
owner: string;
|
|
32
|
+
name: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Assay project root where rules go. */
|
|
35
|
+
catalogPath: string;
|
|
36
|
+
/** Where pr-progress.json lives. */
|
|
37
|
+
progressDir: string;
|
|
38
|
+
/** Where run reports go. */
|
|
39
|
+
runsDir: string;
|
|
40
|
+
/** Model name for reporting. */
|
|
41
|
+
model: string;
|
|
42
|
+
/** Max repos to process. */
|
|
43
|
+
limit?: number;
|
|
44
|
+
/** Only scan these repos (owner/name format). */
|
|
45
|
+
repoFilter?: string[];
|
|
46
|
+
/** Skip already-processed PRs. */
|
|
47
|
+
resume?: boolean;
|
|
48
|
+
/** Max PRs per repo. */
|
|
49
|
+
maxPRsPerRepo?: number;
|
|
50
|
+
/** Logging callback. */
|
|
51
|
+
onLog?: (msg: string) => void;
|
|
52
|
+
}
|
|
53
|
+
export declare function harvestPRs(config: PRHarvestConfig): Promise<void>;
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Harvest Orchestrator — ties discovery -> extraction -> generalization -> catalog
|
|
3
|
+
* into a complete pipeline for mining bug-fix PRs from public GitHub repos.
|
|
4
|
+
*
|
|
5
|
+
* PR-sourced rules are validated through the validation harness before promotion.
|
|
6
|
+
* Fuzzy deduplication via Dice coefficient prevents near-duplicate rules.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { discoverBugFixPRs, fetchPRDiffs } from './pr-discovery.js';
|
|
11
|
+
import { filterHunks } from './diff-parser.js';
|
|
12
|
+
import { generalizeHunk, mapToExtractedPattern } from './rule-generalizer.js';
|
|
13
|
+
import { addRule, updateRule, loadRules, loadStats } from '../learned-rules/learned-catalog.js';
|
|
14
|
+
import { validateRule } from '../learned-rules/validation-harness.js';
|
|
15
|
+
import { saveRunReport } from './reporter.js';
|
|
16
|
+
export function createPRProgress() {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
export function markPRProcessed(progress, repo, prNumber) {
|
|
20
|
+
const existing = progress[repo] ?? [];
|
|
21
|
+
if (existing.includes(prNumber))
|
|
22
|
+
return progress;
|
|
23
|
+
return { ...progress, [repo]: [...existing, prNumber] };
|
|
24
|
+
}
|
|
25
|
+
export function isPRProcessed(progress, repo, prNumber) {
|
|
26
|
+
return (progress[repo] ?? []).includes(prNumber);
|
|
27
|
+
}
|
|
28
|
+
export function getPRProgressStats(progress, repo) {
|
|
29
|
+
return { processedPRs: (progress[repo] ?? []).length };
|
|
30
|
+
}
|
|
31
|
+
export async function loadPRProgress(dir) {
|
|
32
|
+
const filePath = join(dir, 'pr-progress.json');
|
|
33
|
+
try {
|
|
34
|
+
const content = await readFile(filePath, 'utf-8');
|
|
35
|
+
return JSON.parse(content);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function savePRProgress(dir, progress) {
|
|
42
|
+
await mkdir(dir, { recursive: true });
|
|
43
|
+
const filePath = join(dir, 'pr-progress.json');
|
|
44
|
+
await writeFile(filePath, JSON.stringify(progress, null, 2), 'utf-8');
|
|
45
|
+
}
|
|
46
|
+
// ── Fuzzy Deduplication ─────────────────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* Dice coefficient (bigram overlap) for fuzzy string similarity.
|
|
49
|
+
* Returns a value between 0 (no overlap) and 1 (identical).
|
|
50
|
+
*/
|
|
51
|
+
export function diceCoefficient(a, b) {
|
|
52
|
+
if (a === b)
|
|
53
|
+
return 1;
|
|
54
|
+
if (a.length < 2 || b.length < 2)
|
|
55
|
+
return 0;
|
|
56
|
+
const bigramsA = new Map();
|
|
57
|
+
for (let i = 0; i < a.length - 1; i++) {
|
|
58
|
+
const bigram = a.substring(i, i + 2);
|
|
59
|
+
bigramsA.set(bigram, (bigramsA.get(bigram) ?? 0) + 1);
|
|
60
|
+
}
|
|
61
|
+
const bigramsB = new Map();
|
|
62
|
+
for (let i = 0; i < b.length - 1; i++) {
|
|
63
|
+
const bigram = b.substring(i, i + 2);
|
|
64
|
+
bigramsB.set(bigram, (bigramsB.get(bigram) ?? 0) + 1);
|
|
65
|
+
}
|
|
66
|
+
let intersectionSize = 0;
|
|
67
|
+
for (const [bigram, countA] of bigramsA) {
|
|
68
|
+
const countB = bigramsB.get(bigram) ?? 0;
|
|
69
|
+
intersectionSize += Math.min(countA, countB);
|
|
70
|
+
}
|
|
71
|
+
return (2 * intersectionSize) / (a.length - 1 + (b.length - 1));
|
|
72
|
+
}
|
|
73
|
+
/** Similarity threshold above which two descriptions are considered duplicates. */
|
|
74
|
+
const DEDUP_THRESHOLD = 0.7;
|
|
75
|
+
/**
|
|
76
|
+
* Find the most similar existing rule by description, if above threshold.
|
|
77
|
+
*/
|
|
78
|
+
export function findFuzzyDuplicate(existingRules, description, category) {
|
|
79
|
+
let bestMatch = null;
|
|
80
|
+
let bestScore = 0;
|
|
81
|
+
for (const rule of existingRules) {
|
|
82
|
+
// Only compare within the same category
|
|
83
|
+
if (rule.pattern.claimCategory !== category)
|
|
84
|
+
continue;
|
|
85
|
+
if (rule.status === 'rejected' || rule.status === 'deprecated')
|
|
86
|
+
continue;
|
|
87
|
+
const score = diceCoefficient(rule.pattern.description.toLowerCase(), description.toLowerCase());
|
|
88
|
+
if (score > bestScore) {
|
|
89
|
+
bestScore = score;
|
|
90
|
+
bestMatch = rule;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return bestScore >= DEDUP_THRESHOLD ? bestMatch : null;
|
|
94
|
+
}
|
|
95
|
+
// ── Rule Construction ───────────────────────────────────────
|
|
96
|
+
function buildLearnedRule(generalizedRule, patternId, repo, prNumber, hunkFile, buggyCode) {
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
const pattern = mapToExtractedPattern(generalizedRule, patternId);
|
|
99
|
+
// Use actual buggy code from the diff hunk so validation has real test material
|
|
100
|
+
const codeSnippet = buggyCode && buggyCode.trim().length > 10
|
|
101
|
+
? buggyCode
|
|
102
|
+
: `PR #${prNumber}: ${generalizedRule.fix.description}`;
|
|
103
|
+
const sourceFinding = {
|
|
104
|
+
claimId: `pr_${repo.replace('/', '_')}_${prNumber}`,
|
|
105
|
+
claimDescription: generalizedRule.description,
|
|
106
|
+
codeSnippet,
|
|
107
|
+
filePath: hunkFile,
|
|
108
|
+
language: generalizedRule.detection.language,
|
|
109
|
+
timestamp: now,
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
id: patternId,
|
|
113
|
+
pattern,
|
|
114
|
+
status: 'promoted', // Default; overridden by validation harness result
|
|
115
|
+
createdAt: now,
|
|
116
|
+
updatedAt: now,
|
|
117
|
+
fireCount: 0,
|
|
118
|
+
truePositiveCount: 0,
|
|
119
|
+
falsePositiveCount: 0,
|
|
120
|
+
sourceFindings: [sourceFinding],
|
|
121
|
+
source: 'pr',
|
|
122
|
+
fixDescription: generalizedRule.fix.description,
|
|
123
|
+
fixPattern: generalizedRule.fix.pattern,
|
|
124
|
+
confirmationCount: 1,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ── Main Orchestrator ───────────────────────────────────────
|
|
128
|
+
function log(config, msg) {
|
|
129
|
+
if (config.onLog) {
|
|
130
|
+
config.onLog(msg);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log(msg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function harvestPRs(config) {
|
|
137
|
+
const startTime = Date.now();
|
|
138
|
+
// 1. Load progress if resuming
|
|
139
|
+
let progress = config.resume
|
|
140
|
+
? await loadPRProgress(config.progressDir)
|
|
141
|
+
: createPRProgress();
|
|
142
|
+
if (config.resume) {
|
|
143
|
+
const totalTracked = Object.values(progress).reduce((sum, prs) => sum + prs.length, 0);
|
|
144
|
+
log(config, `Resumed PR progress: ${totalTracked} PRs tracked`);
|
|
145
|
+
}
|
|
146
|
+
// 2. Filter repos
|
|
147
|
+
let repos = config.repoList;
|
|
148
|
+
if (config.repoFilter && config.repoFilter.length > 0) {
|
|
149
|
+
const filterSet = new Set(config.repoFilter);
|
|
150
|
+
repos = repos.filter((r) => filterSet.has(`${r.owner}/${r.name}`));
|
|
151
|
+
}
|
|
152
|
+
if (config.limit !== undefined && config.limit > 0) {
|
|
153
|
+
repos = repos.slice(0, config.limit);
|
|
154
|
+
}
|
|
155
|
+
log(config, `Processing ${repos.length} repos in PR mode`);
|
|
156
|
+
// Tracking for the run report
|
|
157
|
+
let totalPRsDiscovered = 0;
|
|
158
|
+
let totalHunksProcessed = 0;
|
|
159
|
+
let rulesLearned = 0;
|
|
160
|
+
let rulesRejected = 0;
|
|
161
|
+
let rulesDuplicate = 0;
|
|
162
|
+
const unmatchedCategories = {};
|
|
163
|
+
for (const repo of repos) {
|
|
164
|
+
const key = `${repo.owner}/${repo.name}`;
|
|
165
|
+
log(config, `[PR-DISCOVER] ${key}`);
|
|
166
|
+
// 3. Discover bug-fix PRs
|
|
167
|
+
let discoveredPRs;
|
|
168
|
+
try {
|
|
169
|
+
const maxPRs = config.maxPRsPerRepo ?? 100;
|
|
170
|
+
const allDiscoveredPRs = discoverBugFixPRs(repo.owner, repo.name, {
|
|
171
|
+
perPage: 30,
|
|
172
|
+
maxPages: Math.ceil(maxPRs / 30),
|
|
173
|
+
titleFallback: true,
|
|
174
|
+
fetchComments: true,
|
|
175
|
+
});
|
|
176
|
+
discoveredPRs = allDiscoveredPRs.slice(0, maxPRs);
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
log(config, `[FAIL] ${key} — discovery failed: ${String(err)}`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
log(config, `[FOUND] ${key} — ${discoveredPRs.length} bug-fix PRs`);
|
|
183
|
+
totalPRsDiscovered += discoveredPRs.length;
|
|
184
|
+
for (const pr of discoveredPRs) {
|
|
185
|
+
// Skip already-processed PRs on resume
|
|
186
|
+
if (config.resume && isPRProcessed(progress, key, pr.prNumber)) {
|
|
187
|
+
log(config, ` [SKIP] PR #${pr.prNumber} — already processed`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
log(config, ` [PR] #${pr.prNumber}: ${pr.title}`);
|
|
191
|
+
// 4. Fetch and parse diffs
|
|
192
|
+
let parsedDiff;
|
|
193
|
+
try {
|
|
194
|
+
parsedDiff = fetchPRDiffs(repo.owner, repo.name, pr);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
log(config, ` [DIFF_ERR] PR #${pr.prNumber} — ${String(err)}`);
|
|
198
|
+
progress = markPRProcessed(progress, key, pr.prNumber);
|
|
199
|
+
await savePRProgress(config.progressDir, progress);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
// Filter to meaningful hunks
|
|
203
|
+
const meaningfulHunks = filterHunks(parsedDiff.hunks);
|
|
204
|
+
if (meaningfulHunks.length === 0) {
|
|
205
|
+
log(config, ` [SKIP] PR #${pr.prNumber} — no meaningful hunks`);
|
|
206
|
+
progress = markPRProcessed(progress, key, pr.prNumber);
|
|
207
|
+
await savePRProgress(config.progressDir, progress);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
log(config, ` [HUNKS] ${meaningfulHunks.length} meaningful (of ${parsedDiff.hunks.length} total)`);
|
|
211
|
+
totalHunksProcessed += meaningfulHunks.length;
|
|
212
|
+
// Load catalog once before processing hunks (refreshed after writes)
|
|
213
|
+
let existingRules = await loadRules(config.catalogPath);
|
|
214
|
+
// 5. Generalize each hunk
|
|
215
|
+
for (const hunk of meaningfulHunks) {
|
|
216
|
+
// Find matching review comment for this hunk's file
|
|
217
|
+
const matchingComment = pr.reviewComments.find((c) => c.path === hunk.file);
|
|
218
|
+
let generalizedRule;
|
|
219
|
+
try {
|
|
220
|
+
generalizedRule = await generalizeHunk(hunk, key, pr.prNumber, pr.title, matchingComment?.body);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
log(config, ` [GEN_ERR] ${hunk.file}:${hunk.startLine} — ${String(err)}`);
|
|
224
|
+
rulesRejected++;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (!generalizedRule) {
|
|
228
|
+
log(config, ` [SKIP] ${hunk.file}:${hunk.startLine} — too context-specific`);
|
|
229
|
+
rulesRejected++;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
// 6. Check for fuzzy duplicates in catalog
|
|
233
|
+
const duplicate = findFuzzyDuplicate(existingRules, generalizedRule.description, generalizedRule.category);
|
|
234
|
+
if (duplicate) {
|
|
235
|
+
// Merge provenance into existing rule
|
|
236
|
+
log(config, ` [DEDUP] "${generalizedRule.description}" → merging into ${duplicate.id}`);
|
|
237
|
+
await updateRule(config.catalogPath, duplicate.id, (existing) => ({
|
|
238
|
+
...existing,
|
|
239
|
+
confirmationCount: (existing.confirmationCount ?? 1) + 1,
|
|
240
|
+
updatedAt: new Date().toISOString(),
|
|
241
|
+
sourceFindings: [
|
|
242
|
+
...existing.sourceFindings,
|
|
243
|
+
{
|
|
244
|
+
claimId: `pr_${key.replace('/', '_')}_${pr.prNumber}`,
|
|
245
|
+
claimDescription: generalizedRule.description,
|
|
246
|
+
codeSnippet: `PR #${pr.prNumber}: ${generalizedRule.fix.description}`,
|
|
247
|
+
filePath: hunk.file,
|
|
248
|
+
language: generalizedRule.detection.language,
|
|
249
|
+
timestamp: new Date().toISOString(),
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
}));
|
|
253
|
+
rulesDuplicate++;
|
|
254
|
+
existingRules = await loadRules(config.catalogPath);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
// 7. Build candidate rule and validate before promotion
|
|
258
|
+
const patternId = `lp_pr_${Date.now()}`;
|
|
259
|
+
// Pass the buggy code (removed lines + context) so validation has real test material
|
|
260
|
+
const buggyCode = [...hunk.context, ...hunk.removedLines].join('\n');
|
|
261
|
+
const candidateRule = buildLearnedRule(generalizedRule, patternId, key, pr.prNumber, hunk.file, buggyCode);
|
|
262
|
+
// 7b. Run through validation harness
|
|
263
|
+
const validationResult = validateRule(candidateRule);
|
|
264
|
+
const finalRule = {
|
|
265
|
+
...candidateRule,
|
|
266
|
+
status: validationResult.passed ? 'promoted' : 'rejected',
|
|
267
|
+
validationResults: validationResult,
|
|
268
|
+
};
|
|
269
|
+
await addRule(config.catalogPath, finalRule);
|
|
270
|
+
existingRules = await loadRules(config.catalogPath);
|
|
271
|
+
if (validationResult.passed) {
|
|
272
|
+
rulesLearned++;
|
|
273
|
+
log(config, ` [LEARNED] ${patternId}: ${generalizedRule.description} (precision=${validationResult.precision.toFixed(2)} recall=${validationResult.recall.toFixed(2)})`);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
rulesRejected++;
|
|
277
|
+
log(config, ` [REJECTED] ${patternId}: ${generalizedRule.description} — validation failed (precision=${validationResult.precision.toFixed(2)} recall=${validationResult.recall.toFixed(2)})`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Mark PR as processed and persist after each PR
|
|
281
|
+
progress = markPRProcessed(progress, key, pr.prNumber);
|
|
282
|
+
await savePRProgress(config.progressDir, progress);
|
|
283
|
+
}
|
|
284
|
+
log(config, `[DONE] ${key}`);
|
|
285
|
+
}
|
|
286
|
+
// 8. Generate and save run report
|
|
287
|
+
const stats = await loadStats(config.catalogPath);
|
|
288
|
+
const allRules = await loadRules(config.catalogPath);
|
|
289
|
+
const catalogSize = {
|
|
290
|
+
total: allRules.length,
|
|
291
|
+
promoted: allRules.filter((r) => r.status === 'promoted').length,
|
|
292
|
+
rejected: allRules.filter((r) => r.status === 'rejected').length,
|
|
293
|
+
};
|
|
294
|
+
const durationMinutes = (Date.now() - startTime) / 60_000;
|
|
295
|
+
const report = {
|
|
296
|
+
timestamp: new Date().toISOString(),
|
|
297
|
+
model: config.model,
|
|
298
|
+
reposScanned: repos.length,
|
|
299
|
+
filesScanned: totalHunksProcessed, // hunks are the PR-mode equivalent of files
|
|
300
|
+
claimsExtracted: totalPRsDiscovered,
|
|
301
|
+
findingsConfirmed: totalHunksProcessed,
|
|
302
|
+
rulesLearned,
|
|
303
|
+
rulesRejected,
|
|
304
|
+
rulesDuplicate,
|
|
305
|
+
unmatchedCategories,
|
|
306
|
+
durationMinutes,
|
|
307
|
+
catalogSize,
|
|
308
|
+
};
|
|
309
|
+
const reportPath = await saveRunReport(config.runsDir, report);
|
|
310
|
+
// 9. Print summary
|
|
311
|
+
log(config, '');
|
|
312
|
+
log(config, '══════════════════════════════════════');
|
|
313
|
+
log(config, ' PR HARVEST COMPLETE');
|
|
314
|
+
log(config, '══════════════════════════════════════');
|
|
315
|
+
log(config, ` Repos processed: ${repos.length}`);
|
|
316
|
+
log(config, ` PRs discovered: ${totalPRsDiscovered}`);
|
|
317
|
+
log(config, ` Hunks processed: ${totalHunksProcessed}`);
|
|
318
|
+
log(config, ` Rules learned: ${rulesLearned}`);
|
|
319
|
+
log(config, ` Rules duplicate: ${rulesDuplicate}`);
|
|
320
|
+
log(config, ` Rules rejected: ${rulesRejected}`);
|
|
321
|
+
log(config, ` Catalog total: ${catalogSize.total} (${catalogSize.promoted} promoted)`);
|
|
322
|
+
log(config, ` Duration: ${durationMinutes.toFixed(1)}m`);
|
|
323
|
+
log(config, ` Report: ${reportPath}`);
|
|
324
|
+
log(config, '══════════════════════════════════════');
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=pr-harvest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-harvest.js","sourceRoot":"","sources":["../../../src/lib/rule-harvester/pr-harvest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type FileState = 'pending' | 'scanned' | 'confirmed' | 'learned';
|
|
2
|
+
export interface RepoProgress {
|
|
3
|
+
status: 'pending' | 'in_progress' | 'complete';
|
|
4
|
+
startedAt: string;
|
|
5
|
+
files: Record<string, FileState>;
|
|
6
|
+
}
|
|
7
|
+
export type HarvestProgress = Record<string, RepoProgress>;
|
|
8
|
+
export declare function loadProgress(dir: string): Promise<HarvestProgress>;
|
|
9
|
+
export declare function saveProgress(dir: string, progress: HarvestProgress): Promise<void>;
|
|
10
|
+
export declare function getFileState(progress: HarvestProgress, repoKey: string, filePath: string): FileState;
|
|
11
|
+
export declare function getRepoStatus(files: Record<string, FileState>): 'pending' | 'in_progress' | 'complete';
|
|
12
|
+
export declare function initRepo(progress: HarvestProgress, repoKey: string): HarvestProgress;
|
|
13
|
+
export declare function setFileState(progress: HarvestProgress, repoKey: string, filePath: string, state: FileState): HarvestProgress;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export async function loadProgress(dir) {
|
|
4
|
+
const filePath = join(dir, 'progress.json');
|
|
5
|
+
try {
|
|
6
|
+
const content = await readFile(filePath, 'utf-8');
|
|
7
|
+
return JSON.parse(content);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function saveProgress(dir, progress) {
|
|
14
|
+
await mkdir(dir, { recursive: true });
|
|
15
|
+
const filePath = join(dir, 'progress.json');
|
|
16
|
+
await writeFile(filePath, JSON.stringify(progress, null, 2), 'utf-8');
|
|
17
|
+
}
|
|
18
|
+
export function getFileState(progress, repoKey, filePath) {
|
|
19
|
+
return progress[repoKey]?.files[filePath] ?? 'pending';
|
|
20
|
+
}
|
|
21
|
+
export function getRepoStatus(files) {
|
|
22
|
+
const states = Object.values(files);
|
|
23
|
+
if (states.length === 0)
|
|
24
|
+
return 'pending';
|
|
25
|
+
if (states.every((s) => s === 'learned'))
|
|
26
|
+
return 'complete';
|
|
27
|
+
if (states.every((s) => s === 'pending'))
|
|
28
|
+
return 'pending';
|
|
29
|
+
return 'in_progress';
|
|
30
|
+
}
|
|
31
|
+
export function initRepo(progress, repoKey) {
|
|
32
|
+
if (progress[repoKey])
|
|
33
|
+
return progress;
|
|
34
|
+
return {
|
|
35
|
+
...progress,
|
|
36
|
+
[repoKey]: { status: 'pending', startedAt: new Date().toISOString(), files: {} },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function setFileState(progress, repoKey, filePath, state) {
|
|
40
|
+
const existingRepo = progress[repoKey];
|
|
41
|
+
const existingFiles = existingRepo?.files ?? {};
|
|
42
|
+
const updatedFiles = { ...existingFiles, [filePath]: state };
|
|
43
|
+
const updatedRepo = {
|
|
44
|
+
status: getRepoStatus(updatedFiles),
|
|
45
|
+
startedAt: existingRepo?.startedAt ?? new Date().toISOString(),
|
|
46
|
+
files: updatedFiles,
|
|
47
|
+
};
|
|
48
|
+
return { ...progress, [repoKey]: updatedRepo };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/lib/rule-harvester/progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAoB,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,QAAyB;IACvE,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAC5C,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,QAAyB,EACzB,OAAe,EACf,QAAgB;IAEhB,OAAO,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,KAAgC;IAEhC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;QAAE,OAAO,UAAU,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,QAAyB,EACzB,OAAe;IAEf,IAAI,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvC,OAAO;QACL,GAAG,QAAQ;QACX,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;KACjF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,QAAyB,EACzB,OAAe,EACf,QAAgB,EAChB,KAAgB;IAEhB,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC;IAChD,MAAM,YAAY,GAA8B,EAAE,GAAG,aAAa,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;IAExF,MAAM,WAAW,GAAiB;QAChC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC;QACnC,SAAS,EAAE,YAAY,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC9D,KAAK,EAAE,YAAY;KACpB,CAAC;IAEF,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;AACjD,CAAC"}
|