From 9123ae2bb09a83c7abbd1f04fee6f360b9c5d9c4 Mon Sep 17 00:00:00 2001 From: garrytan Date: Tue, 3 Nov 2026 19:02:11 +0000 Subject: [PATCH] review-brief: sliceDiff splits and names git-quoted and spaced filenames (GSTA-258 L7 Addendum 1.2) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- lib/review-brief.ts | 11 +++++++++-- test/review-depth-lean.test.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/review-brief.ts b/lib/review-brief.ts index 698715c1d..aadc15e36 100644 --- a/lib/review-brief.ts +++ b/lib/review-brief.ts @@ -43,14 +43,21 @@ export class BriefError extends Error {} */ export function sliceDiff(text: string, cap: number): { text: string; sliced: boolean; files: number; kept: number; bytes: number; total: number; left: string[] } { const total = Buffer.byteLength(text); - const starts = [...text.matchAll(/^diff --git a\/(\S+)/gm)]; + const starts = [...text.matchAll(/^diff --git (.*)$/gm)]; + const name = (rest: string) => { + const quoted = /^"a\/((?:[^"\\]|\\.)*)"/.exec(rest); + if (quoted) return `"${quoted[1]}"`; + const half = (rest.length - 1) / 2; + if (rest.startsWith('a/') && rest.slice(half) === ` b/${rest.slice(2, half)}`) return rest.slice(2, half); + return rest.startsWith('a/') ? rest.slice(2).split(' b/')[0]! : rest; + }; if (total <= cap || !starts.length) return { text, sliced: false, files: starts.length, kept: starts.length, bytes: total, total, left: [] }; let out = '', bytes = 0; const left: string[] = []; starts.forEach((m, k) => { const section = text.slice(m.index!, k + 1 < starts.length ? starts[k + 1]!.index! : text.length); const n = Buffer.byteLength(section); - if (bytes + n <= cap) { out += section; bytes += n; } else left.push(m[1]!); + if (bytes + n <= cap) { out += section; bytes += n; } else left.push(name(m[1]!)); }); return { text: out, sliced: true, files: starts.length, kept: starts.length - left.length, bytes, total, left }; } diff --git a/test/review-depth-lean.test.ts b/test/review-depth-lean.test.ts index 760fb0971..2859f6738 100644 --- a/test/review-depth-lean.test.ts +++ b/test/review-depth-lean.test.ts @@ -232,6 +232,17 @@ describe('C7 merged reader brief and the outside voice reading its diff from dis expect(sliceNote(s, 100)).toMatch(/2 of 3 files.*big\.json/); expect(sliceDiff(sec('a.ts', 10), 100).sliced).toBe(false); }); + // Value: protects=no file leaves the outside voice's slice unnamed (GSTA-258 L7 Addendum 1.2); fails_when=a git-quoted header + // before the first plain one is dropped unlisted, or glued onto the file before it; seam=sliceDiff headers + test('a git-quoted or spaced filename is its own file in the slice and is named when left out', () => { + const quoted = (p: string, n: number) => `diff --git "a/${p}" "b/${p}"\n+${'x'.repeat(n)}\n`; + const sec = (p: string, n: number) => `diff --git a/${p} b/${p}\n+${'x'.repeat(n)}\n`; + const s = sliceDiff(quoted('t\\303\\251st.sql', 500) + sec('a.ts', 10) + quoted('tab\\there.ts', 10), 100); + expect([s.files, s.kept, s.left]).toEqual([3, 2, ['"t\\303\\251st.sql"']]); + expect(s.text).toContain('tab\\there.ts'); + const spaced = sliceDiff(sec('my notes/big data.csv', 500) + sec('a.ts', 10), 100); + expect(spaced.left).toEqual(['my notes/big data.csv']); + }); test('the outside voice gets a path and a hash, not the pasted diff', () => { const text = renderBrief('outside-voice', { diff_base: sha, diff_file: '/tmp/o/outside-voice.diff', diff_sha256: 'd'.repeat(64), diff_bytes: '1234' }, t); expect(text).toContain('/tmp/o/outside-voice.diff');