tryassay 0.29.0 → 0.31.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.
Files changed (85) hide show
  1. package/dist/cli.js +21 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/catalog-push.d.ts +7 -0
  4. package/dist/commands/catalog-push.js +47 -0
  5. package/dist/commands/catalog-push.js.map +1 -0
  6. package/dist/commands/generate.js +1 -0
  7. package/dist/commands/generate.js.map +1 -1
  8. package/dist/commands/harvest.d.ts +9 -0
  9. package/dist/commands/harvest.js +76 -0
  10. package/dist/commands/harvest.js.map +1 -0
  11. package/dist/lib/__tests__/learned-rules.test.d.ts +1 -0
  12. package/dist/lib/__tests__/learned-rules.test.js +260 -0
  13. package/dist/lib/__tests__/learned-rules.test.js.map +1 -0
  14. package/dist/lib/__tests__/pr-harvester-types.test.d.ts +1 -0
  15. package/dist/lib/__tests__/pr-harvester-types.test.js +43 -0
  16. package/dist/lib/__tests__/pr-harvester-types.test.js.map +1 -0
  17. package/dist/lib/__tests__/pr-harvester.test.d.ts +1 -0
  18. package/dist/lib/__tests__/pr-harvester.test.js +341 -0
  19. package/dist/lib/__tests__/pr-harvester.test.js.map +1 -0
  20. package/dist/lib/__tests__/rule-harvester.test.d.ts +1 -0
  21. package/dist/lib/__tests__/rule-harvester.test.js +526 -0
  22. package/dist/lib/__tests__/rule-harvester.test.js.map +1 -0
  23. package/dist/lib/learned-rules/category-map.d.ts +28 -0
  24. package/dist/lib/learned-rules/category-map.js +110 -0
  25. package/dist/lib/learned-rules/category-map.js.map +1 -0
  26. package/dist/lib/learned-rules/index.d.ts +107 -0
  27. package/dist/lib/learned-rules/index.js +198 -0
  28. package/dist/lib/learned-rules/index.js.map +1 -0
  29. package/dist/lib/learned-rules/learned-catalog.d.ts +62 -0
  30. package/dist/lib/learned-rules/learned-catalog.js +161 -0
  31. package/dist/lib/learned-rules/learned-catalog.js.map +1 -0
  32. package/dist/lib/learned-rules/pattern-extractor.d.ts +25 -0
  33. package/dist/lib/learned-rules/pattern-extractor.js +351 -0
  34. package/dist/lib/learned-rules/pattern-extractor.js.map +1 -0
  35. package/dist/lib/learned-rules/rule-codifier.d.ts +41 -0
  36. package/dist/lib/learned-rules/rule-codifier.js +138 -0
  37. package/dist/lib/learned-rules/rule-codifier.js.map +1 -0
  38. package/dist/lib/learned-rules/starter-catalog.d.ts +16 -0
  39. package/dist/lib/learned-rules/starter-catalog.js +402 -0
  40. package/dist/lib/learned-rules/starter-catalog.js.map +1 -0
  41. package/dist/lib/learned-rules/types.d.ts +196 -0
  42. package/dist/lib/learned-rules/types.js +9 -0
  43. package/dist/lib/learned-rules/types.js.map +1 -0
  44. package/dist/lib/learned-rules/validation-harness.d.ts +26 -0
  45. package/dist/lib/learned-rules/validation-harness.js +260 -0
  46. package/dist/lib/learned-rules/validation-harness.js.map +1 -0
  47. package/dist/lib/rule-harvester/diff-parser.d.ts +9 -0
  48. package/dist/lib/rule-harvester/diff-parser.js +77 -0
  49. package/dist/lib/rule-harvester/diff-parser.js.map +1 -0
  50. package/dist/lib/rule-harvester/file-selector.d.ts +10 -0
  51. package/dist/lib/rule-harvester/file-selector.js +59 -0
  52. package/dist/lib/rule-harvester/file-selector.js.map +1 -0
  53. package/dist/lib/rule-harvester/ground-truth.d.ts +19 -0
  54. package/dist/lib/rule-harvester/ground-truth.js +156 -0
  55. package/dist/lib/rule-harvester/ground-truth.js.map +1 -0
  56. package/dist/lib/rule-harvester/harvest.d.ts +26 -0
  57. package/dist/lib/rule-harvester/harvest.js +307 -0
  58. package/dist/lib/rule-harvester/harvest.js.map +1 -0
  59. package/dist/lib/rule-harvester/pr-discovery.d.ts +49 -0
  60. package/dist/lib/rule-harvester/pr-discovery.js +168 -0
  61. package/dist/lib/rule-harvester/pr-discovery.js.map +1 -0
  62. package/dist/lib/rule-harvester/pr-harvest.d.ts +53 -0
  63. package/dist/lib/rule-harvester/pr-harvest.js +326 -0
  64. package/dist/lib/rule-harvester/pr-harvest.js.map +1 -0
  65. package/dist/lib/rule-harvester/progress.d.ts +13 -0
  66. package/dist/lib/rule-harvester/progress.js +50 -0
  67. package/dist/lib/rule-harvester/progress.js.map +1 -0
  68. package/dist/lib/rule-harvester/reporter.d.ts +35 -0
  69. package/dist/lib/rule-harvester/reporter.js +46 -0
  70. package/dist/lib/rule-harvester/reporter.js.map +1 -0
  71. package/dist/lib/rule-harvester/rule-generalizer.d.ts +25 -0
  72. package/dist/lib/rule-harvester/rule-generalizer.js +135 -0
  73. package/dist/lib/rule-harvester/rule-generalizer.js.map +1 -0
  74. package/dist/lib/rule-harvester/scanner.d.ts +20 -0
  75. package/dist/lib/rule-harvester/scanner.js +37 -0
  76. package/dist/lib/rule-harvester/scanner.js.map +1 -0
  77. package/dist/sdk/api-client.d.ts +65 -0
  78. package/dist/sdk/api-client.js +41 -0
  79. package/dist/sdk/api-client.js.map +1 -0
  80. package/dist/sdk/forward-verify.d.ts +3 -1
  81. package/dist/sdk/forward-verify.js +138 -5
  82. package/dist/sdk/forward-verify.js.map +1 -1
  83. package/dist/sdk/index.d.ts +1 -1
  84. package/dist/sdk/types.d.ts +21 -0
  85. package/package.json +1 -1
@@ -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"}
@@ -0,0 +1,35 @@
1
+ export interface ScanFileResult {
2
+ repo: string;
3
+ filePath: string;
4
+ claimsExtracted: number;
5
+ confirmed: number;
6
+ rulesLearned: number;
7
+ rulesRejected: number;
8
+ rulesDuplicate: number;
9
+ unmatchedCategories: string[];
10
+ durationMs: number;
11
+ }
12
+ export interface RunReport {
13
+ timestamp: string;
14
+ model: string;
15
+ reposScanned: number;
16
+ filesScanned: number;
17
+ claimsExtracted: number;
18
+ findingsConfirmed: number;
19
+ rulesLearned: number;
20
+ rulesRejected: number;
21
+ rulesDuplicate: number;
22
+ unmatchedCategories: Record<string, number>;
23
+ durationMinutes: number;
24
+ catalogSize: {
25
+ total: number;
26
+ promoted: number;
27
+ rejected: number;
28
+ };
29
+ }
30
+ export declare function createRunReport(fileResults: ScanFileResult[], model: string, catalogSize: {
31
+ total: number;
32
+ promoted: number;
33
+ rejected: number;
34
+ }): RunReport;
35
+ export declare function saveRunReport(runsDir: string, report: RunReport): Promise<string>;
@@ -0,0 +1,46 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export function createRunReport(fileResults, model, catalogSize) {
4
+ const uniqueRepos = new Set(fileResults.map((r) => r.repo));
5
+ let claimsExtracted = 0;
6
+ let findingsConfirmed = 0;
7
+ let rulesLearned = 0;
8
+ let rulesRejected = 0;
9
+ let rulesDuplicate = 0;
10
+ let totalDurationMs = 0;
11
+ const unmatchedCategories = {};
12
+ for (const result of fileResults) {
13
+ claimsExtracted += result.claimsExtracted;
14
+ findingsConfirmed += result.confirmed;
15
+ rulesLearned += result.rulesLearned;
16
+ rulesRejected += result.rulesRejected;
17
+ rulesDuplicate += result.rulesDuplicate;
18
+ totalDurationMs += result.durationMs;
19
+ for (const category of result.unmatchedCategories) {
20
+ unmatchedCategories[category] = (unmatchedCategories[category] ?? 0) + 1;
21
+ }
22
+ }
23
+ return {
24
+ timestamp: new Date().toISOString(),
25
+ model,
26
+ reposScanned: uniqueRepos.size,
27
+ filesScanned: fileResults.length,
28
+ claimsExtracted,
29
+ findingsConfirmed,
30
+ rulesLearned,
31
+ rulesRejected,
32
+ rulesDuplicate,
33
+ unmatchedCategories,
34
+ durationMinutes: totalDurationMs / 60_000,
35
+ catalogSize,
36
+ };
37
+ }
38
+ export async function saveRunReport(runsDir, report) {
39
+ await mkdir(runsDir, { recursive: true });
40
+ // Replace : and . with - to make a safe filename
41
+ const safeName = report.timestamp.replace(/[:.]/g, '-');
42
+ const filePath = join(runsDir, `${safeName}.json`);
43
+ await writeFile(filePath, JSON.stringify(report, null, 2), 'utf-8');
44
+ return filePath;
45
+ }
46
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../../src/lib/rule-harvester/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA6BjC,MAAM,UAAU,eAAe,CAC7B,WAA6B,EAC7B,KAAa,EACb,WAAkE;IAElE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE5D,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,MAAM,mBAAmB,GAA2B,EAAE,CAAC;IAEvD,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,eAAe,IAAI,MAAM,CAAC,eAAe,CAAC;QAC1C,iBAAiB,IAAI,MAAM,CAAC,SAAS,CAAC;QACtC,YAAY,IAAI,MAAM,CAAC,YAAY,CAAC;QACpC,aAAa,IAAI,MAAM,CAAC,aAAa,CAAC;QACtC,cAAc,IAAI,MAAM,CAAC,cAAc,CAAC;QACxC,eAAe,IAAI,MAAM,CAAC,UAAU,CAAC;QAErC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAClD,mBAAmB,CAAC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK;QACL,YAAY,EAAE,WAAW,CAAC,IAAI;QAC9B,YAAY,EAAE,WAAW,CAAC,MAAM;QAChC,eAAe;QACf,iBAAiB;QACjB,YAAY;QACZ,aAAa;QACb,cAAc;QACd,mBAAmB;QACnB,eAAe,EAAE,eAAe,GAAG,MAAM;QACzC,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,MAAiB;IACpE,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,iDAAiD;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;IAEnD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAEpE,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Rule Generalizer — Uses LLM to generalize PR diff hunks into reusable
3
+ * code quality rules for the Assay catalog.
4
+ *
5
+ * Given a before/after diff hunk (and optional reviewer comment), the LLM
6
+ * produces a GeneralizedRule with detection regex, fix description, severity,
7
+ * and provenance. The rule is then mapped to an ExtractedPattern for catalog
8
+ * ingestion.
9
+ */
10
+ import type { DiffHunk, GeneralizedRule } from '../learned-rules/types.js';
11
+ import type { ExtractedPattern } from '../learned-rules/types.js';
12
+ /**
13
+ * Build the user prompt for the LLM generalization call.
14
+ */
15
+ export declare function buildGeneralizationPrompt(hunk: DiffHunk, repo: string, prNumber: number, prTitle: string, reviewComment?: string): string;
16
+ /**
17
+ * Call the LLM to generalize a diff hunk into a reusable rule.
18
+ * Returns null if the hunk is too context-specific, parse fails,
19
+ * or all retries are exhausted.
20
+ */
21
+ export declare function generalizeHunk(hunk: DiffHunk, repo: string, prNumber: number, prTitle: string, reviewComment?: string): Promise<GeneralizedRule | null>;
22
+ /**
23
+ * Map a GeneralizedRule to an ExtractedPattern for catalog ingestion.
24
+ */
25
+ export declare function mapToExtractedPattern(rule: GeneralizedRule, patternId: string): ExtractedPattern;