@mmnto/cli 1.15.10 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/commands/recurrence-stats.d.ts +19 -0
  2. package/dist/commands/recurrence-stats.d.ts.map +1 -0
  3. package/dist/commands/recurrence-stats.js +412 -0
  4. package/dist/commands/recurrence-stats.js.map +1 -0
  5. package/dist/commands/recurrence-stats.test.d.ts +2 -0
  6. package/dist/commands/recurrence-stats.test.d.ts.map +1 -0
  7. package/dist/commands/recurrence-stats.test.js +379 -0
  8. package/dist/commands/recurrence-stats.test.js.map +1 -0
  9. package/dist/commands/shield-estimate.d.ts +24 -0
  10. package/dist/commands/shield-estimate.d.ts.map +1 -0
  11. package/dist/commands/shield-estimate.js +55 -0
  12. package/dist/commands/shield-estimate.js.map +1 -0
  13. package/dist/commands/shield-estimate.test.d.ts +2 -0
  14. package/dist/commands/shield-estimate.test.d.ts.map +1 -0
  15. package/dist/commands/shield-estimate.test.js +309 -0
  16. package/dist/commands/shield-estimate.test.js.map +1 -0
  17. package/dist/commands/shield-templates.d.ts +9 -0
  18. package/dist/commands/shield-templates.d.ts.map +1 -1
  19. package/dist/commands/shield-templates.js +9 -0
  20. package/dist/commands/shield-templates.js.map +1 -1
  21. package/dist/commands/shield.d.ts +13 -0
  22. package/dist/commands/shield.d.ts.map +1 -1
  23. package/dist/commands/shield.js +33 -0
  24. package/dist/commands/shield.js.map +1 -1
  25. package/dist/commands/stats.d.ts +7 -1
  26. package/dist/commands/stats.d.ts.map +1 -1
  27. package/dist/commands/stats.js +10 -1
  28. package/dist/commands/stats.js.map +1 -1
  29. package/dist/index.js +39 -3
  30. package/dist/index.js.map +1 -1
  31. 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":"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"}
@@ -0,0 +1,24 @@
1
+ import type { TotemConfig } from '@mmnto/totem';
2
+ import type { ShieldOptions } from './shield.js';
3
+ /**
4
+ * Pre-flight deterministic-rule estimator for `totem review --estimate`
5
+ * (mmnto-ai/totem#1714). Runs the same compiled-rule engine as
6
+ * `totem lint` against the diff resolved by `totem review`'s standard
7
+ * resolution chain (explicit `--diff` → `--staged` → working-tree →
8
+ * branch-vs-base) and returns immediately. No orchestrator, no
9
+ * embedder, no LanceDB — the entire LLM Verification Layer is
10
+ * structurally unreachable from this module.
11
+ *
12
+ * Output is labeled `[Estimate]` (`ESTIMATE_DISPLAY_TAG`) on every log
13
+ * line so consumers cannot conflate this with an LLM verdict; the
14
+ * verdict line and `SHIELD_FAILED` exit semantics are inherited from
15
+ * `runCompiledRules` unchanged so a passing estimate looks identical to
16
+ * a passing `totem lint` run on the metrics + trap-ledger surface.
17
+ *
18
+ * Empty-diff handling intentionally does NOT stamp the
19
+ * `.reviewed-content-hash` push-gate cache: an estimate is a forecast,
20
+ * not a passing review, and stamping the cache would let the push-gate
21
+ * unblock without ever running the LLM review.
22
+ */
23
+ export declare function runEstimate(options: ShieldOptions, config: TotemConfig, cwd: string, configRoot: string): Promise<void>;
24
+ //# sourceMappingURL=shield-estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-estimate.d.ts","sourceRoot":"","sources":["../../src/commands/shield-estimate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf"}
@@ -0,0 +1,55 @@
1
+ // totem-context: shield-templates is a pure constants + types module with no runtime logic; static import matches the established shield.ts:19 DISPLAY_TAG pattern and the lazy-import lint rule is a false positive here
2
+ import { ESTIMATE_DISPLAY_TAG } from './shield-templates.js';
3
+ /**
4
+ * Pre-flight deterministic-rule estimator for `totem review --estimate`
5
+ * (mmnto-ai/totem#1714). Runs the same compiled-rule engine as
6
+ * `totem lint` against the diff resolved by `totem review`'s standard
7
+ * resolution chain (explicit `--diff` → `--staged` → working-tree →
8
+ * branch-vs-base) and returns immediately. No orchestrator, no
9
+ * embedder, no LanceDB — the entire LLM Verification Layer is
10
+ * structurally unreachable from this module.
11
+ *
12
+ * Output is labeled `[Estimate]` (`ESTIMATE_DISPLAY_TAG`) on every log
13
+ * line so consumers cannot conflate this with an LLM verdict; the
14
+ * verdict line and `SHIELD_FAILED` exit semantics are inherited from
15
+ * `runCompiledRules` unchanged so a passing estimate looks identical to
16
+ * a passing `totem lint` run on the metrics + trap-ledger surface.
17
+ *
18
+ * Empty-diff handling intentionally does NOT stamp the
19
+ * `.reviewed-content-hash` push-gate cache: an estimate is a forecast,
20
+ * not a passing review, and stamping the cache would let the push-gate
21
+ * unblock without ever running the LLM review.
22
+ */
23
+ export async function runEstimate(options, config, cwd, configRoot) {
24
+ const { log } = await import('../ui.js');
25
+ const { getDiffForReview } = await import('../git.js');
26
+ const { runCompiledRules } = await import('./run-compiled-rules.js');
27
+ log.info(ESTIMATE_DISPLAY_TAG, 'Pre-flight prediction (deterministic, zero-LLM):');
28
+ const diffResult = await getDiffForReview(options, config, cwd, ESTIMATE_DISPLAY_TAG);
29
+ if (!diffResult) {
30
+ // Distinct from the `totem review` no-diff branch: the LLM path
31
+ // stamps the push-gate content hash because an empty diff is a
32
+ // trivial pass; an estimate is a forecast and explicitly does NOT
33
+ // stamp the cache. (Q2 in `.totem/specs/1714.md`.)
34
+ log.info(ESTIMATE_DISPLAY_TAG, 'No changes detected. Nothing to estimate.');
35
+ return;
36
+ }
37
+ await runCompiledRules({
38
+ diff: diffResult.diff,
39
+ cwd,
40
+ totemDir: config.totemDir,
41
+ format: 'text',
42
+ outPath: options.out,
43
+ ignorePatterns: config.ignorePatterns,
44
+ tag: ESTIMATE_DISPLAY_TAG,
45
+ configRoot,
46
+ // Source-of-truth for staged-mode is the resolved `DiffForReviewSource`,
47
+ // not the raw `options.staged` flag. `--diff` outranks `--staged` in
48
+ // `getDiffForReview` (mmnto-ai/totem#1717), so passing both flags must
49
+ // not cause `runCompiledRules` to use the staged-index read strategy
50
+ // when the diff actually came from an explicit range
51
+ // (mmnto-ai/totem#1732 CR R2).
52
+ isStaged: diffResult.source === 'staged',
53
+ });
54
+ }
55
+ //# sourceMappingURL=shield-estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-estimate.js","sourceRoot":"","sources":["../../src/commands/shield-estimate.ts"],"names":[],"mappings":"AAGA,0NAA0N;AAC1N,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAsB,EACtB,MAAmB,EACnB,GAAW,EACX,UAAkB;IAElB,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAErE,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,kDAAkD,CAAC,CAAC;IAEnF,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;IACtF,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,gEAAgE;QAChE,+DAA+D;QAC/D,kEAAkE;QAClE,mDAAmD;QACnD,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,2CAA2C,CAAC,CAAC;QAC5E,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,CAAC;QACrB,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,GAAG;QACH,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,OAAO,CAAC,GAAG;QACpB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,GAAG,EAAE,oBAAoB;QACzB,UAAU;QACV,yEAAyE;QACzE,qEAAqE;QACrE,uEAAuE;QACvE,qEAAqE;QACrE,qDAAqD;QACrD,+BAA+B;QAC/B,QAAQ,EAAE,UAAU,CAAC,MAAM,KAAK,QAAQ;KACzC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shield-estimate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-estimate.test.d.ts","sourceRoot":"","sources":["../../src/commands/shield-estimate.test.ts"],"names":[],"mappings":""}