@mmnto/cli 1.5.4 → 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 (53) hide show
  1. package/dist/commands/doctor.d.ts +9 -1
  2. package/dist/commands/doctor.d.ts.map +1 -1
  3. package/dist/commands/doctor.js +141 -1
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/doctor.test.js +200 -2
  6. package/dist/commands/doctor.test.js.map +1 -1
  7. package/dist/commands/ledger-analyzer.d.ts +24 -0
  8. package/dist/commands/ledger-analyzer.d.ts.map +1 -0
  9. package/dist/commands/ledger-analyzer.js +64 -0
  10. package/dist/commands/ledger-analyzer.js.map +1 -0
  11. package/dist/commands/ledger-analyzer.test.d.ts +2 -0
  12. package/dist/commands/ledger-analyzer.test.d.ts.map +1 -0
  13. package/dist/commands/ledger-analyzer.test.js +163 -0
  14. package/dist/commands/ledger-analyzer.test.js.map +1 -0
  15. package/dist/commands/rule-mutator.d.ts +17 -0
  16. package/dist/commands/rule-mutator.d.ts.map +1 -0
  17. package/dist/commands/rule-mutator.js +33 -0
  18. package/dist/commands/rule-mutator.js.map +1 -0
  19. package/dist/commands/rule-mutator.test.d.ts +2 -0
  20. package/dist/commands/rule-mutator.test.d.ts.map +1 -0
  21. package/dist/commands/rule-mutator.test.js +104 -0
  22. package/dist/commands/rule-mutator.test.js.map +1 -0
  23. package/dist/commands/triage-pr.d.ts +21 -0
  24. package/dist/commands/triage-pr.d.ts.map +1 -0
  25. package/dist/commands/triage-pr.js +231 -0
  26. package/dist/commands/triage-pr.js.map +1 -0
  27. package/dist/commands/triage-pr.test.d.ts +2 -0
  28. package/dist/commands/triage-pr.test.d.ts.map +1 -0
  29. package/dist/commands/triage-pr.test.js +163 -0
  30. package/dist/commands/triage-pr.test.js.map +1 -0
  31. package/dist/index.js +17 -3
  32. package/dist/index.js.map +1 -1
  33. package/dist/parsers/triage-dedup.d.ts +8 -0
  34. package/dist/parsers/triage-dedup.d.ts.map +1 -0
  35. package/dist/parsers/triage-dedup.js +134 -0
  36. package/dist/parsers/triage-dedup.js.map +1 -0
  37. package/dist/parsers/triage-dedup.test.d.ts +2 -0
  38. package/dist/parsers/triage-dedup.test.d.ts.map +1 -0
  39. package/dist/parsers/triage-dedup.test.js +209 -0
  40. package/dist/parsers/triage-dedup.test.js.map +1 -0
  41. package/dist/parsers/triage-severity-mapper.d.ts +9 -0
  42. package/dist/parsers/triage-severity-mapper.d.ts.map +1 -0
  43. package/dist/parsers/triage-severity-mapper.js +86 -0
  44. package/dist/parsers/triage-severity-mapper.js.map +1 -0
  45. package/dist/parsers/triage-severity-mapper.test.d.ts +2 -0
  46. package/dist/parsers/triage-severity-mapper.test.d.ts.map +1 -0
  47. package/dist/parsers/triage-severity-mapper.test.js +62 -0
  48. package/dist/parsers/triage-severity-mapper.test.js.map +1 -0
  49. package/dist/parsers/triage-types.d.ts +12 -0
  50. package/dist/parsers/triage-types.d.ts.map +1 -0
  51. package/dist/parsers/triage-types.js +2 -0
  52. package/dist/parsers/triage-types.js.map +1 -0
  53. package/package.json +2 -2
@@ -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"}
@@ -0,0 +1,86 @@
1
+ /** Keyword dictionaries for severity mapping */
2
+ export const SECURITY_KEYWORDS = [
3
+ 'injection',
4
+ 'xss',
5
+ 'csrf',
6
+ 'redos',
7
+ 'shell',
8
+ 'exec',
9
+ 'spawn',
10
+ 'credential',
11
+ 'secret',
12
+ 'leak',
13
+ 'vulnerability',
14
+ 'cwe-',
15
+ 'security',
16
+ 'sanitiz',
17
+ 'escap',
18
+ 'authori',
19
+ 'authenticat',
20
+ ];
21
+ export const ARCHITECTURE_KEYWORDS = [
22
+ 'empty catch',
23
+ 'validation',
24
+ 'zod',
25
+ 'type safety',
26
+ 'static import',
27
+ 'dynamic import',
28
+ 'race condition',
29
+ 'missing guard',
30
+ 'null check',
31
+ 'error handling',
32
+ 'boundary',
33
+ 'coupling',
34
+ 'abstraction',
35
+ ];
36
+ export const CONVENTION_KEYWORDS = [
37
+ 'tag',
38
+ 'log.error',
39
+ 'naming',
40
+ 'style guide',
41
+ 'rule #',
42
+ 'convention',
43
+ 'formatting',
44
+ 'casing',
45
+ 'prefix',
46
+ 'totem error',
47
+ 'styleguide',
48
+ ];
49
+ export const NIT_KEYWORDS = [
50
+ 'marketing',
51
+ 'copy',
52
+ 'rephrase',
53
+ 'consider',
54
+ 'optional',
55
+ 'nitpick',
56
+ 'nit',
57
+ 'minor',
58
+ 'cosmetic',
59
+ 'typo',
60
+ 'spelling',
61
+ 'whitespace',
62
+ 'trailing',
63
+ ];
64
+ export function mapToTriageCategory(finding) {
65
+ // Only search the body for keywords — NOT severity, which would cause
66
+ // 'minor' severity to match NIT_KEYWORDS and misbucket
67
+ const text = finding.body.toLowerCase();
68
+ // Check in priority order — security first
69
+ if (SECURITY_KEYWORDS.some((kw) => text.includes(kw)))
70
+ return 'security';
71
+ if (ARCHITECTURE_KEYWORDS.some((kw) => text.includes(kw)))
72
+ return 'architecture';
73
+ if (CONVENTION_KEYWORDS.some((kw) => text.includes(kw)))
74
+ return 'convention';
75
+ if (NIT_KEYWORDS.some((kw) => text.includes(kw)))
76
+ return 'nit';
77
+ // Fall back to bot-assigned severity
78
+ if (finding.severity === 'critical' || finding.severity === 'high')
79
+ return 'security';
80
+ if (finding.severity === 'major' || finding.severity === 'medium')
81
+ return 'architecture';
82
+ if (finding.severity === 'minor' || finding.severity === 'low')
83
+ return 'convention';
84
+ return 'architecture'; // default to architecture (better safe than sorry)
85
+ }
86
+ //# sourceMappingURL=triage-severity-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-severity-mapper.js","sourceRoot":"","sources":["../../src/parsers/triage-severity-mapper.ts"],"names":[],"mappings":"AAGA,gDAAgD;AAChD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW;IACX,KAAK;IACL,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,YAAY;IACZ,QAAQ;IACR,MAAM;IACN,eAAe;IACf,MAAM;IACN,UAAU;IACV,SAAS;IACT,OAAO;IACP,SAAS;IACT,aAAa;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,aAAa;IACb,YAAY;IACZ,KAAK;IACL,aAAa;IACb,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,eAAe;IACf,YAAY;IACZ,gBAAgB;IAChB,UAAU;IACV,UAAU;IACV,aAAa;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,KAAK;IACL,WAAW;IACX,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,aAAa;IACb,YAAY;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,WAAW;IACX,MAAM;IACN,UAAU;IACV,UAAU;IACV,UAAU;IACV,SAAS;IACT,KAAK;IACL,OAAO;IACP,UAAU;IACV,MAAM;IACN,UAAU;IACV,YAAY;IACZ,UAAU;CACX,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,sEAAsE;IACtE,uDAAuD;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAExC,2CAA2C;IAC3C,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC;IACzE,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,cAAc,CAAC;IACjF,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,YAAY,CAAC;IAC7E,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAE/D,qCAAqC;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC;IACtF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,cAAc,CAAC;IACzF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;QAAE,OAAO,YAAY,CAAC;IAEpF,OAAO,cAAc,CAAC,CAAC,mDAAmD;AAC5E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=triage-severity-mapper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-severity-mapper.test.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-severity-mapper.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,62 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { mapToTriageCategory } from './triage-severity-mapper.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
+ // ─── mapToTriageCategory ─────────────────────────────
14
+ describe('mapToTriageCategory', () => {
15
+ it('maps shell injection finding to security', () => {
16
+ const finding = makeFinding({ body: 'Avoid shell injection via exec() call' });
17
+ expect(mapToTriageCategory(finding)).toBe('security');
18
+ });
19
+ it('maps ReDoS finding to security', () => {
20
+ const finding = makeFinding({ body: 'This regex is vulnerable to ReDoS attacks' });
21
+ expect(mapToTriageCategory(finding)).toBe('security');
22
+ });
23
+ it('maps empty catch finding to architecture', () => {
24
+ const finding = makeFinding({ body: 'Empty catch block silently swallows errors' });
25
+ expect(mapToTriageCategory(finding)).toBe('architecture');
26
+ });
27
+ it('maps static import finding to architecture', () => {
28
+ const finding = makeFinding({
29
+ body: 'Convert static import to dynamic import for startup perf',
30
+ });
31
+ expect(mapToTriageCategory(finding)).toBe('architecture');
32
+ });
33
+ it('maps log.error tag finding to convention', () => {
34
+ const finding = makeFinding({ body: 'Missing [Totem Error] tag on log.error call' });
35
+ expect(mapToTriageCategory(finding)).toBe('convention');
36
+ });
37
+ it('maps styleguide rule reference to convention', () => {
38
+ const finding = makeFinding({ body: 'Violates styleguide naming convention' });
39
+ expect(mapToTriageCategory(finding)).toBe('convention');
40
+ });
41
+ it('maps nitpick finding to nit', () => {
42
+ const finding = makeFinding({ body: 'Nitpick: maybe rename this variable' });
43
+ expect(mapToTriageCategory(finding)).toBe('nit');
44
+ });
45
+ it('maps whitespace finding to nit', () => {
46
+ const finding = makeFinding({ body: 'Trailing whitespace on line 42' });
47
+ expect(mapToTriageCategory(finding)).toBe('nit');
48
+ });
49
+ it('falls back to architecture for unknown findings', () => {
50
+ const finding = makeFinding({ body: 'Something unusual happened here' });
51
+ expect(mapToTriageCategory(finding)).toBe('architecture');
52
+ });
53
+ it('uses bot severity as fallback (critical -> security)', () => {
54
+ const finding = makeFinding({ body: 'Something unusual happened here', severity: 'critical' });
55
+ expect(mapToTriageCategory(finding)).toBe('security');
56
+ });
57
+ it('assigns nit category to findings with nitpick keywords regardless of case', () => {
58
+ const finding = makeFinding({ body: 'NITPICK: This could be cleaner' });
59
+ expect(mapToTriageCategory(finding)).toBe('nit');
60
+ });
61
+ });
62
+ //# sourceMappingURL=triage-severity-mapper.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-severity-mapper.test.js","sourceRoot":"","sources":["../../src/parsers/triage-severity-mapper.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { NormalizedBotFinding } from './bot-review-parser.js';
2
+ /** Triage categories ordered by blast radius */
3
+ export type TriageCategory = 'security' | 'architecture' | 'convention' | 'nit';
4
+ /** A finding with heuristic category assignment and dedup info */
5
+ export interface CategorizedFinding extends NormalizedBotFinding {
6
+ triageCategory: TriageCategory;
7
+ /** Unique ID for dedup grouping */
8
+ dedupKey: string;
9
+ /** Other findings merged into this one during dedup */
10
+ mergedWith?: NormalizedBotFinding[];
11
+ }
12
+ //# sourceMappingURL=triage-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-types.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,cAAc,GAAG,YAAY,GAAG,KAAK,CAAC;AAEhF,kEAAkE;AAClE,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,cAAc,EAAE,cAAc,CAAC;IAC/B,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACrC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=triage-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-types.js","sourceRoot":"","sources":["../../src/parsers/triage-types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmnto/cli",
3
- "version": "1.5.4",
3
+ "version": "1.5.5",
4
4
  "description": "CLI for Totem — AI persistent memory and context layer",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "smol-toml": "^1.6.1",
24
24
  "yaml": "^2.4.0",
25
25
  "zod": "^3.24.0",
26
- "@mmnto/totem": "1.5.4"
26
+ "@mmnto/totem": "1.5.5"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@anthropic-ai/sdk": "^0.78.0",