@mmnto/cli 1.5.3 → 1.5.5

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 (134) hide show
  1. package/dist/commands/add-lesson.d.ts.map +1 -1
  2. package/dist/commands/add-lesson.js +12 -0
  3. package/dist/commands/add-lesson.js.map +1 -1
  4. package/dist/commands/add-lesson.test.d.ts +2 -0
  5. package/dist/commands/add-lesson.test.d.ts.map +1 -0
  6. package/dist/commands/add-lesson.test.js +63 -0
  7. package/dist/commands/add-lesson.test.js.map +1 -0
  8. package/dist/commands/add-secret.d.ts +5 -0
  9. package/dist/commands/add-secret.d.ts.map +1 -0
  10. package/dist/commands/add-secret.js +85 -0
  11. package/dist/commands/add-secret.js.map +1 -0
  12. package/dist/commands/add-secret.test.d.ts +2 -0
  13. package/dist/commands/add-secret.test.d.ts.map +1 -0
  14. package/dist/commands/add-secret.test.js +97 -0
  15. package/dist/commands/add-secret.test.js.map +1 -0
  16. package/dist/commands/doctor.d.ts +10 -1
  17. package/dist/commands/doctor.d.ts.map +1 -1
  18. package/dist/commands/doctor.js +177 -2
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/doctor.test.js +284 -2
  21. package/dist/commands/doctor.test.js.map +1 -1
  22. package/dist/commands/extract.d.ts.map +1 -1
  23. package/dist/commands/extract.js +4 -1
  24. package/dist/commands/extract.js.map +1 -1
  25. package/dist/commands/extract.test.js +53 -0
  26. package/dist/commands/extract.test.js.map +1 -1
  27. package/dist/commands/init.d.ts.map +1 -1
  28. package/dist/commands/init.js +16 -0
  29. package/dist/commands/init.js.map +1 -1
  30. package/dist/commands/ledger-analyzer.d.ts +24 -0
  31. package/dist/commands/ledger-analyzer.d.ts.map +1 -0
  32. package/dist/commands/ledger-analyzer.js +64 -0
  33. package/dist/commands/ledger-analyzer.js.map +1 -0
  34. package/dist/commands/ledger-analyzer.test.d.ts +2 -0
  35. package/dist/commands/ledger-analyzer.test.d.ts.map +1 -0
  36. package/dist/commands/ledger-analyzer.test.js +163 -0
  37. package/dist/commands/ledger-analyzer.test.js.map +1 -0
  38. package/dist/commands/list-secrets.d.ts +15 -0
  39. package/dist/commands/list-secrets.d.ts.map +1 -0
  40. package/dist/commands/list-secrets.js +104 -0
  41. package/dist/commands/list-secrets.js.map +1 -0
  42. package/dist/commands/list-secrets.test.d.ts +2 -0
  43. package/dist/commands/list-secrets.test.d.ts.map +1 -0
  44. package/dist/commands/list-secrets.test.js +85 -0
  45. package/dist/commands/list-secrets.test.js.map +1 -0
  46. package/dist/commands/remove-secret.d.ts +2 -0
  47. package/dist/commands/remove-secret.d.ts.map +1 -0
  48. package/dist/commands/remove-secret.js +53 -0
  49. package/dist/commands/remove-secret.js.map +1 -0
  50. package/dist/commands/remove-secret.test.d.ts +2 -0
  51. package/dist/commands/remove-secret.test.d.ts.map +1 -0
  52. package/dist/commands/remove-secret.test.js +85 -0
  53. package/dist/commands/remove-secret.test.js.map +1 -0
  54. package/dist/commands/review-learn-templates.d.ts +7 -0
  55. package/dist/commands/review-learn-templates.d.ts.map +1 -0
  56. package/dist/commands/review-learn-templates.js +36 -0
  57. package/dist/commands/review-learn-templates.js.map +1 -0
  58. package/dist/commands/review-learn-templates.test.d.ts +2 -0
  59. package/dist/commands/review-learn-templates.test.d.ts.map +1 -0
  60. package/dist/commands/review-learn-templates.test.js +29 -0
  61. package/dist/commands/review-learn-templates.test.js.map +1 -0
  62. package/dist/commands/review-learn.d.ts +13 -0
  63. package/dist/commands/review-learn.d.ts.map +1 -0
  64. package/dist/commands/review-learn.js +260 -0
  65. package/dist/commands/review-learn.js.map +1 -0
  66. package/dist/commands/review-learn.test.d.ts +2 -0
  67. package/dist/commands/review-learn.test.d.ts.map +1 -0
  68. package/dist/commands/review-learn.test.js +218 -0
  69. package/dist/commands/review-learn.test.js.map +1 -0
  70. package/dist/commands/rule-mutator.d.ts +17 -0
  71. package/dist/commands/rule-mutator.d.ts.map +1 -0
  72. package/dist/commands/rule-mutator.js +33 -0
  73. package/dist/commands/rule-mutator.js.map +1 -0
  74. package/dist/commands/rule-mutator.test.d.ts +2 -0
  75. package/dist/commands/rule-mutator.test.d.ts.map +1 -0
  76. package/dist/commands/rule-mutator.test.js +104 -0
  77. package/dist/commands/rule-mutator.test.js.map +1 -0
  78. package/dist/commands/run-compiled-rules.d.ts.map +1 -1
  79. package/dist/commands/run-compiled-rules.js +49 -5
  80. package/dist/commands/run-compiled-rules.js.map +1 -1
  81. package/dist/commands/run-compiled-rules.test.js +107 -1
  82. package/dist/commands/run-compiled-rules.test.js.map +1 -1
  83. package/dist/commands/shield-hints.d.ts +16 -2
  84. package/dist/commands/shield-hints.d.ts.map +1 -1
  85. package/dist/commands/shield-hints.js +35 -20
  86. package/dist/commands/shield-hints.js.map +1 -1
  87. package/dist/commands/shield-hints.test.js +70 -1
  88. package/dist/commands/shield-hints.test.js.map +1 -1
  89. package/dist/commands/shield.d.ts.map +1 -1
  90. package/dist/commands/shield.js +21 -2
  91. package/dist/commands/shield.js.map +1 -1
  92. package/dist/commands/triage-pr.d.ts +21 -0
  93. package/dist/commands/triage-pr.d.ts.map +1 -0
  94. package/dist/commands/triage-pr.js +231 -0
  95. package/dist/commands/triage-pr.js.map +1 -0
  96. package/dist/commands/triage-pr.test.d.ts +2 -0
  97. package/dist/commands/triage-pr.test.d.ts.map +1 -0
  98. package/dist/commands/triage-pr.test.js +163 -0
  99. package/dist/commands/triage-pr.test.js.map +1 -0
  100. package/dist/index.js +74 -4
  101. package/dist/index.js.map +1 -1
  102. package/dist/parsers/bot-review-parser.d.ts +48 -0
  103. package/dist/parsers/bot-review-parser.d.ts.map +1 -0
  104. package/dist/parsers/bot-review-parser.js +139 -0
  105. package/dist/parsers/bot-review-parser.js.map +1 -0
  106. package/dist/parsers/bot-review-parser.test.d.ts +2 -0
  107. package/dist/parsers/bot-review-parser.test.d.ts.map +1 -0
  108. package/dist/parsers/bot-review-parser.test.js +240 -0
  109. package/dist/parsers/bot-review-parser.test.js.map +1 -0
  110. package/dist/parsers/triage-dedup.d.ts +8 -0
  111. package/dist/parsers/triage-dedup.d.ts.map +1 -0
  112. package/dist/parsers/triage-dedup.js +134 -0
  113. package/dist/parsers/triage-dedup.js.map +1 -0
  114. package/dist/parsers/triage-dedup.test.d.ts +2 -0
  115. package/dist/parsers/triage-dedup.test.d.ts.map +1 -0
  116. package/dist/parsers/triage-dedup.test.js +209 -0
  117. package/dist/parsers/triage-dedup.test.js.map +1 -0
  118. package/dist/parsers/triage-severity-mapper.d.ts +9 -0
  119. package/dist/parsers/triage-severity-mapper.d.ts.map +1 -0
  120. package/dist/parsers/triage-severity-mapper.js +86 -0
  121. package/dist/parsers/triage-severity-mapper.js.map +1 -0
  122. package/dist/parsers/triage-severity-mapper.test.d.ts +2 -0
  123. package/dist/parsers/triage-severity-mapper.test.d.ts.map +1 -0
  124. package/dist/parsers/triage-severity-mapper.test.js +62 -0
  125. package/dist/parsers/triage-severity-mapper.test.js.map +1 -0
  126. package/dist/parsers/triage-types.d.ts +12 -0
  127. package/dist/parsers/triage-types.d.ts.map +1 -0
  128. package/dist/parsers/triage-types.js +2 -0
  129. package/dist/parsers/triage-types.js.map +1 -0
  130. package/dist/utils.d.ts +3 -1
  131. package/dist/utils.d.ts.map +1 -1
  132. package/dist/utils.js +1 -1
  133. package/dist/utils.js.map +1 -1
  134. package/package.json +2 -2
@@ -0,0 +1,240 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { detectBot, extractResolvedBotFindings, extractSuggestion, isBotComment, isThreadResolved, parseCRSeverity, parseGCASeverity, stripHtmlWrappers, } from './bot-review-parser.js';
3
+ // ─── detectBot ──────────────────────────────────────────
4
+ describe('detectBot', () => {
5
+ it('identifies coderabbitai[bot]', () => {
6
+ expect(detectBot('coderabbitai[bot]')).toBe('coderabbit');
7
+ });
8
+ it('identifies gemini-code-assist[bot]', () => {
9
+ expect(detectBot('gemini-code-assist[bot]')).toBe('gca');
10
+ });
11
+ it('returns unknown for human authors', () => {
12
+ expect(detectBot('octocat')).toBe('unknown');
13
+ expect(detectBot('jmatt')).toBe('unknown');
14
+ });
15
+ });
16
+ // ─── isBotComment ───────────────────────────────────────
17
+ describe('isBotComment', () => {
18
+ it('returns true for coderabbit bot', () => {
19
+ expect(isBotComment('coderabbitai[bot]')).toBe(true);
20
+ });
21
+ it('returns true for GCA bot', () => {
22
+ expect(isBotComment('gemini-code-assist[bot]')).toBe(true);
23
+ });
24
+ it('returns false for human authors', () => {
25
+ expect(isBotComment('octocat')).toBe(false);
26
+ });
27
+ });
28
+ // ─── parseCRSeverity ────────────────────────────────────
29
+ describe('parseCRSeverity', () => {
30
+ it('extracts critical from emoji', () => {
31
+ expect(parseCRSeverity('\u{1F534} **Critical:** Buffer overflow risk')).toBe('critical');
32
+ });
33
+ it('extracts critical from text', () => {
34
+ expect(parseCRSeverity('This is a critical issue')).toBe('critical');
35
+ });
36
+ it('extracts major from emoji', () => {
37
+ expect(parseCRSeverity('\u{1F7E0} **Major:** Missing null check')).toBe('major');
38
+ });
39
+ it('extracts minor from emoji', () => {
40
+ expect(parseCRSeverity('\u{1F7E1} **Minor:** Consider renaming')).toBe('minor');
41
+ });
42
+ it('returns info for plain text', () => {
43
+ expect(parseCRSeverity('Just a comment about style')).toBe('info');
44
+ });
45
+ });
46
+ // ─── parseGCASeverity ───────────────────────────────────
47
+ describe('parseGCASeverity', () => {
48
+ it('extracts high from SVG reference', () => {
49
+ expect(parseGCASeverity('![](https://example.com/high-priority.svg) Fix this')).toBe('high');
50
+ });
51
+ it('extracts high from security SVG reference', () => {
52
+ expect(parseGCASeverity('![](https://example.com/security-high-priority.svg)')).toBe('high');
53
+ });
54
+ it('extracts medium from SVG reference', () => {
55
+ expect(parseGCASeverity('![](https://example.com/medium-priority.svg) Rework this')).toBe('medium');
56
+ });
57
+ it('extracts low from SVG reference', () => {
58
+ expect(parseGCASeverity('![](https://example.com/low-priority.svg) Nice to have')).toBe('low');
59
+ });
60
+ it('returns info when no SVG marker present', () => {
61
+ expect(parseGCASeverity('Plain comment without severity')).toBe('info');
62
+ });
63
+ });
64
+ // ─── stripHtmlWrappers ──────────────────────────────────
65
+ describe('stripHtmlWrappers', () => {
66
+ it('removes details/summary/blockquote tags', () => {
67
+ const html = '<details><summary>Click to expand</summary><blockquote>Content</blockquote></details>';
68
+ expect(stripHtmlWrappers(html)).toBe('Content');
69
+ });
70
+ it('removes HTML comments', () => {
71
+ const html = '<!-- fingerprint:abc123 -->Actual content<!-- end -->';
72
+ expect(stripHtmlWrappers(html)).toBe('Actual content');
73
+ });
74
+ it('removes code tags', () => {
75
+ const html = 'Use <code>const</code> instead';
76
+ expect(stripHtmlWrappers(html)).toBe('Use const instead');
77
+ });
78
+ it('preserves inner text content', () => {
79
+ expect(stripHtmlWrappers('No HTML here')).toBe('No HTML here');
80
+ });
81
+ });
82
+ // ─── extractSuggestion ─────────────────────────────────
83
+ describe('extractSuggestion', () => {
84
+ it('extracts code from suggestion blocks', () => {
85
+ const body = 'Consider this:\n```suggestion\nconst x = 42;\n```\nEnd.';
86
+ expect(extractSuggestion(body)).toBe('const x = 42;');
87
+ });
88
+ it('returns undefined when no suggestion', () => {
89
+ expect(extractSuggestion('Just a plain comment')).toBeUndefined();
90
+ });
91
+ it('returns undefined for non-suggestion code blocks', () => {
92
+ const body = '```typescript\nconst x = 42;\n```';
93
+ expect(extractSuggestion(body)).toBeUndefined();
94
+ });
95
+ });
96
+ // ─── isThreadResolved ───────────────────────────────────
97
+ describe('isThreadResolved', () => {
98
+ const botAuthor = 'coderabbitai[bot]';
99
+ const humanAuthor = 'dev-user';
100
+ function makeThread(botBody, humanReplies) {
101
+ return {
102
+ path: 'src/foo.ts',
103
+ diffHunk: '@@ -1,3 +1,5 @@',
104
+ comments: [
105
+ { author: botAuthor, body: botBody },
106
+ ...humanReplies.map((body) => ({ author: humanAuthor, body })),
107
+ ],
108
+ };
109
+ }
110
+ it('returns true when human replied "Fixed"', () => {
111
+ expect(isThreadResolved(makeThread('Issue here', ['Fixed in latest commit']))).toBe(true);
112
+ });
113
+ it('returns true when human replied "done"', () => {
114
+ expect(isThreadResolved(makeThread('Issue here', ['Done']))).toBe(true);
115
+ });
116
+ it('returns true when human replied "addressed"', () => {
117
+ expect(isThreadResolved(makeThread('Issue here', ['Addressed this']))).toBe(true);
118
+ });
119
+ it('returns true when human replied "applied"', () => {
120
+ expect(isThreadResolved(makeThread('Issue here', ['Applied the suggestion']))).toBe(true);
121
+ });
122
+ it('returns false when human replied "intentional"', () => {
123
+ expect(isThreadResolved(makeThread('Issue here', ['This is intentional']))).toBe(false);
124
+ });
125
+ it('returns false when human replied "by design"', () => {
126
+ expect(isThreadResolved(makeThread('Issue here', ['This is by design']))).toBe(false);
127
+ });
128
+ it('returns false when human replied "won\'t fix"', () => {
129
+ expect(isThreadResolved(makeThread('Issue here', ["Won't fix this"]))).toBe(false);
130
+ });
131
+ it('returns false with no human replies', () => {
132
+ const thread = {
133
+ path: 'src/foo.ts',
134
+ diffHunk: '@@ -1,3 +1,5 @@',
135
+ comments: [{ author: botAuthor, body: 'Issue here' }],
136
+ };
137
+ expect(isThreadResolved(thread)).toBe(false);
138
+ });
139
+ it('returns false when first comment is not from a bot', () => {
140
+ const thread = {
141
+ path: 'src/foo.ts',
142
+ diffHunk: '@@ -1,3 +1,5 @@',
143
+ comments: [
144
+ { author: humanAuthor, body: 'I have a question' },
145
+ { author: botAuthor, body: 'Here is the answer' },
146
+ ],
147
+ };
148
+ expect(isThreadResolved(thread)).toBe(false);
149
+ });
150
+ it('returns true when reply contains commit SHA', () => {
151
+ expect(isThreadResolved(makeThread('Issue here', ['Fixed in abc1234']))).toBe(true);
152
+ });
153
+ it('returns true when reply contains ticket reference', () => {
154
+ expect(isThreadResolved(makeThread('Issue here', ['Tracked in #456']))).toBe(true);
155
+ });
156
+ it('returns false when human reply has no signal', () => {
157
+ expect(isThreadResolved(makeThread('Issue here', ['Thanks for the review']))).toBe(false);
158
+ });
159
+ it('returns false when empty thread', () => {
160
+ const thread = {
161
+ path: 'src/foo.ts',
162
+ diffHunk: '@@ -1,3 +1,5 @@',
163
+ comments: [],
164
+ };
165
+ expect(isThreadResolved(thread)).toBe(false);
166
+ });
167
+ });
168
+ // ─── extractResolvedBotFindings ─────────────────────────
169
+ describe('extractResolvedBotFindings', () => {
170
+ it('filters to only resolved threads', () => {
171
+ const threads = [
172
+ {
173
+ path: 'src/a.ts',
174
+ diffHunk: '@@ hunk',
175
+ comments: [
176
+ { author: 'coderabbitai[bot]', body: '\u{1F7E1} Minor issue' },
177
+ { author: 'dev', body: 'Fixed' },
178
+ ],
179
+ },
180
+ {
181
+ path: 'src/b.ts',
182
+ diffHunk: '@@ hunk',
183
+ comments: [
184
+ { author: 'coderabbitai[bot]', body: 'Some issue' },
185
+ // No human reply — not resolved
186
+ ],
187
+ },
188
+ {
189
+ path: 'src/c.ts',
190
+ diffHunk: '@@ hunk',
191
+ comments: [
192
+ { author: 'coderabbitai[bot]', body: 'Another issue' },
193
+ { author: 'dev', body: 'Intentional' },
194
+ ],
195
+ },
196
+ ];
197
+ const findings = extractResolvedBotFindings(threads);
198
+ expect(findings).toHaveLength(1);
199
+ expect(findings[0].file).toBe('src/a.ts');
200
+ expect(findings[0].severity).toBe('minor');
201
+ expect(findings[0].resolutionSignal).toBe('reply');
202
+ });
203
+ it('normalizes CR and GCA findings', () => {
204
+ const threads = [
205
+ {
206
+ path: 'src/x.ts',
207
+ diffHunk: '@@ cr-hunk',
208
+ comments: [
209
+ {
210
+ author: 'coderabbitai[bot]',
211
+ body: '\u{1F534} Critical: SQL injection risk\n```suggestion\nuse parameterized query\n```',
212
+ },
213
+ { author: 'dev', body: 'Applied' },
214
+ ],
215
+ },
216
+ {
217
+ path: 'src/y.ts',
218
+ diffHunk: '@@ gca-hunk',
219
+ comments: [
220
+ {
221
+ author: 'gemini-code-assist[bot]',
222
+ body: '![](https://img/medium-priority.svg) Consider null check',
223
+ },
224
+ { author: 'dev', body: 'Done' },
225
+ ],
226
+ },
227
+ ];
228
+ const findings = extractResolvedBotFindings(threads);
229
+ expect(findings).toHaveLength(2);
230
+ // CodeRabbit finding
231
+ expect(findings[0].tool).toBe('coderabbit');
232
+ expect(findings[0].severity).toBe('critical');
233
+ expect(findings[0].suggestion).toBe('use parameterized query');
234
+ // GCA finding
235
+ expect(findings[1].tool).toBe('gca');
236
+ expect(findings[1].severity).toBe('medium');
237
+ expect(findings[1].suggestion).toBeUndefined();
238
+ });
239
+ });
240
+ //# sourceMappingURL=bot-review-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-review-parser.test.js","sourceRoot":"","sources":["../../src/parsers/bot-review-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { NormalizedBotFinding } from './bot-review-parser.js';
2
+ import type { CategorizedFinding } from './triage-types.js';
3
+ /** Extract significant words from text (strip stopwords, lowercase) */
4
+ export declare function extractKeywords(text: string): Set<string>;
5
+ /** Jaccard similarity between two keyword sets */
6
+ export declare function jaccardSimilarity(a: Set<string>, b: Set<string>): number;
7
+ export declare function deduplicateFindings(findings: NormalizedBotFinding[]): CategorizedFinding[];
8
+ //# sourceMappingURL=triage-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-dedup.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA4D5D,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAQzD;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAKxE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,kBAAkB,EAAE,CA6D1F"}
@@ -0,0 +1,134 @@
1
+ import { mapToTriageCategory } from './triage-severity-mapper.js';
2
+ const PROXIMITY_THRESHOLD = 3; // lines
3
+ const KEYWORD_OVERLAP_THRESHOLD = 0.3; // 30% Jaccard similarity
4
+ const STOPWORDS = new Set([
5
+ 'the',
6
+ 'a',
7
+ 'an',
8
+ 'is',
9
+ 'are',
10
+ 'was',
11
+ 'were',
12
+ 'be',
13
+ 'been',
14
+ 'being',
15
+ 'have',
16
+ 'has',
17
+ 'had',
18
+ 'do',
19
+ 'does',
20
+ 'did',
21
+ 'will',
22
+ 'would',
23
+ 'could',
24
+ 'should',
25
+ 'may',
26
+ 'might',
27
+ 'shall',
28
+ 'can',
29
+ 'to',
30
+ 'of',
31
+ 'in',
32
+ 'for',
33
+ 'on',
34
+ 'with',
35
+ 'at',
36
+ 'by',
37
+ 'from',
38
+ 'as',
39
+ 'into',
40
+ 'through',
41
+ 'during',
42
+ 'before',
43
+ 'after',
44
+ 'above',
45
+ 'below',
46
+ 'this',
47
+ 'that',
48
+ 'these',
49
+ 'those',
50
+ 'it',
51
+ 'its',
52
+ 'and',
53
+ 'but',
54
+ 'or',
55
+ 'not',
56
+ 'no',
57
+ ]);
58
+ /** Extract significant words from text (strip stopwords, lowercase) */
59
+ export function extractKeywords(text) {
60
+ return new Set(text
61
+ .toLowerCase()
62
+ .replace(/[^a-z0-9\s]/g, ' ')
63
+ .split(/\s+/)
64
+ .filter((w) => w.length > 2 && !STOPWORDS.has(w)));
65
+ }
66
+ /** Jaccard similarity between two keyword sets */
67
+ export function jaccardSimilarity(a, b) {
68
+ if (a.size === 0 && b.size === 0)
69
+ return 0;
70
+ const intersection = new Set([...a].filter((x) => b.has(x)));
71
+ const union = new Set([...a, ...b]);
72
+ return intersection.size / union.size;
73
+ }
74
+ export function deduplicateFindings(findings) {
75
+ // First, categorize all findings
76
+ const categorized = findings.map((f, i) => ({
77
+ ...f,
78
+ triageCategory: mapToTriageCategory(f),
79
+ dedupKey: `${f.file}:${f.line ?? 'file'}:${i}`,
80
+ }));
81
+ const merged = [];
82
+ const consumed = new Set();
83
+ for (let i = 0; i < categorized.length; i++) {
84
+ if (consumed.has(i))
85
+ continue;
86
+ const primary = categorized[i];
87
+ const primaryKw = extractKeywords(primary.body);
88
+ const group = [];
89
+ for (let j = i + 1; j < categorized.length; j++) {
90
+ if (consumed.has(j))
91
+ continue;
92
+ const candidate = categorized[j];
93
+ // Must be same category
94
+ if (candidate.triageCategory !== primary.triageCategory)
95
+ continue;
96
+ // Must be same file
97
+ if (candidate.file !== primary.file)
98
+ continue;
99
+ // Check line proximity
100
+ if (primary.line != null && candidate.line != null) {
101
+ if (Math.abs(primary.line - candidate.line) > PROXIMITY_THRESHOLD)
102
+ continue;
103
+ }
104
+ else if (primary.line == null && candidate.line == null) {
105
+ // Both file-level — require high similarity to merge
106
+ const sim = jaccardSimilarity(primaryKw, extractKeywords(candidate.body));
107
+ if (sim < 0.8)
108
+ continue;
109
+ }
110
+ else {
111
+ // One has a line, one doesn't — require high similarity
112
+ const sim = jaccardSimilarity(primaryKw, extractKeywords(candidate.body));
113
+ if (sim < 0.8)
114
+ continue;
115
+ }
116
+ // Check keyword overlap
117
+ const candidateKw = extractKeywords(candidate.body);
118
+ const similarity = jaccardSimilarity(primaryKw, candidateKw);
119
+ if (similarity < KEYWORD_OVERLAP_THRESHOLD)
120
+ continue;
121
+ // Merge
122
+ group.push(candidate);
123
+ consumed.add(j);
124
+ }
125
+ if (group.length > 0) {
126
+ primary.mergedWith = group;
127
+ // Update dedupKey to reflect the merge
128
+ primary.dedupKey = `merged:${primary.file}:${primary.line ?? 'file'}:${primary.triageCategory}`;
129
+ }
130
+ merged.push(primary);
131
+ }
132
+ return merged;
133
+ }
134
+ //# sourceMappingURL=triage-dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-dedup.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=triage-dedup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-dedup.test.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-dedup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,209 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { deduplicateFindings, extractKeywords, jaccardSimilarity } from './triage-dedup.js';
3
+ // ─── Helpers ─────────────────────────────────────────
4
+ function makeFinding(overrides = {}) {
5
+ return {
6
+ tool: 'coderabbit',
7
+ severity: 'info',
8
+ file: 'src/foo.ts',
9
+ body: 'Some finding body',
10
+ ...overrides,
11
+ };
12
+ }
13
+ // ─── extractKeywords ─────────────────────────────────
14
+ describe('extractKeywords', () => {
15
+ it('extracts significant words and strips stopwords', () => {
16
+ const kw = extractKeywords('The quick brown fox jumps over the lazy dog');
17
+ expect(kw.has('the')).toBe(false);
18
+ expect(kw.has('quick')).toBe(true);
19
+ expect(kw.has('brown')).toBe(true);
20
+ expect(kw.has('over')).toBe(true); // 4 chars, not a stopword, included
21
+ });
22
+ it('filters words shorter than 3 characters', () => {
23
+ const kw = extractKeywords('I am a big fan of it');
24
+ expect(kw.has('am')).toBe(false);
25
+ expect(kw.has('big')).toBe(true);
26
+ expect(kw.has('fan')).toBe(true);
27
+ });
28
+ });
29
+ // ─── jaccardSimilarity ──────────────────────────────
30
+ describe('jaccardSimilarity', () => {
31
+ it('returns 0 for two empty sets', () => {
32
+ expect(jaccardSimilarity(new Set(), new Set())).toBe(0);
33
+ });
34
+ it('returns 1 for identical sets', () => {
35
+ const s = new Set(['foo', 'bar']);
36
+ expect(jaccardSimilarity(s, s)).toBe(1);
37
+ });
38
+ it('returns 0 for disjoint sets', () => {
39
+ const a = new Set(['foo', 'bar']);
40
+ const b = new Set(['baz', 'qux']);
41
+ expect(jaccardSimilarity(a, b)).toBe(0);
42
+ });
43
+ it('returns correct value for partial overlap', () => {
44
+ const a = new Set(['foo', 'bar', 'baz']);
45
+ const b = new Set(['bar', 'baz', 'qux']);
46
+ // intersection = {bar, baz} = 2, union = {foo, bar, baz, qux} = 4
47
+ expect(jaccardSimilarity(a, b)).toBeCloseTo(0.5);
48
+ });
49
+ });
50
+ // ─── deduplicateFindings ─────────────────────────────
51
+ describe('deduplicateFindings', () => {
52
+ it('merges findings from different bots on same file+line with same category', () => {
53
+ const findings = [
54
+ makeFinding({
55
+ tool: 'coderabbit',
56
+ file: 'src/auth.ts',
57
+ line: 10,
58
+ body: 'SQL injection risk in query builder',
59
+ }),
60
+ makeFinding({
61
+ tool: 'gca',
62
+ file: 'src/auth.ts',
63
+ line: 10,
64
+ body: 'Potential injection vulnerability in SQL query',
65
+ }),
66
+ ];
67
+ const result = deduplicateFindings(findings);
68
+ expect(result).toHaveLength(1);
69
+ expect(result[0].mergedWith).toHaveLength(1);
70
+ expect(result[0].mergedWith[0].tool).toBe('gca');
71
+ });
72
+ it('refuses to merge findings on the same line if triageCategory differs', () => {
73
+ const findings = [
74
+ makeFinding({
75
+ file: 'src/foo.ts',
76
+ line: 10,
77
+ body: 'SQL injection risk via exec call',
78
+ }),
79
+ makeFinding({
80
+ file: 'src/foo.ts',
81
+ line: 10,
82
+ body: 'Trailing whitespace on this line is a typo',
83
+ }),
84
+ ];
85
+ const result = deduplicateFindings(findings);
86
+ // security vs nit — should NOT merge
87
+ expect(result).toHaveLength(2);
88
+ expect(result[0].mergedWith).toBeUndefined();
89
+ expect(result[1].mergedWith).toBeUndefined();
90
+ });
91
+ it('merges findings within +/-3 line proximity', () => {
92
+ const findings = [
93
+ makeFinding({
94
+ file: 'src/auth.ts',
95
+ line: 10,
96
+ body: 'Credential leak risk in secret handling code',
97
+ }),
98
+ makeFinding({
99
+ file: 'src/auth.ts',
100
+ line: 13,
101
+ body: 'Secret credential leak risk detected in code',
102
+ }),
103
+ ];
104
+ const result = deduplicateFindings(findings);
105
+ expect(result).toHaveLength(1);
106
+ expect(result[0].mergedWith).toHaveLength(1);
107
+ });
108
+ it('does not merge findings more than 3 lines apart', () => {
109
+ const findings = [
110
+ makeFinding({
111
+ file: 'src/auth.ts',
112
+ line: 10,
113
+ body: 'Credential leak risk in this function',
114
+ }),
115
+ makeFinding({
116
+ file: 'src/auth.ts',
117
+ line: 14,
118
+ body: 'Secret credential exposed in this block',
119
+ }),
120
+ ];
121
+ const result = deduplicateFindings(findings);
122
+ expect(result).toHaveLength(2);
123
+ });
124
+ it('does not merge findings in different files', () => {
125
+ const findings = [
126
+ makeFinding({
127
+ file: 'src/auth.ts',
128
+ line: 10,
129
+ body: 'SQL injection risk via exec call',
130
+ }),
131
+ makeFinding({
132
+ file: 'src/db.ts',
133
+ line: 10,
134
+ body: 'SQL injection risk via exec call',
135
+ }),
136
+ ];
137
+ const result = deduplicateFindings(findings);
138
+ expect(result).toHaveLength(2);
139
+ });
140
+ it('handles file-level comments (no line) with high body similarity', () => {
141
+ const findings = [
142
+ makeFinding({
143
+ file: 'src/auth.ts',
144
+ line: undefined,
145
+ body: 'This module has security vulnerabilities in the authentication flow',
146
+ }),
147
+ makeFinding({
148
+ file: 'src/auth.ts',
149
+ line: undefined,
150
+ body: 'Security vulnerabilities detected in the authentication flow of this module',
151
+ }),
152
+ ];
153
+ const result = deduplicateFindings(findings);
154
+ expect(result).toHaveLength(1);
155
+ expect(result[0].mergedWith).toHaveLength(1);
156
+ });
157
+ it('preserves all findings when no duplicates exist', () => {
158
+ const findings = [
159
+ makeFinding({
160
+ file: 'src/auth.ts',
161
+ line: 10,
162
+ body: 'SQL injection risk via exec call',
163
+ }),
164
+ makeFinding({
165
+ file: 'src/utils.ts',
166
+ line: 50,
167
+ body: 'Trailing whitespace is a cosmetic nit',
168
+ }),
169
+ makeFinding({
170
+ file: 'src/config.ts',
171
+ line: 5,
172
+ body: 'Missing null check on boundary parameter',
173
+ }),
174
+ ];
175
+ const result = deduplicateFindings(findings);
176
+ expect(result).toHaveLength(3);
177
+ for (const r of result) {
178
+ expect(r.mergedWith).toBeUndefined();
179
+ }
180
+ });
181
+ it('populates mergedWith on the primary finding', () => {
182
+ const findings = [
183
+ makeFinding({
184
+ tool: 'coderabbit',
185
+ file: 'src/auth.ts',
186
+ line: 10,
187
+ body: 'Credential leak risk in secret handling',
188
+ }),
189
+ makeFinding({
190
+ tool: 'gca',
191
+ file: 'src/auth.ts',
192
+ line: 11,
193
+ body: 'Secret credential leak detected here',
194
+ }),
195
+ makeFinding({
196
+ tool: 'unknown',
197
+ file: 'src/auth.ts',
198
+ line: 12,
199
+ body: 'Credential secret leak in this block',
200
+ }),
201
+ ];
202
+ const result = deduplicateFindings(findings);
203
+ expect(result).toHaveLength(1);
204
+ expect(result[0].tool).toBe('coderabbit'); // primary is the first one
205
+ expect(result[0].mergedWith).toHaveLength(2);
206
+ expect(result[0].dedupKey).toContain('merged:');
207
+ });
208
+ });
209
+ //# sourceMappingURL=triage-dedup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-dedup.test.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { NormalizedBotFinding } from './bot-review-parser.js';
2
+ import type { TriageCategory } from './triage-types.js';
3
+ /** Keyword dictionaries for severity mapping */
4
+ export declare const SECURITY_KEYWORDS: string[];
5
+ export declare const ARCHITECTURE_KEYWORDS: string[];
6
+ export declare const CONVENTION_KEYWORDS: string[];
7
+ export declare const NIT_KEYWORDS: string[];
8
+ export declare function mapToTriageCategory(finding: NormalizedBotFinding): TriageCategory;
9
+ //# sourceMappingURL=triage-severity-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-severity-mapper.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-severity-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,UAkB7B,CAAC;AAEF,eAAO,MAAM,qBAAqB,UAcjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,UAY/B,CAAC;AAEF,eAAO,MAAM,YAAY,UAcxB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAiBjF"}