@mmnto/cli 1.101.0 → 1.101.2

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 (72) hide show
  1. package/dist/commands/doctor-parity.d.ts.map +1 -1
  2. package/dist/commands/doctor-parity.js +11 -5
  3. package/dist/commands/doctor-parity.js.map +1 -1
  4. package/dist/commands/doctor.d.ts +36 -6
  5. package/dist/commands/doctor.d.ts.map +1 -1
  6. package/dist/commands/doctor.js +27 -0
  7. package/dist/commands/doctor.js.map +1 -1
  8. package/dist/commands/doctor.test.js +46 -1
  9. package/dist/commands/doctor.test.js.map +1 -1
  10. package/dist/commands/ecl-gc.d.ts.map +1 -1
  11. package/dist/commands/ecl-gc.js +16 -4
  12. package/dist/commands/ecl-gc.js.map +1 -1
  13. package/dist/commands/eject.d.ts +37 -2
  14. package/dist/commands/eject.d.ts.map +1 -1
  15. package/dist/commands/eject.js +79 -9
  16. package/dist/commands/eject.js.map +1 -1
  17. package/dist/commands/eject.test.js +169 -7
  18. package/dist/commands/eject.test.js.map +1 -1
  19. package/dist/commands/gate-install.test.js +22 -1
  20. package/dist/commands/gate-install.test.js.map +1 -1
  21. package/dist/commands/init-templates.js +8 -8
  22. package/dist/commands/install-hooks-exit-contract.test.js +171 -2
  23. package/dist/commands/install-hooks-exit-contract.test.js.map +1 -1
  24. package/dist/commands/install-hooks.d.ts +30 -0
  25. package/dist/commands/install-hooks.d.ts.map +1 -1
  26. package/dist/commands/install-hooks.js +151 -20
  27. package/dist/commands/install-hooks.js.map +1 -1
  28. package/dist/commands/mail-cli-wiring.test.d.ts +15 -0
  29. package/dist/commands/mail-cli-wiring.test.d.ts.map +1 -0
  30. package/dist/commands/mail-cli-wiring.test.js +106 -0
  31. package/dist/commands/mail-cli-wiring.test.js.map +1 -0
  32. package/dist/commands/mail.d.ts +80 -0
  33. package/dist/commands/mail.d.ts.map +1 -1
  34. package/dist/commands/mail.js +291 -19
  35. package/dist/commands/mail.js.map +1 -1
  36. package/dist/commands/mail.test.js +432 -4
  37. package/dist/commands/mail.test.js.map +1 -1
  38. package/dist/commands/shield-generated.d.ts +145 -0
  39. package/dist/commands/shield-generated.d.ts.map +1 -0
  40. package/dist/commands/shield-generated.js +266 -0
  41. package/dist/commands/shield-generated.js.map +1 -0
  42. package/dist/commands/shield-generated.test.d.ts +2 -0
  43. package/dist/commands/shield-generated.test.d.ts.map +1 -0
  44. package/dist/commands/shield-generated.test.js +323 -0
  45. package/dist/commands/shield-generated.test.js.map +1 -0
  46. package/dist/commands/shield.d.ts +2 -2
  47. package/dist/commands/shield.d.ts.map +1 -1
  48. package/dist/commands/shield.js +49 -4
  49. package/dist/commands/shield.js.map +1 -1
  50. package/dist/commands/shield.test.js +23 -0
  51. package/dist/commands/shield.test.js.map +1 -1
  52. package/dist/commands/status.d.ts.map +1 -1
  53. package/dist/commands/status.js +26 -2
  54. package/dist/commands/status.js.map +1 -1
  55. package/dist/commands/status.test.js +55 -1
  56. package/dist/commands/status.test.js.map +1 -1
  57. package/dist/index.js +28 -7
  58. package/dist/index.js.map +1 -1
  59. package/dist/parse-nits.d.ts +20 -3
  60. package/dist/parse-nits.d.ts.map +1 -1
  61. package/dist/parse-nits.js +111 -6
  62. package/dist/parse-nits.js.map +1 -1
  63. package/dist/parse-nits.test.js +141 -0
  64. package/dist/parse-nits.test.js.map +1 -1
  65. package/dist/parsers/bot-review-parser.d.ts.map +1 -1
  66. package/dist/parsers/bot-review-parser.js +12 -2
  67. package/dist/parsers/bot-review-parser.js.map +1 -1
  68. package/dist/utils.d.ts +1 -0
  69. package/dist/utils.d.ts.map +1 -1
  70. package/dist/utils.js +5 -0
  71. package/dist/utils.js.map +1 -1
  72. package/package.json +2 -2
@@ -0,0 +1,266 @@
1
+ import * as crypto from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ // Imported from the CLI's own `utils` re-export barrel (NOT '@mmnto/totem'
5
+ // directly) so this command module avoids a static top-level import of the
6
+ // heavy core barrel at startup (mmnto-ai/totem#2339).
7
+ import { matchesGlob, sanitize, wrapXml } from '../utils.js';
8
+ /**
9
+ * Generated-artifact exclusion for the review synthesis input (mmnto-ai/totem#2398).
10
+ *
11
+ * `totem review` used to send generated-artifact bytes (lockfiles,
12
+ * `compiled-rules.json`, `dist/**`, `*.wasm`, regenerated dashboards) to the LLM
13
+ * as part of the review diff. The only exclusion mechanism was `ignorePatterns`
14
+ * — opt-in, empty by default, and a **silent drop**: an excluded file simply
15
+ * vanished from the payload, losing the signal that it changed at all.
16
+ *
17
+ * This module classifies generated artifacts by default and replaces their
18
+ * bytes with a per-file SUMMARY (path, change shape, size delta, semantic hash)
19
+ * injected into the synthesis input. The reviewer keeps the "this regenerated"
20
+ * signal without paying review-context tokens for bytes no reviewer should read.
21
+ *
22
+ * Cautionary sibling #2329: the injected summary is CLEARLY LABELLED as a
23
+ * Totem-generated summarization artifact (a distinct XML tag + a preamble that
24
+ * says "not diff content") so the model cannot mistake it for real diff content
25
+ * the way secret-redaction's env-var rewriting was mistaken for a real read.
26
+ *
27
+ * Aligns with the Prop 297 taxonomy (GENERATED spans take regeneration-diff
28
+ * treatment, never prose review — mmnto-ai/totem-strategy#639 operating spec).
29
+ */
30
+ // ─── Default seeded globs ────────────────────────────────
31
+ /**
32
+ * The default generated-artifact classification for the review payload. Seeded
33
+ * globs covering the classes the issue names (lockfiles, `compiled-rules.json`,
34
+ * `dist/**`, `*.wasm`) plus the conventional build-output + compiled-web set.
35
+ *
36
+ * These globs use `matchesGlob` semantics (see `@mmnto/totem` `matchesGlob`):
37
+ * `**​/name` matches `name` at any depth, `**​/dir/**` matches a directory tree
38
+ * at any depth, `*.ext` matches an extension anywhere.
39
+ *
40
+ * A false positive here strips a real-code file from LLM review — but it is
41
+ * NEVER a silent drop: every excluded file is loudly named in the injected
42
+ * summary (path + hash), and a repo un-marks a false positive Git-natively via
43
+ * `.gitattributes` `linguist-generated=false` (honored below). Repos extend the
44
+ * set the same way (`path/to/thing linguist-generated`).
45
+ */
46
+ export const DEFAULT_GENERATED_ARTIFACT_GLOBS = [
47
+ // Dependency lockfiles — machine-regenerated, never meaningfully hand-authored.
48
+ '**/package-lock.json',
49
+ '**/pnpm-lock.yaml',
50
+ '**/yarn.lock',
51
+ '**/npm-shrinkwrap.json',
52
+ '**/bun.lockb',
53
+ '**/Cargo.lock',
54
+ '**/poetry.lock',
55
+ '**/composer.lock',
56
+ '**/Gemfile.lock',
57
+ '**/go.sum',
58
+ '**/flake.lock',
59
+ // Totem compiled artifacts (issue-named).
60
+ '**/.totem/compiled-rules.json',
61
+ '**/.totem/compile-manifest.json',
62
+ // Conventional build-output directories.
63
+ '**/dist/**',
64
+ '**/build/**',
65
+ '**/out/**',
66
+ '**/.next/**',
67
+ '**/coverage/**',
68
+ // Compiled / minified / binary web + WASM artifacts (issue-named `*.wasm`).
69
+ '**/*.wasm',
70
+ '**/*.min.js',
71
+ '**/*.min.css',
72
+ '**/*.map',
73
+ '**/*.tsbuildinfo',
74
+ ];
75
+ // ─── .gitattributes linguist-generated ──────────────────
76
+ /** Cap on the `.gitattributes` bytes read — a defensive bound, real files are tiny. */
77
+ const MAX_GITATTRIBUTES_BYTES = 256 * 1024;
78
+ /**
79
+ * Translate a `.gitattributes` path pattern into a `matchesGlob`-compatible glob.
80
+ *
81
+ * Full gitattributes/gitignore pattern fidelity is out of scope; this covers the
82
+ * common forms the classification cares about:
83
+ * - a leading `/` (root-anchored) is stripped — `matchesGlob` treats a
84
+ * slash-bearing literal as repo-root-relative already;
85
+ * - a trailing `/` (directory) becomes `<dir>/**` so the tree is matched;
86
+ * - bare patterns (`*.lock`, `foo.map`) pass through — `matchesGlob` already
87
+ * matches those at any depth.
88
+ */
89
+ export function gitattributesPatternToGlob(pattern) {
90
+ let p = pattern.trim();
91
+ if (p.startsWith('/'))
92
+ p = p.slice(1);
93
+ if (p.endsWith('/'))
94
+ p = `${p}**`;
95
+ return p;
96
+ }
97
+ /**
98
+ * Parse `.gitattributes` at the repo root for `linguist-generated` markers.
99
+ * Returns empty pattern lists when the file is absent or unreadable (best-effort
100
+ * enrichment — a missing `.gitattributes` is never an error). Comment lines
101
+ * (`#…`) and macro lines (`[attr]…`) are ignored.
102
+ */
103
+ export function readGitattributesGeneratedPatterns(cwd) {
104
+ const generated = [];
105
+ const notGenerated = [];
106
+ const file = path.join(cwd, '.gitattributes');
107
+ let raw;
108
+ try {
109
+ const stat = fs.statSync(file);
110
+ if (!stat.isFile() || stat.size > MAX_GITATTRIBUTES_BYTES) {
111
+ return { generated, notGenerated };
112
+ }
113
+ raw = fs.readFileSync(file, 'utf-8');
114
+ // totem-context: intentional cleanup — an absent / unreadable .gitattributes is honest-absent (the seeded default globs still apply); this best-effort enrichment read must never crash the review, so degrading to "no repo-declared patterns" is correct, not a swallowed error (mmnto-ai/totem#2398).
115
+ }
116
+ catch {
117
+ return { generated, notGenerated };
118
+ }
119
+ for (const line of raw.split(/\r?\n/)) {
120
+ const trimmed = line.trim();
121
+ if (trimmed.length === 0 || trimmed.startsWith('#') || trimmed.startsWith('['))
122
+ continue;
123
+ // A gitattributes line is `<pattern> <attr> <attr> …`. Split on whitespace;
124
+ // the first token is the pattern, the rest are attributes.
125
+ const tokens = trimmed.split(/\s+/);
126
+ const pattern = tokens[0];
127
+ if (pattern === undefined || pattern.length === 0)
128
+ continue;
129
+ const attrs = tokens.slice(1);
130
+ for (const attr of attrs) {
131
+ if (attr === 'linguist-generated' || attr === 'linguist-generated=true') {
132
+ generated.push(gitattributesPatternToGlob(pattern));
133
+ }
134
+ else if (attr === '-linguist-generated' || attr === 'linguist-generated=false') {
135
+ // `-attr` and `attr=false` both UNSET the attribute in git's model.
136
+ notGenerated.push(gitattributesPatternToGlob(pattern));
137
+ }
138
+ }
139
+ }
140
+ return { generated, notGenerated };
141
+ }
142
+ /**
143
+ * Split a unified diff into per-file sections at `diff --git` boundaries and
144
+ * extract each section's destination (`b/`) path. Mirrors the split + path
145
+ * extraction that `filterDiffByPatterns` / `extractChangedFiles` use so the two
146
+ * agree on file identity. Joining `section` values back reconstructs the input
147
+ * exactly (the zero-width split consumes no characters).
148
+ */
149
+ export function splitDiffIntoFileSections(diff) {
150
+ const rawSections = diff.split(/^(?=diff --git )/m);
151
+ return rawSections
152
+ .filter((section) => section.length > 0)
153
+ .map((section) => {
154
+ // A section with no newline at all (a truncated diff tail) must use the
155
+ // WHOLE section as its first line — indexOf's -1 would otherwise slice
156
+ // off the final character and break the $-anchored filename match (GCA
157
+ // round on #2443).
158
+ const newlineIdx = section.indexOf('\n');
159
+ const firstLine = newlineIdx === -1 ? section : section.slice(0, newlineIdx);
160
+ const quoted = firstLine.match(/^diff --git "a\/.*?" "b\/(.*?)"$/);
161
+ const unquoted = firstLine.match(/^diff --git a\/\S+ b\/(.+)$/);
162
+ const file = quoted?.[1] ?? unquoted?.[1] ?? null;
163
+ return { file, section };
164
+ });
165
+ }
166
+ /** Semantic hash of an excluded artifact's diff segment: sha256, first 12 hex chars. */
167
+ export function hashDiffSection(section) {
168
+ return crypto.createHash('sha256').update(section, 'utf-8').digest('hex').slice(0, 12);
169
+ }
170
+ /** Summarize one generated-artifact diff section (shape + size delta + hash). */
171
+ function summarizeSection(file, section) {
172
+ const shape = /^new file mode /m.test(section)
173
+ ? 'added'
174
+ : /^deleted file mode /m.test(section)
175
+ ? 'deleted'
176
+ : 'regenerated';
177
+ const binary = /^Binary files /m.test(section) || /^GIT binary patch/m.test(section);
178
+ let addedLines = 0;
179
+ let removedLines = 0;
180
+ if (!binary) {
181
+ for (const line of section.split('\n')) {
182
+ // Skip the `+++ `/`--- ` file-header lines (always a space or /dev/null
183
+ // after the triple marker); a bare `+++`/`---` prefix check would also
184
+ // swallow real hunk content like `++i;` → `+++i;` (GCA round on #2443).
185
+ if (line.startsWith('+') && !line.startsWith('+++ '))
186
+ addedLines++;
187
+ else if (line.startsWith('-') && !line.startsWith('--- '))
188
+ removedLines++;
189
+ }
190
+ }
191
+ return { file, shape, addedLines, removedLines, binary, hash: hashDiffSection(section) };
192
+ }
193
+ /**
194
+ * Classify the changed files into generated artifacts vs. kept files, remove the
195
+ * artifact sections from the diff, and build a per-file summary of each excluded
196
+ * artifact. A file is a generated artifact iff it matches ANY positive glob AND
197
+ * matches NO un-mark (exclude) glob.
198
+ *
199
+ * When no artifact matches, `keptDiff === diff` and `keptFiles === changedFiles`
200
+ * (order preserved) — the legacy review payload is byte-identical, so callers
201
+ * can gate the new path on `summaries.length > 0`.
202
+ */
203
+ export function classifyGeneratedArtifacts(params) {
204
+ const generatedGlobs = params.generatedGlobs ?? DEFAULT_GENERATED_ARTIFACT_GLOBS;
205
+ const excludeGlobs = params.excludeGlobs ?? [];
206
+ const isGenerated = (file) => generatedGlobs.some((g) => matchesGlob(file, g)) &&
207
+ !excludeGlobs.some((g) => matchesGlob(file, g));
208
+ const artifactSet = new Set();
209
+ const summaries = [];
210
+ const keptSections = [];
211
+ for (const { file, section } of splitDiffIntoFileSections(params.diff)) {
212
+ if (file !== null && isGenerated(file)) {
213
+ artifactSet.add(file);
214
+ summaries.push(summarizeSection(file, section));
215
+ }
216
+ else {
217
+ keptSections.push(section);
218
+ }
219
+ }
220
+ // Derive kept files from the ORIGINAL changedFiles (preserves order + covers
221
+ // any file the diff-section parse might miss), subtracting the classified set.
222
+ const keptFiles = params.changedFiles.filter((f) => !artifactSet.has(f));
223
+ return {
224
+ artifactFiles: [...artifactSet],
225
+ summaries,
226
+ keptDiff: keptSections.join(''), // totem-ignore (#669) — joining diff sections, not text fragments
227
+ keptFiles,
228
+ };
229
+ }
230
+ // ─── Summary rendering ───────────────────────────────────
231
+ const SHAPE_LABEL = {
232
+ added: 'added',
233
+ deleted: 'deleted',
234
+ regenerated: 'regenerated',
235
+ };
236
+ /** One operator-visible / prompt line for an excluded artifact. Paths are sanitized. */
237
+ export function formatGeneratedArtifactLine(summary) {
238
+ const delta = summary.binary ? 'binary' : `+${summary.addedLines}/-${summary.removedLines} lines`;
239
+ return `- ${sanitize(summary.file)} — ${SHAPE_LABEL[summary.shape]}, ${delta}, hash ${summary.hash}`;
240
+ }
241
+ /**
242
+ * Build the synthesis-input section for the excluded generated artifacts.
243
+ * Returns `''` when there are no artifacts (so the caller injects nothing on the
244
+ * legacy path). The body is wrapped in a distinct XML tag and the preamble
245
+ * states plainly that these lines are a Totem-generated summary, NOT diff
246
+ * content — the #2329 mislabel guard.
247
+ */
248
+ export function buildGeneratedArtifactSection(summaries) {
249
+ if (summaries.length === 0)
250
+ return '';
251
+ const lines = summaries.map(formatGeneratedArtifactLine).join('\n');
252
+ const preamble = 'The files below changed but their BYTES WERE EXCLUDED from this review because ' +
253
+ 'they are generated artifacts (lockfiles, compiled outputs, build products). ' +
254
+ 'This block is a TOTEM-GENERATED SUMMARY, not diff content — do NOT treat these ' +
255
+ 'lines as code under review, and do NOT emit findings about them. Their ' +
256
+ 'correctness is the job of deterministic regeneration gates (e.g. `totem lint`, ' +
257
+ 'lockfile-sync), not prose review. Each line is: path — change shape, size ' +
258
+ 'delta (unified-diff insert/delete counts), semantic hash (sha256/12 of the ' +
259
+ "excluded file's diff segment).";
260
+ return [
261
+ '\n=== EXCLUDED GENERATED ARTIFACTS (TOTEM SUMMARY — NOT DIFF CONTENT) ===',
262
+ preamble,
263
+ wrapXml('generated_artifacts_summary', lines),
264
+ ].join('\n');
265
+ }
266
+ //# sourceMappingURL=shield-generated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-generated.js","sourceRoot":"","sources":["../../src/commands/shield-generated.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shield-generated.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-generated.test.d.ts","sourceRoot":"","sources":["../../src/commands/shield-generated.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,323 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { cleanTmpDir } from '../test-utils.js';
6
+ import { buildGeneratedArtifactSection, classifyGeneratedArtifacts, DEFAULT_GENERATED_ARTIFACT_GLOBS, formatGeneratedArtifactLine, gitattributesPatternToGlob, hashDiffSection, readGitattributesGeneratedPatterns, splitDiffIntoFileSections, } from './shield-generated.js';
7
+ // ─── Diff builders ──────────────────────────────────────
8
+ /** A minimal modified-file (regenerated) diff section. */
9
+ function modifiedSection(file, added = 1, removed = 1) {
10
+ const plus = Array.from({ length: added }, (_, i) => `+added-${i}`).join('\n');
11
+ const minus = Array.from({ length: removed }, (_, i) => `-removed-${i}`).join('\n');
12
+ return [
13
+ `diff --git a/${file} b/${file}`,
14
+ `index 1111111..2222222 100644`,
15
+ `--- a/${file}`,
16
+ `+++ b/${file}`,
17
+ `@@ -1,${removed} +1,${added} @@`,
18
+ minus,
19
+ plus,
20
+ '',
21
+ ].join('\n');
22
+ }
23
+ function addedSection(file) {
24
+ return [
25
+ `diff --git a/${file} b/${file}`,
26
+ `new file mode 100644`,
27
+ `index 0000000..3333333`,
28
+ `--- /dev/null`,
29
+ `+++ b/${file}`,
30
+ `@@ -0,0 +1,2 @@`,
31
+ `+line one`,
32
+ `+line two`,
33
+ '',
34
+ ].join('\n');
35
+ }
36
+ function deletedSection(file) {
37
+ return [
38
+ `diff --git a/${file} b/${file}`,
39
+ `deleted file mode 100644`,
40
+ `index 4444444..0000000`,
41
+ `--- a/${file}`,
42
+ `+++ /dev/null`,
43
+ `@@ -1,1 +0,0 @@`,
44
+ `-only line`,
45
+ '',
46
+ ].join('\n');
47
+ }
48
+ function binarySection(file) {
49
+ return [
50
+ `diff --git a/${file} b/${file}`,
51
+ `index 5555555..6666666 100644`,
52
+ `Binary files a/${file} and b/${file} differ`,
53
+ '',
54
+ ].join('\n');
55
+ }
56
+ // ─── splitDiffIntoFileSections ──────────────────────────
57
+ describe('splitDiffIntoFileSections', () => {
58
+ it('reconstructs the input exactly when sections are joined', () => {
59
+ const diff = modifiedSection('src/a.ts') + modifiedSection('src/b.ts');
60
+ const sections = splitDiffIntoFileSections(diff);
61
+ expect(sections.map((s) => s.section).join('')).toBe(diff);
62
+ });
63
+ it('extracts the destination path of each section', () => {
64
+ const diff = modifiedSection('src/a.ts') + addedSection('dist/out.js');
65
+ const sections = splitDiffIntoFileSections(diff);
66
+ expect(sections.map((s) => s.file)).toEqual(['src/a.ts', 'dist/out.js']);
67
+ });
68
+ it('handles quoted (spaced) paths', () => {
69
+ const diff = [
70
+ 'diff --git "a/my file.ts" "b/my file.ts"',
71
+ '--- "a/my file.ts"',
72
+ '+++ "b/my file.ts"',
73
+ '@@ -1 +1 @@',
74
+ '-a',
75
+ '+b',
76
+ '',
77
+ ].join('\n');
78
+ const sections = splitDiffIntoFileSections(diff);
79
+ expect(sections[0]?.file).toBe('my file.ts');
80
+ });
81
+ it('returns an empty array for an empty diff', () => {
82
+ expect(splitDiffIntoFileSections('')).toEqual([]);
83
+ });
84
+ it('parses a newline-less section (truncated diff tail) without truncating the filename', () => {
85
+ // GCA round on #2443: indexOf('\n') === -1 previously fed slice(0, -1),
86
+ // chopping the final character and breaking the $-anchored path match.
87
+ const sections = splitDiffIntoFileSections('diff --git a/dist/out.js b/dist/out.js');
88
+ expect(sections).toHaveLength(1);
89
+ expect(sections[0]?.file).toBe('dist/out.js');
90
+ });
91
+ });
92
+ // ─── hashDiffSection ────────────────────────────────────
93
+ describe('hashDiffSection', () => {
94
+ it('is deterministic and 12 hex chars', () => {
95
+ const section = modifiedSection('pnpm-lock.yaml');
96
+ const h1 = hashDiffSection(section);
97
+ const h2 = hashDiffSection(section);
98
+ expect(h1).toBe(h2);
99
+ expect(h1).toMatch(/^[0-9a-f]{12}$/);
100
+ });
101
+ it('differs when the section content differs', () => {
102
+ expect(hashDiffSection(modifiedSection('a', 1, 1))).not.toBe(hashDiffSection(modifiedSection('a', 2, 1)));
103
+ });
104
+ });
105
+ // ─── classifyGeneratedArtifacts ─────────────────────────
106
+ describe('classifyGeneratedArtifacts', () => {
107
+ it('leaves the diff and files byte-identical when nothing matches', () => {
108
+ const diff = modifiedSection('src/foo.ts') + modifiedSection('src/bar.ts');
109
+ const changedFiles = ['src/foo.ts', 'src/bar.ts'];
110
+ const result = classifyGeneratedArtifacts({ diff, changedFiles });
111
+ expect(result.keptDiff).toBe(diff);
112
+ expect(result.keptFiles).toEqual(changedFiles);
113
+ expect(result.artifactFiles).toEqual([]);
114
+ expect(result.summaries).toEqual([]);
115
+ });
116
+ it('classifies a lockfile, strips its bytes, and keeps a summary', () => {
117
+ const diff = modifiedSection('pnpm-lock.yaml', 42, 13) + modifiedSection('src/foo.ts');
118
+ const changedFiles = ['pnpm-lock.yaml', 'src/foo.ts'];
119
+ const result = classifyGeneratedArtifacts({ diff, changedFiles });
120
+ expect(result.artifactFiles).toEqual(['pnpm-lock.yaml']);
121
+ expect(result.keptFiles).toEqual(['src/foo.ts']);
122
+ // The lockfile bytes are gone from the kept diff; the code file remains.
123
+ expect(result.keptDiff).not.toContain('pnpm-lock.yaml');
124
+ expect(result.keptDiff).toContain('src/foo.ts');
125
+ const summary = result.summaries[0];
126
+ expect(summary?.file).toBe('pnpm-lock.yaml');
127
+ expect(summary?.shape).toBe('regenerated');
128
+ expect(summary?.addedLines).toBe(42);
129
+ expect(summary?.removedLines).toBe(13);
130
+ expect(summary?.binary).toBe(false);
131
+ expect(summary?.hash).toMatch(/^[0-9a-f]{12}$/);
132
+ });
133
+ it('classifies nested build output (**/dist/**) and *.wasm and compiled-rules.json', () => {
134
+ const files = [
135
+ 'packages/cli/dist/index.js',
136
+ 'src/pkg.wasm',
137
+ '.totem/compiled-rules.json',
138
+ 'src/keep.ts',
139
+ ];
140
+ const diff = files.map((f) => modifiedSection(f)).join('');
141
+ const result = classifyGeneratedArtifacts({ diff, changedFiles: files });
142
+ expect(result.artifactFiles.sort()).toEqual(['.totem/compiled-rules.json', 'packages/cli/dist/index.js', 'src/pkg.wasm'].sort());
143
+ expect(result.keptFiles).toEqual(['src/keep.ts']);
144
+ });
145
+ it('detects added / deleted / regenerated change shapes', () => {
146
+ const diff = addedSection('dist/new.js') + deletedSection('dist/old.js') + modifiedSection('dist/mod.js');
147
+ const changedFiles = ['dist/new.js', 'dist/old.js', 'dist/mod.js'];
148
+ const result = classifyGeneratedArtifacts({ diff, changedFiles });
149
+ const byFile = Object.fromEntries(result.summaries.map((s) => [s.file, s.shape]));
150
+ expect(byFile['dist/new.js']).toBe('added');
151
+ expect(byFile['dist/old.js']).toBe('deleted');
152
+ expect(byFile['dist/mod.js']).toBe('regenerated');
153
+ });
154
+ it('counts hunk content beginning with ++/-- (e.g. `+++i;`) and still skips the `+++ `/`--- ` headers', () => {
155
+ // GCA round on #2443: a bare `+++` prefix check swallowed real added lines
156
+ // like C's `++i;` (rendered `+++i;` in a hunk). Headers always carry a
157
+ // space (`+++ b/...`, `+++ /dev/null`) — that is the discriminator.
158
+ const section = [
159
+ 'diff --git a/dist/gen.c b/dist/gen.c',
160
+ 'index 1111111..2222222 100644',
161
+ '--- a/dist/gen.c',
162
+ '+++ b/dist/gen.c',
163
+ '@@ -1,2 +1,2 @@',
164
+ '---x;',
165
+ '+++i;',
166
+ '',
167
+ ].join('\n');
168
+ const result = classifyGeneratedArtifacts({
169
+ diff: section,
170
+ changedFiles: ['dist/gen.c'],
171
+ generatedGlobs: [...DEFAULT_GENERATED_ARTIFACT_GLOBS],
172
+ excludeGlobs: [],
173
+ });
174
+ expect(result.summaries).toHaveLength(1);
175
+ expect(result.summaries[0]?.addedLines).toBe(1);
176
+ expect(result.summaries[0]?.removedLines).toBe(1);
177
+ });
178
+ it('marks a binary artifact and reports no line counts', () => {
179
+ const diff = binarySection('src/pkg.wasm');
180
+ const result = classifyGeneratedArtifacts({ diff, changedFiles: ['src/pkg.wasm'] });
181
+ const summary = result.summaries[0];
182
+ expect(summary?.binary).toBe(true);
183
+ expect(summary?.addedLines).toBe(0);
184
+ expect(summary?.removedLines).toBe(0);
185
+ });
186
+ it('honors an un-mark (exclude) glob — a matched default is NOT generated', () => {
187
+ const diff = modifiedSection('pnpm-lock.yaml');
188
+ const result = classifyGeneratedArtifacts({
189
+ diff,
190
+ changedFiles: ['pnpm-lock.yaml'],
191
+ excludeGlobs: ['**/pnpm-lock.yaml'],
192
+ });
193
+ expect(result.artifactFiles).toEqual([]);
194
+ expect(result.keptDiff).toBe(diff);
195
+ });
196
+ it('honors an added generated glob passed by the caller', () => {
197
+ const diff = modifiedSection('dashboards/report.html');
198
+ const result = classifyGeneratedArtifacts({
199
+ diff,
200
+ changedFiles: ['dashboards/report.html'],
201
+ generatedGlobs: [...DEFAULT_GENERATED_ARTIFACT_GLOBS, '**/dashboards/**'],
202
+ });
203
+ expect(result.artifactFiles).toEqual(['dashboards/report.html']);
204
+ });
205
+ it('produces an all-generated (empty kept diff) result', () => {
206
+ const diff = modifiedSection('pnpm-lock.yaml') + modifiedSection('yarn.lock');
207
+ const result = classifyGeneratedArtifacts({
208
+ diff,
209
+ changedFiles: ['pnpm-lock.yaml', 'yarn.lock'],
210
+ });
211
+ expect(result.keptDiff.trim()).toBe('');
212
+ expect(result.keptFiles).toEqual([]);
213
+ expect(result.summaries).toHaveLength(2);
214
+ });
215
+ });
216
+ // ─── gitattributesPatternToGlob ─────────────────────────
217
+ describe('gitattributesPatternToGlob', () => {
218
+ it('strips a leading root-anchor slash', () => {
219
+ expect(gitattributesPatternToGlob('/dist/bundle.js')).toBe('dist/bundle.js');
220
+ });
221
+ it('expands a trailing directory slash to a recursive glob', () => {
222
+ expect(gitattributesPatternToGlob('generated/')).toBe('generated/**');
223
+ });
224
+ it('passes a bare extension pattern through unchanged', () => {
225
+ expect(gitattributesPatternToGlob('*.lock')).toBe('*.lock');
226
+ });
227
+ });
228
+ // ─── readGitattributesGeneratedPatterns ─────────────────
229
+ describe('readGitattributesGeneratedPatterns', () => {
230
+ let dir;
231
+ afterEach(() => {
232
+ cleanTmpDir(dir);
233
+ dir = undefined;
234
+ });
235
+ it('returns empty pattern lists when .gitattributes is absent', () => {
236
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-gitattr-'));
237
+ expect(readGitattributesGeneratedPatterns(dir)).toEqual({ generated: [], notGenerated: [] });
238
+ });
239
+ it('parses generated (true) and un-mark (false) markers, skipping comments', () => {
240
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-gitattr-'));
241
+ fs.writeFileSync(path.join(dir, '.gitattributes'), [
242
+ '# a comment',
243
+ 'dashboards/** linguist-generated',
244
+ 'src/vendor.js linguist-generated=true',
245
+ 'src/hand-written.min.js linguist-generated=false',
246
+ 'legacy/build.js -linguist-generated',
247
+ '*.ts text',
248
+ '',
249
+ ].join('\n'), 'utf-8');
250
+ const result = readGitattributesGeneratedPatterns(dir);
251
+ expect(result.generated).toContain('dashboards/**');
252
+ expect(result.generated).toContain('src/vendor.js');
253
+ expect(result.notGenerated).toContain('src/hand-written.min.js');
254
+ expect(result.notGenerated).toContain('legacy/build.js');
255
+ // A non-generated attribute line contributes nothing.
256
+ expect(result.generated).not.toContain('*.ts');
257
+ });
258
+ it('wires .gitattributes patterns end-to-end through classification', () => {
259
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-gitattr-'));
260
+ fs.writeFileSync(path.join(dir, '.gitattributes'),
261
+ // Un-mark a default match AND add a repo-specific generated dir.
262
+ ['**/pnpm-lock.yaml linguist-generated=false', 'dashboards/ linguist-generated', ''].join('\n'), 'utf-8');
263
+ const gitattr = readGitattributesGeneratedPatterns(dir);
264
+ const diff = modifiedSection('pnpm-lock.yaml') + modifiedSection('dashboards/x.html');
265
+ const result = classifyGeneratedArtifacts({
266
+ diff,
267
+ changedFiles: ['pnpm-lock.yaml', 'dashboards/x.html'],
268
+ generatedGlobs: [...DEFAULT_GENERATED_ARTIFACT_GLOBS, ...gitattr.generated],
269
+ excludeGlobs: gitattr.notGenerated,
270
+ });
271
+ // pnpm-lock.yaml un-marked → kept; dashboards/ added → excluded.
272
+ expect(result.keptFiles).toContain('pnpm-lock.yaml');
273
+ expect(result.artifactFiles).toEqual(['dashboards/x.html']);
274
+ });
275
+ });
276
+ // ─── rendering ──────────────────────────────────────────
277
+ describe('formatGeneratedArtifactLine', () => {
278
+ it('renders shape, size delta, and hash', () => {
279
+ const line = formatGeneratedArtifactLine({
280
+ file: 'pnpm-lock.yaml',
281
+ shape: 'regenerated',
282
+ addedLines: 42,
283
+ removedLines: 13,
284
+ binary: false,
285
+ hash: 'abcdef012345',
286
+ });
287
+ expect(line).toBe('- pnpm-lock.yaml — regenerated, +42/-13 lines, hash abcdef012345');
288
+ });
289
+ it('renders "binary" instead of line counts for a binary artifact', () => {
290
+ const line = formatGeneratedArtifactLine({
291
+ file: 'src/pkg.wasm',
292
+ shape: 'regenerated',
293
+ addedLines: 0,
294
+ removedLines: 0,
295
+ binary: true,
296
+ hash: 'abcdef012345',
297
+ });
298
+ expect(line).toContain('binary');
299
+ expect(line).not.toContain('lines');
300
+ });
301
+ });
302
+ describe('buildGeneratedArtifactSection', () => {
303
+ it('returns an empty string when there are no artifacts', () => {
304
+ expect(buildGeneratedArtifactSection([])).toBe('');
305
+ });
306
+ it('labels the block as a summary, not diff content (#2329 guard)', () => {
307
+ const section = buildGeneratedArtifactSection([
308
+ {
309
+ file: 'pnpm-lock.yaml',
310
+ shape: 'regenerated',
311
+ addedLines: 1,
312
+ removedLines: 1,
313
+ binary: false,
314
+ hash: 'abcdef012345',
315
+ },
316
+ ]);
317
+ expect(section).toContain('EXCLUDED GENERATED ARTIFACTS');
318
+ expect(section).toContain('NOT DIFF CONTENT');
319
+ expect(section).toContain('<generated_artifacts_summary>');
320
+ expect(section).toContain('- pnpm-lock.yaml — regenerated');
321
+ });
322
+ });
323
+ //# sourceMappingURL=shield-generated.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-generated.test.js","sourceRoot":"","sources":["../../src/commands/shield-generated.test.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,8 @@ interface RetrievedContext {
9
9
  lessons: SearchResult[];
10
10
  }
11
11
  export declare function buildFileContext(changedFiles: string[], cwd: string, maxLines: number, maxChars: number): Promise<string>;
12
- export declare function assemblePrompt(diff: string, changedFiles: string[], context: RetrievedContext, systemPrompt: string, smartHints?: string[], fileContext?: string): string;
13
- export declare function assembleStructuralPrompt(diff: string, changedFiles: string[], systemPrompt: string, smartHints?: string[], fileContext?: string): string;
12
+ export declare function assemblePrompt(diff: string, changedFiles: string[], context: RetrievedContext, systemPrompt: string, smartHints?: string[], fileContext?: string, generatedArtifactSummary?: string): string;
13
+ export declare function assembleStructuralPrompt(diff: string, changedFiles: string[], systemPrompt: string, smartHints?: string[], fileContext?: string, generatedArtifactSummary?: string): string;
14
14
  export declare function parseVerdict(content: string): {
15
15
  pass: boolean;
16
16
  reason: string;