@mmnto/cli 1.15.9 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/recurrence-stats.d.ts +19 -0
- package/dist/commands/recurrence-stats.d.ts.map +1 -0
- package/dist/commands/recurrence-stats.js +412 -0
- package/dist/commands/recurrence-stats.js.map +1 -0
- package/dist/commands/recurrence-stats.test.d.ts +2 -0
- package/dist/commands/recurrence-stats.test.d.ts.map +1 -0
- package/dist/commands/recurrence-stats.test.js +379 -0
- package/dist/commands/recurrence-stats.test.js.map +1 -0
- package/dist/commands/shield.d.ts +19 -0
- package/dist/commands/shield.d.ts.map +1 -1
- package/dist/commands/shield.js +39 -20
- package/dist/commands/shield.js.map +1 -1
- package/dist/commands/shield.test.js +63 -1
- package/dist/commands/shield.test.js.map +1 -1
- package/dist/commands/stats.d.ts +7 -1
- package/dist/commands/stats.d.ts.map +1 -1
- package/dist/commands/stats.js +10 -1
- package/dist/commands/stats.js.map +1 -1
- package/dist/git.d.ts +26 -3
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +54 -15
- package/dist/git.js.map +1 -1
- package/dist/git.test.js +71 -5
- package/dist/git.test.js.map +1 -1
- package/dist/index.js +42 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
// Mock @clack/prompts confirm to a no-op returning false.
|
|
6
|
+
vi.mock('@clack/prompts', () => ({
|
|
7
|
+
confirm: vi.fn().mockResolvedValue(false),
|
|
8
|
+
isCancel: vi.fn().mockReturnValue(false),
|
|
9
|
+
}));
|
|
10
|
+
// Mock the GitHubCliPrAdapter and gh-utils used by recurrence-stats.
|
|
11
|
+
const mockFetchPr = vi.fn();
|
|
12
|
+
const mockFetchReviewComments = vi.fn();
|
|
13
|
+
const mockGhFetchAndParse = vi.fn();
|
|
14
|
+
vi.mock('../adapters/github-cli-pr.js', () => ({
|
|
15
|
+
// Use a real class so `new GitHubCliPrAdapter(...)` is a valid construct.
|
|
16
|
+
GitHubCliPrAdapter: class GitHubCliPrAdapter {
|
|
17
|
+
fetchPr(num) {
|
|
18
|
+
return mockFetchPr(num);
|
|
19
|
+
}
|
|
20
|
+
fetchReviewComments(num) {
|
|
21
|
+
return mockFetchReviewComments(num);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
vi.mock('../adapters/gh-utils.js', () => ({
|
|
26
|
+
ghFetchAndParse: (...args) => mockGhFetchAndParse(...args),
|
|
27
|
+
handleGhError: (err) => {
|
|
28
|
+
throw err;
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
// Mock loadConfig + resolveConfigPath to a tmp totemDir.
|
|
32
|
+
let tmpDir;
|
|
33
|
+
let totemDir;
|
|
34
|
+
vi.mock('../utils.js', () => ({
|
|
35
|
+
loadConfig: vi.fn().mockImplementation(async () => ({ totemDir: '.totem' })),
|
|
36
|
+
resolveConfigPath: vi.fn().mockReturnValue(''),
|
|
37
|
+
}));
|
|
38
|
+
import { runRecurrenceStats } from './recurrence-stats.js';
|
|
39
|
+
// ─── Test setup ────────────────────────────────────────
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'recurrence-stats-'));
|
|
42
|
+
totemDir = path.join(tmpDir, '.totem');
|
|
43
|
+
fs.mkdirSync(totemDir, { recursive: true });
|
|
44
|
+
// Run from tmpDir so totemDir resolves under it.
|
|
45
|
+
process.chdir(tmpDir);
|
|
46
|
+
mockFetchPr.mockReset();
|
|
47
|
+
mockFetchReviewComments.mockReset();
|
|
48
|
+
mockGhFetchAndParse.mockReset();
|
|
49
|
+
});
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
// Restore cwd to a known location so test cleanup can rm tmpDir.
|
|
52
|
+
process.chdir(os.tmpdir());
|
|
53
|
+
fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
54
|
+
});
|
|
55
|
+
// ─── Test data factories ───────────────────────────────
|
|
56
|
+
function makeReviewComment(overrides) {
|
|
57
|
+
return {
|
|
58
|
+
id: overrides.id,
|
|
59
|
+
author: overrides.prAuthor ?? 'coderabbitai[bot]',
|
|
60
|
+
body: overrides.body,
|
|
61
|
+
path: overrides.filePath ?? 'src/handler.ts',
|
|
62
|
+
diffHunk: `@@ -1,3 +${overrides.line ?? 42},3 @@`,
|
|
63
|
+
inReplyToId: undefined,
|
|
64
|
+
createdAt: '2026-04-01T00:00:00.000Z',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function loadStats() {
|
|
68
|
+
const raw = fs.readFileSync(path.join(totemDir, 'recurrence-stats.json'), 'utf-8');
|
|
69
|
+
return JSON.parse(raw);
|
|
70
|
+
}
|
|
71
|
+
// ─── Tests ─────────────────────────────────────────────
|
|
72
|
+
describe('runRecurrenceStats', () => {
|
|
73
|
+
it('collapses path/line variants of the same finding to one signature', async () => {
|
|
74
|
+
mockGhFetchAndParse.mockReturnValue([
|
|
75
|
+
{ number: 100, mergedAt: '2026-04-01T00:00:00.000Z' },
|
|
76
|
+
{ number: 101, mergedAt: '2026-04-02T00:00:00.000Z' },
|
|
77
|
+
{ number: 102, mergedAt: '2026-04-03T00:00:00.000Z' },
|
|
78
|
+
]);
|
|
79
|
+
// Same finding text, different files / lines / fenced code blocks
|
|
80
|
+
mockFetchPr.mockImplementation((num) => ({
|
|
81
|
+
number: num,
|
|
82
|
+
title: `PR ${num}`,
|
|
83
|
+
body: '',
|
|
84
|
+
state: 'merged',
|
|
85
|
+
comments: [],
|
|
86
|
+
reviews: [],
|
|
87
|
+
}));
|
|
88
|
+
mockFetchReviewComments.mockImplementation((num) => {
|
|
89
|
+
const variants = [
|
|
90
|
+
'Avoid using `any` in packages/cli/src/foo.ts:42 — prefer `unknown`.',
|
|
91
|
+
'Avoid using `any` in packages/core/src/bar.ts:99 — prefer `unknown`.',
|
|
92
|
+
'Avoid using `any` in src/baz.ts:7 — prefer `unknown`.',
|
|
93
|
+
];
|
|
94
|
+
const idx = num - 100;
|
|
95
|
+
return [makeReviewComment({ id: 1000 + num, body: variants[idx], line: 42 + idx })];
|
|
96
|
+
});
|
|
97
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
98
|
+
const stats = loadStats();
|
|
99
|
+
// Threshold 1 → all clusters surface; should be exactly one cluster
|
|
100
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
101
|
+
expect(allPatterns.length).toBe(1);
|
|
102
|
+
expect(allPatterns[0].occurrences).toBe(3);
|
|
103
|
+
});
|
|
104
|
+
it('marks cluster as `mixed` when same signature spans multiple bots', async () => {
|
|
105
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 200, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
106
|
+
mockFetchPr.mockReturnValue({
|
|
107
|
+
number: 200,
|
|
108
|
+
title: 't',
|
|
109
|
+
body: '',
|
|
110
|
+
state: 'merged',
|
|
111
|
+
comments: [],
|
|
112
|
+
reviews: [],
|
|
113
|
+
});
|
|
114
|
+
mockFetchReviewComments.mockReturnValue([
|
|
115
|
+
makeReviewComment({
|
|
116
|
+
id: 1,
|
|
117
|
+
prAuthor: 'coderabbitai[bot]',
|
|
118
|
+
body: 'Avoid using `any` — prefer `unknown`.',
|
|
119
|
+
}),
|
|
120
|
+
makeReviewComment({
|
|
121
|
+
id: 2,
|
|
122
|
+
prAuthor: 'gemini-code-assist[bot]',
|
|
123
|
+
body: 'Avoid using `any` — prefer `unknown`.',
|
|
124
|
+
}),
|
|
125
|
+
]);
|
|
126
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
127
|
+
const stats = loadStats();
|
|
128
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
129
|
+
expect(allPatterns.length).toBe(1);
|
|
130
|
+
expect(allPatterns[0].tool).toBe('mixed');
|
|
131
|
+
// Two distinct findings with same signature
|
|
132
|
+
expect(allPatterns[0].occurrences).toBe(2);
|
|
133
|
+
});
|
|
134
|
+
it('counts occurrences across distinct findings, not distinct PRs', async () => {
|
|
135
|
+
mockGhFetchAndParse.mockReturnValue([
|
|
136
|
+
{ number: 300, mergedAt: '2026-04-01T00:00:00.000Z' },
|
|
137
|
+
{ number: 301, mergedAt: '2026-04-02T00:00:00.000Z' },
|
|
138
|
+
]);
|
|
139
|
+
mockFetchPr.mockReturnValue({
|
|
140
|
+
number: 0,
|
|
141
|
+
title: 't',
|
|
142
|
+
body: '',
|
|
143
|
+
state: 'merged',
|
|
144
|
+
comments: [],
|
|
145
|
+
reviews: [],
|
|
146
|
+
});
|
|
147
|
+
// PR 300 has 3 distinct findings with the same body, PR 301 has 1.
|
|
148
|
+
// Total occurrences: 4. Distinct PRs: 2.
|
|
149
|
+
mockFetchReviewComments.mockImplementation((num) => {
|
|
150
|
+
if (num === 300) {
|
|
151
|
+
return [
|
|
152
|
+
makeReviewComment({ id: 1, body: 'Empty catch block.', filePath: 'a.ts', line: 1 }),
|
|
153
|
+
makeReviewComment({ id: 2, body: 'Empty catch block.', filePath: 'b.ts', line: 2 }),
|
|
154
|
+
makeReviewComment({ id: 3, body: 'Empty catch block.', filePath: 'c.ts', line: 3 }),
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
return [makeReviewComment({ id: 4, body: 'Empty catch block.', filePath: 'd.ts', line: 4 })];
|
|
158
|
+
});
|
|
159
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
160
|
+
const stats = loadStats();
|
|
161
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
162
|
+
expect(allPatterns.length).toBe(1);
|
|
163
|
+
expect(allPatterns[0].occurrences).toBe(4);
|
|
164
|
+
expect(allPatterns[0].prs).toEqual(['300', '301']);
|
|
165
|
+
});
|
|
166
|
+
it('dedupes + sorts prs ascending numerically', async () => {
|
|
167
|
+
mockGhFetchAndParse.mockReturnValue([
|
|
168
|
+
{ number: 1500, mergedAt: '2026-04-03T00:00:00.000Z' },
|
|
169
|
+
{ number: 200, mergedAt: '2026-04-02T00:00:00.000Z' },
|
|
170
|
+
{ number: 80, mergedAt: '2026-04-01T00:00:00.000Z' },
|
|
171
|
+
]);
|
|
172
|
+
mockFetchPr.mockReturnValue({
|
|
173
|
+
number: 0,
|
|
174
|
+
title: 't',
|
|
175
|
+
body: '',
|
|
176
|
+
state: 'merged',
|
|
177
|
+
comments: [],
|
|
178
|
+
reviews: [],
|
|
179
|
+
});
|
|
180
|
+
mockFetchReviewComments.mockImplementation((num) => [
|
|
181
|
+
makeReviewComment({ id: num, body: 'Same finding text everywhere.', filePath: 'x.ts' }),
|
|
182
|
+
]);
|
|
183
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
184
|
+
const stats = loadStats();
|
|
185
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
186
|
+
expect(allPatterns.length).toBe(1);
|
|
187
|
+
// 80 < 200 < 1500 numerically (NOT lexically — '1500' < '200' < '80' lex)
|
|
188
|
+
expect(allPatterns[0].prs).toEqual(['80', '200', '1500']);
|
|
189
|
+
});
|
|
190
|
+
it('excludes patterns below threshold from headline patterns', async () => {
|
|
191
|
+
mockGhFetchAndParse.mockReturnValue([
|
|
192
|
+
{ number: 400, mergedAt: '2026-04-01T00:00:00.000Z' },
|
|
193
|
+
{ number: 401, mergedAt: '2026-04-02T00:00:00.000Z' },
|
|
194
|
+
]);
|
|
195
|
+
mockFetchPr.mockReturnValue({
|
|
196
|
+
number: 0,
|
|
197
|
+
title: 't',
|
|
198
|
+
body: '',
|
|
199
|
+
state: 'merged',
|
|
200
|
+
comments: [],
|
|
201
|
+
reviews: [],
|
|
202
|
+
});
|
|
203
|
+
mockFetchReviewComments.mockImplementation((num) => [
|
|
204
|
+
makeReviewComment({ id: num, body: `Distinct issue ${num}.`, filePath: 'x.ts' }),
|
|
205
|
+
]);
|
|
206
|
+
// threshold=5 — neither cluster has enough occurrences (each is 1)
|
|
207
|
+
await runRecurrenceStats({ threshold: 5, historyDepth: 5, yes: true });
|
|
208
|
+
const stats = loadStats();
|
|
209
|
+
expect(stats.patterns.length).toBe(0);
|
|
210
|
+
});
|
|
211
|
+
it('routes patterns matching an existing rule to coveredPatterns', async () => {
|
|
212
|
+
// Seed compiled-rules.json with a rule whose message overlaps the
|
|
213
|
+
// finding text well enough to clear Jaccard >= 0.6.
|
|
214
|
+
const rule = {
|
|
215
|
+
lessonHash: 'abc123',
|
|
216
|
+
lessonHeading: 'Avoid any',
|
|
217
|
+
message: 'Avoid using any type — prefer unknown',
|
|
218
|
+
pattern: 'any',
|
|
219
|
+
engine: 'regex',
|
|
220
|
+
severity: 'warning',
|
|
221
|
+
category: 'style',
|
|
222
|
+
fileGlobs: ['**/*.ts'],
|
|
223
|
+
status: 'active',
|
|
224
|
+
compiledAt: '2026-04-01T00:00:00.000Z',
|
|
225
|
+
};
|
|
226
|
+
fs.writeFileSync(path.join(totemDir, 'compiled-rules.json'), JSON.stringify({ version: 1, rules: [rule], nonCompilable: [] }));
|
|
227
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 500, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
228
|
+
mockFetchPr.mockReturnValue({
|
|
229
|
+
number: 500,
|
|
230
|
+
title: 't',
|
|
231
|
+
body: '',
|
|
232
|
+
state: 'merged',
|
|
233
|
+
comments: [],
|
|
234
|
+
reviews: [],
|
|
235
|
+
});
|
|
236
|
+
mockFetchReviewComments.mockReturnValue([
|
|
237
|
+
makeReviewComment({
|
|
238
|
+
id: 5001,
|
|
239
|
+
body: 'Avoid using any type — prefer unknown.',
|
|
240
|
+
}),
|
|
241
|
+
]);
|
|
242
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
243
|
+
const stats = loadStats();
|
|
244
|
+
expect(stats.patterns.length).toBe(0);
|
|
245
|
+
expect(stats.coveredPatterns.length).toBe(1);
|
|
246
|
+
expect(stats.coveredPatterns[0].tool).toBe('coderabbit');
|
|
247
|
+
});
|
|
248
|
+
it('atomic write — temp file is cleaned up after rename', async () => {
|
|
249
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 600, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
250
|
+
mockFetchPr.mockReturnValue({
|
|
251
|
+
number: 600,
|
|
252
|
+
title: 't',
|
|
253
|
+
body: '',
|
|
254
|
+
state: 'merged',
|
|
255
|
+
comments: [],
|
|
256
|
+
reviews: [],
|
|
257
|
+
});
|
|
258
|
+
mockFetchReviewComments.mockReturnValue([makeReviewComment({ id: 6001, body: 'A finding.' })]);
|
|
259
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
260
|
+
expect(fs.existsSync(path.join(totemDir, 'recurrence-stats.json'))).toBe(true);
|
|
261
|
+
// No .tmp residue under any name (covers the legacy fixed-name path
|
|
262
|
+
// AND the unique PID+timestamp form introduced for mmnto-ai/totem#1729 CR R1).
|
|
263
|
+
const residue = fs.readdirSync(totemDir).filter((f) => f.endsWith('.tmp'));
|
|
264
|
+
expect(residue).toEqual([]);
|
|
265
|
+
});
|
|
266
|
+
it('survives concurrent invocations without temp-file collision', async () => {
|
|
267
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 650, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
268
|
+
mockFetchPr.mockReturnValue({
|
|
269
|
+
number: 650,
|
|
270
|
+
title: 't',
|
|
271
|
+
body: '',
|
|
272
|
+
state: 'merged',
|
|
273
|
+
comments: [],
|
|
274
|
+
reviews: [],
|
|
275
|
+
});
|
|
276
|
+
mockFetchReviewComments.mockReturnValue([
|
|
277
|
+
makeReviewComment({ id: 6501, body: 'Concurrent invocation test finding.' }),
|
|
278
|
+
]);
|
|
279
|
+
// Two parallel invocations would collide on a fixed `.tmp` path; the
|
|
280
|
+
// PID+epochMs suffix introduced for mmnto-ai/totem#1729 CR R1 keeps
|
|
281
|
+
// them disjoint. Both must resolve and the final file must be valid.
|
|
282
|
+
await Promise.all([
|
|
283
|
+
runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true }),
|
|
284
|
+
runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true }),
|
|
285
|
+
]);
|
|
286
|
+
expect(fs.existsSync(path.join(totemDir, 'recurrence-stats.json'))).toBe(true);
|
|
287
|
+
const stats = loadStats();
|
|
288
|
+
expect(stats.version).toBe(1);
|
|
289
|
+
// No .tmp residue under any name
|
|
290
|
+
const residue = fs.readdirSync(totemDir).filter((f) => f.endsWith('.tmp'));
|
|
291
|
+
expect(residue).toEqual([]);
|
|
292
|
+
});
|
|
293
|
+
it('does not throw when compiled-rules.json is missing', async () => {
|
|
294
|
+
// Make sure rules file does not exist
|
|
295
|
+
const rulesPath = path.join(totemDir, 'compiled-rules.json');
|
|
296
|
+
if (fs.existsSync(rulesPath))
|
|
297
|
+
fs.unlinkSync(rulesPath);
|
|
298
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 700, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
299
|
+
mockFetchPr.mockReturnValue({
|
|
300
|
+
number: 700,
|
|
301
|
+
title: 't',
|
|
302
|
+
body: '',
|
|
303
|
+
state: 'merged',
|
|
304
|
+
comments: [],
|
|
305
|
+
reviews: [],
|
|
306
|
+
});
|
|
307
|
+
mockFetchReviewComments.mockReturnValue([
|
|
308
|
+
makeReviewComment({ id: 7001, body: 'Some finding.' }),
|
|
309
|
+
]);
|
|
310
|
+
await expect(runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true })).resolves.toBeUndefined();
|
|
311
|
+
});
|
|
312
|
+
it('folds trap-ledger override events as co-equal findings', async () => {
|
|
313
|
+
// Seed events.ndjson with one override event
|
|
314
|
+
const ledgerDir = path.join(totemDir, 'ledger');
|
|
315
|
+
fs.mkdirSync(ledgerDir, { recursive: true });
|
|
316
|
+
const event = {
|
|
317
|
+
timestamp: '2026-04-01T00:00:00.000Z',
|
|
318
|
+
type: 'override',
|
|
319
|
+
ruleId: 'rule-xyz',
|
|
320
|
+
file: 'src/legacy.ts',
|
|
321
|
+
line: 10,
|
|
322
|
+
justification: 'Legacy code we will refactor later.',
|
|
323
|
+
source: 'shield',
|
|
324
|
+
};
|
|
325
|
+
fs.writeFileSync(path.join(ledgerDir, 'events.ndjson'), JSON.stringify(event) + '\n');
|
|
326
|
+
mockGhFetchAndParse.mockReturnValue([]);
|
|
327
|
+
mockFetchPr.mockReturnValue({
|
|
328
|
+
number: 0,
|
|
329
|
+
title: 't',
|
|
330
|
+
body: '',
|
|
331
|
+
state: 'merged',
|
|
332
|
+
comments: [],
|
|
333
|
+
reviews: [],
|
|
334
|
+
});
|
|
335
|
+
mockFetchReviewComments.mockReturnValue([]);
|
|
336
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
337
|
+
const stats = loadStats();
|
|
338
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
339
|
+
expect(allPatterns.length).toBe(1);
|
|
340
|
+
expect(allPatterns[0].tool).toBe('override');
|
|
341
|
+
// Override events are not tied to a PR
|
|
342
|
+
expect(allPatterns[0].prs).toEqual([]);
|
|
343
|
+
});
|
|
344
|
+
it('marks cluster as `mixed` when override + bot finding share a signature', async () => {
|
|
345
|
+
const ledgerDir = path.join(totemDir, 'ledger');
|
|
346
|
+
fs.mkdirSync(ledgerDir, { recursive: true });
|
|
347
|
+
// Use a justification that, after normalization, matches the bot finding
|
|
348
|
+
const event = {
|
|
349
|
+
timestamp: '2026-04-01T00:00:00.000Z',
|
|
350
|
+
type: 'override',
|
|
351
|
+
ruleId: 'rule-xyz',
|
|
352
|
+
file: 'src/handler.ts',
|
|
353
|
+
line: 10,
|
|
354
|
+
justification: 'Avoid using any type prefer unknown.',
|
|
355
|
+
source: 'shield',
|
|
356
|
+
};
|
|
357
|
+
fs.writeFileSync(path.join(ledgerDir, 'events.ndjson'), JSON.stringify(event) + '\n');
|
|
358
|
+
mockGhFetchAndParse.mockReturnValue([{ number: 800, mergedAt: '2026-04-01T00:00:00.000Z' }]);
|
|
359
|
+
mockFetchPr.mockReturnValue({
|
|
360
|
+
number: 800,
|
|
361
|
+
title: 't',
|
|
362
|
+
body: '',
|
|
363
|
+
state: 'merged',
|
|
364
|
+
comments: [],
|
|
365
|
+
reviews: [],
|
|
366
|
+
});
|
|
367
|
+
mockFetchReviewComments.mockReturnValue([
|
|
368
|
+
makeReviewComment({ id: 8001, body: 'Avoid using any type prefer unknown.' }),
|
|
369
|
+
]);
|
|
370
|
+
await runRecurrenceStats({ threshold: 1, historyDepth: 5, yes: true });
|
|
371
|
+
const stats = loadStats();
|
|
372
|
+
const allPatterns = [...stats.patterns, ...stats.coveredPatterns];
|
|
373
|
+
expect(allPatterns.length).toBe(1);
|
|
374
|
+
expect(allPatterns[0].tool).toBe('mixed');
|
|
375
|
+
expect(allPatterns[0].occurrences).toBe(2);
|
|
376
|
+
expect(allPatterns[0].prs).toEqual(['800']);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
//# sourceMappingURL=recurrence-stats.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence-stats.test.js","sourceRoot":"","sources":["../../src/commands/recurrence-stats.test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEzE,0DAA0D;AAC1D,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC;IACzC,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC;CACzC,CAAC,CAAC,CAAC;AAEJ,qEAAqE;AACrE,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAC5B,MAAM,uBAAuB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAEpC,EAAE,CAAC,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,kBAAkB,EAAE,MAAM,kBAAkB;QAC1C,OAAO,CAAC,GAAW;YACjB,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,mBAAmB,CAAC,GAAW;YAC7B,OAAO,uBAAuB,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;KACF;CACF,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,eAAe,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC;IACrE,aAAa,EAAE,CAAC,GAAY,EAAE,EAAE;QAC9B,MAAM,GAAG,CAAC;IACZ,CAAC;CACF,CAAC,CAAC,CAAC;AAEJ,yDAAyD;AACzD,IAAI,MAAc,CAAC;AACnB,IAAI,QAAgB,CAAC;AAErB,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;CAC/C,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,0DAA0D;AAE1D,UAAU,CAAC,GAAG,EAAE;IACd,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACrE,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,iDAAiD;IACjD,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtB,WAAW,CAAC,SAAS,EAAE,CAAC;IACxB,uBAAuB,CAAC,SAAS,EAAE,CAAC;IACpC,mBAAmB,CAAC,SAAS,EAAE,CAAC;AAClC,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,iEAAiE;IACjE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3B,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;AACtF,CAAC,CAAC,CAAC;AAEH,0DAA0D;AAE1D,SAAS,iBAAiB,CAAC,SAM1B;IACC,OAAO;QACL,EAAE,EAAE,SAAS,CAAC,EAAE;QAChB,MAAM,EAAE,SAAS,CAAC,QAAQ,IAAI,mBAAmB;QACjD,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,IAAI,EAAE,SAAS,CAAC,QAAQ,IAAI,gBAAgB;QAC5C,QAAQ,EAAE,YAAY,SAAS,CAAC,IAAI,IAAI,EAAE,OAAO;QACjD,WAAW,EAAE,SAAS;QACtB,SAAS,EAAE,0BAA0B;KACtC,CAAC;AACJ,CAAC;AAWD,SAAS,SAAS;IAOhB,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,EAAE,OAAO,CAAC,CAAC;IACnF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,0DAA0D;AAE1D,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,mBAAmB,CAAC,eAAe,CAAC;YAClC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACrD,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACrD,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;SACtD,CAAC,CAAC;QAEH,kEAAkE;QAClE,WAAW,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC;YAC/C,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,MAAM,GAAG,EAAE;YAClB,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC,CAAC;QACJ,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE;YACzD,MAAM,QAAQ,GAAG;gBACf,qEAAqE;gBACrE,sEAAsE;gBACtE,uDAAuD;aACxD,CAAC;YACF,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;YACtB,OAAO,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,GAAG,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAE,EAAE,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,oEAAoE;QACpE,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC;YACtC,iBAAiB,CAAC;gBAChB,EAAE,EAAE,CAAC;gBACL,QAAQ,EAAE,mBAAmB;gBAC7B,IAAI,EAAE,uCAAuC;aAC9C,CAAC;YACF,iBAAiB,CAAC;gBAChB,EAAE,EAAE,CAAC;gBACL,QAAQ,EAAE,yBAAyB;gBACnC,IAAI,EAAE,uCAAuC;aAC9C,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,4CAA4C;QAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,mBAAmB,CAAC,eAAe,CAAC;YAClC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACrD,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;SACtD,CAAC,CAAC;QACH,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,mEAAmE;QACnE,yCAAyC;QACzC,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE;YACzD,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;gBAChB,OAAO;oBACL,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;oBACnF,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;oBACnF,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;iBACpF,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,mBAAmB,CAAC,eAAe,CAAC;YAClC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACtD,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACrD,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,0BAA0B,EAAE;SACrD,CAAC,CAAC;QACH,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC;YAC1D,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,+BAA+B,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;SACxF,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,0EAA0E;QAC1E,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,mBAAmB,CAAC,eAAe,CAAC;YAClC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;YACrD,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE;SACtD,CAAC,CAAC;QACH,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC;YAC1D,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,kBAAkB,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;SACjF,CAAC,CAAC;QAEH,mEAAmE;QACnE,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,kEAAkE;QAClE,oDAAoD;QACpD,MAAM,IAAI,GAAG;YACX,UAAU,EAAE,QAAQ;YACpB,aAAa,EAAE,WAAW;YAC1B,OAAO,EAAE,uCAAuC;YAChD,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,OAAgB;YACxB,QAAQ,EAAE,SAAkB;YAC5B,QAAQ,EAAE,OAAgB;YAC1B,SAAS,EAAE,CAAC,SAAS,CAAC;YACtB,MAAM,EAAE,QAAiB;YACzB,UAAU,EAAE,0BAA0B;SACvC,CAAC;QACF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAC1C,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CACjE,CAAC;QAEF,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC;YACtC,iBAAiB,CAAC;gBAChB,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,wCAAwC;aAC/C,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/F,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,oEAAoE;QACpE,+EAA+E;QAC/E,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC;YACtC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,qCAAqC,EAAE,CAAC;SAC7E,CAAC,CAAC;QAEH,qEAAqE;QACrE,oEAAoE;QACpE,qEAAqE;QACrE,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;YAChE,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;SACjE,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,iCAAiC;QACjC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,sCAAsC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;QAC7D,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAEvD,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC;YACtC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;SACvD,CAAC,CAAC;QAEH,MAAM,MAAM,CACV,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CACjE,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,6CAA6C;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG;YACZ,SAAS,EAAE,0BAA0B;YACrC,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,EAAE;YACR,aAAa,EAAE,qCAAqC;YACpD,MAAM,EAAE,QAAQ;SACjB,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QAEtF,mBAAmB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACxC,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAE5C,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,uCAAuC;QACvC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,yEAAyE;QACzE,MAAM,KAAK,GAAG;YACZ,SAAS,EAAE,0BAA0B;YACrC,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,EAAE;YACR,aAAa,EAAE,sCAAsC;YACrD,MAAM,EAAE,QAAQ;SACjB,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QAEtF,mBAAmB,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC7F,WAAW,CAAC,eAAe,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,uBAAuB,CAAC,eAAe,CAAC;YACtC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,sCAAsC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,MAAM,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -46,6 +46,23 @@ export declare function formatVerdictForDisplay(verdict: ShieldStructuredVerdict
|
|
|
46
46
|
* boundary.
|
|
47
47
|
*/
|
|
48
48
|
export declare function writeReviewedContentHash(cwd: string, totemDir: string, configRoot?: string, extensions?: readonly string[]): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Record a shield override: append the override event to the Trap Ledger
|
|
51
|
+
* AND stamp the reviewed-content-hash so the push-gate hook unblocks.
|
|
52
|
+
*
|
|
53
|
+
* mmnto-ai/totem#1716: prior to this helper the override branch only wrote the ledger
|
|
54
|
+
* entry; the missing stamp left the contributor stuck behind the push-gate
|
|
55
|
+
* with a tribal-knowledge `git reset --soft HEAD~1 && totem review --staged`
|
|
56
|
+
* workaround. Override is a legitimate completion path (with logged
|
|
57
|
+
* justification) and must produce the same cache state as a passing review.
|
|
58
|
+
*/
|
|
59
|
+
export declare function recordShieldOverride(params: {
|
|
60
|
+
override: string;
|
|
61
|
+
cwd: string;
|
|
62
|
+
totemDir: string;
|
|
63
|
+
configRoot?: string;
|
|
64
|
+
sourceExtensions?: readonly string[];
|
|
65
|
+
}): Promise<void>;
|
|
49
66
|
export type ShieldFormat = 'text' | 'sarif' | 'json';
|
|
50
67
|
export interface ShieldOptions {
|
|
51
68
|
raw?: boolean;
|
|
@@ -53,6 +70,8 @@ export interface ShieldOptions {
|
|
|
53
70
|
model?: string;
|
|
54
71
|
fresh?: boolean;
|
|
55
72
|
staged?: boolean;
|
|
73
|
+
/** Explicit ref range for `git diff` (mmnto-ai/totem#1717). Bypasses implicit fallback chain. */
|
|
74
|
+
diff?: string;
|
|
56
75
|
mode?: 'standard' | 'structural';
|
|
57
76
|
learn?: boolean;
|
|
58
77
|
yes?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shield.d.ts","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"shield.d.ts","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/shield.js
CHANGED
|
@@ -348,6 +348,30 @@ export async function writeReviewedContentHash(cwd, totemDir, configRoot, extens
|
|
|
348
348
|
}
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Record a shield override: append the override event to the Trap Ledger
|
|
353
|
+
* AND stamp the reviewed-content-hash so the push-gate hook unblocks.
|
|
354
|
+
*
|
|
355
|
+
* mmnto-ai/totem#1716: prior to this helper the override branch only wrote the ledger
|
|
356
|
+
* entry; the missing stamp left the contributor stuck behind the push-gate
|
|
357
|
+
* with a tribal-knowledge `git reset --soft HEAD~1 && totem review --staged`
|
|
358
|
+
* workaround. Override is a legitimate completion path (with logged
|
|
359
|
+
* justification) and must produce the same cache state as a passing review.
|
|
360
|
+
*/
|
|
361
|
+
export async function recordShieldOverride(params) {
|
|
362
|
+
const path = await import('node:path');
|
|
363
|
+
const { appendLedgerEvent } = await import('@mmnto/totem');
|
|
364
|
+
const resolvedTotemDir = path.join(params.configRoot ?? params.cwd, params.totemDir);
|
|
365
|
+
appendLedgerEvent(resolvedTotemDir, {
|
|
366
|
+
timestamp: new Date().toISOString(),
|
|
367
|
+
type: 'override',
|
|
368
|
+
ruleId: 'shield-override',
|
|
369
|
+
file: '(shield)',
|
|
370
|
+
justification: params.override,
|
|
371
|
+
source: 'shield',
|
|
372
|
+
}, (msg) => log.dim(DISPLAY_TAG, msg));
|
|
373
|
+
await writeReviewedContentHash(params.cwd, params.totemDir, params.configRoot, params.sourceExtensions);
|
|
374
|
+
}
|
|
351
375
|
// ─── Deterministic mode (delegates to shared engine) ─
|
|
352
376
|
// ─── Learn: extract lessons from failed verdict ─────
|
|
353
377
|
export async function learnFromVerdict(verdictContent, diff, options, config, cwd, configRoot) {
|
|
@@ -580,24 +604,23 @@ async function handleVerdictResult(content, diff, options, config, cwd, configRo
|
|
|
580
604
|
await writeReviewedContentHash(cwd, config.totemDir, configRoot, config.review.sourceExtensions);
|
|
581
605
|
}
|
|
582
606
|
else if (options.override) {
|
|
583
|
-
const { appendLedgerEvent } = await import('@mmnto/totem');
|
|
584
607
|
const criticalFindings = filtered.filter((f) => f.severity === 'CRITICAL');
|
|
585
608
|
log.warn(DISPLAY_TAG, `SHIELD OVERRIDE APPLIED: ${options.override}`);
|
|
586
609
|
for (const finding of criticalFindings) {
|
|
587
610
|
log.warn(DISPLAY_TAG, ` [overridden] ${finding.message}`);
|
|
588
611
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}, (msg) => log.dim(DISPLAY_TAG, msg));
|
|
612
|
+
await recordShieldOverride({
|
|
613
|
+
override: options.override,
|
|
614
|
+
cwd,
|
|
615
|
+
totemDir: config.totemDir,
|
|
616
|
+
configRoot,
|
|
617
|
+
sourceExtensions: config.review.sourceExtensions,
|
|
618
|
+
});
|
|
597
619
|
// Track overridden findings for exemption engine (only non-exempted findings)
|
|
598
620
|
const { readLocalExemptions, writeLocalExemptions } = await import('../exemptions/exemption-store.js');
|
|
599
621
|
const { trackFalsePositives } = await import('../exemptions/exemption-engine.js');
|
|
600
622
|
const { PROMOTION_THRESHOLD } = await import('../exemptions/exemption-schema.js');
|
|
623
|
+
const { appendLedgerEvent } = await import('@mmnto/totem');
|
|
601
624
|
const localExemptions = readLocalExemptions(cacheDir, (msg) => log.dim(DISPLAY_TAG, msg));
|
|
602
625
|
const tracked = trackFalsePositives(criticalFindings, 'shield', localExemptions, shared);
|
|
603
626
|
for (const msg of tracked.promoted) {
|
|
@@ -636,18 +659,14 @@ async function handleVerdictResult(content, diff, options, config, cwd, configRo
|
|
|
636
659
|
await writeReviewedContentHash(cwd, config.totemDir, configRoot, config.review.sourceExtensions);
|
|
637
660
|
}
|
|
638
661
|
else if (options.override) {
|
|
639
|
-
const { appendLedgerEvent } = await import('@mmnto/totem');
|
|
640
|
-
const pathMod = await import('node:path');
|
|
641
|
-
const resolvedTotemDir = pathMod.join(configRoot ?? cwd, config.totemDir);
|
|
642
662
|
log.warn(DISPLAY_TAG, `SHIELD OVERRIDE APPLIED: ${options.override}`);
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}, (msg) => log.dim(DISPLAY_TAG, msg));
|
|
663
|
+
await recordShieldOverride({
|
|
664
|
+
override: options.override,
|
|
665
|
+
cwd,
|
|
666
|
+
totemDir: config.totemDir,
|
|
667
|
+
configRoot,
|
|
668
|
+
sourceExtensions: config.review.sourceExtensions,
|
|
669
|
+
});
|
|
651
670
|
}
|
|
652
671
|
else {
|
|
653
672
|
if (options.learn || config.shieldAutoLearn)
|