@tienne/gestalt 0.83.2 → 0.84.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.
Files changed (142) hide show
  1. package/CLAUDE.md +2 -2
  2. package/README.ko.md +3 -1
  3. package/README.md +3 -1
  4. package/dist/package.json +1 -1
  5. package/dist/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
  6. package/dist/plugin/role-agents/_shared/references/comment-rules.md +1 -1
  7. package/dist/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
  8. package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
  9. package/dist/plugin/skills/_shared/rule-sources.md +1 -1
  10. package/dist/plugin/skills/agent/SKILL.md +2 -0
  11. package/dist/plugin/skills/review/SKILL.md +343 -7
  12. package/dist/plugin/skills/review-loop/SKILL.md +124 -2
  13. package/dist/plugin/skills/ship/SKILL.md +40 -1
  14. package/dist/schemas/gestalt.schema.json +12 -0
  15. package/dist/src/cli/commands/approve-gate.d.ts +24 -0
  16. package/dist/src/cli/commands/approve-gate.d.ts.map +1 -0
  17. package/dist/src/cli/commands/approve-gate.js +90 -0
  18. package/dist/src/cli/commands/approve-gate.js.map +1 -0
  19. package/dist/src/cli/commands/harness-refs-cross-pr.d.ts +218 -0
  20. package/dist/src/cli/commands/harness-refs-cross-pr.d.ts.map +1 -0
  21. package/dist/src/cli/commands/harness-refs-cross-pr.js +934 -0
  22. package/dist/src/cli/commands/harness-refs-cross-pr.js.map +1 -0
  23. package/dist/src/cli/commands/harness-refs.d.ts +19 -0
  24. package/dist/src/cli/commands/harness-refs.d.ts.map +1 -0
  25. package/dist/src/cli/commands/harness-refs.js +51 -0
  26. package/dist/src/cli/commands/harness-refs.js.map +1 -0
  27. package/dist/src/cli/index.d.ts.map +1 -1
  28. package/dist/src/cli/index.js +97 -0
  29. package/dist/src/cli/index.js.map +1 -1
  30. package/dist/src/core/config.d.ts +3 -0
  31. package/dist/src/core/config.d.ts.map +1 -1
  32. package/dist/src/core/config.js +23 -0
  33. package/dist/src/core/config.js.map +1 -1
  34. package/dist/src/core/types.d.ts +2 -0
  35. package/dist/src/core/types.d.ts.map +1 -1
  36. package/dist/src/harness-review/approve-gate.d.ts +53 -0
  37. package/dist/src/harness-review/approve-gate.d.ts.map +1 -0
  38. package/dist/src/harness-review/approve-gate.js +148 -0
  39. package/dist/src/harness-review/approve-gate.js.map +1 -0
  40. package/dist/src/harness-review/backward-search.d.ts +50 -0
  41. package/dist/src/harness-review/backward-search.d.ts.map +1 -0
  42. package/dist/src/harness-review/backward-search.js +183 -0
  43. package/dist/src/harness-review/backward-search.js.map +1 -0
  44. package/dist/src/harness-review/collect.d.ts +75 -0
  45. package/dist/src/harness-review/collect.d.ts.map +1 -0
  46. package/dist/src/harness-review/collect.js +253 -0
  47. package/dist/src/harness-review/collect.js.map +1 -0
  48. package/dist/src/harness-review/copy-drift.d.ts +83 -0
  49. package/dist/src/harness-review/copy-drift.d.ts.map +1 -0
  50. package/dist/src/harness-review/copy-drift.js +477 -0
  51. package/dist/src/harness-review/copy-drift.js.map +1 -0
  52. package/dist/src/harness-review/follow-up-marker.d.ts +29 -0
  53. package/dist/src/harness-review/follow-up-marker.d.ts.map +1 -0
  54. package/dist/src/harness-review/follow-up-marker.js +143 -0
  55. package/dist/src/harness-review/follow-up-marker.js.map +1 -0
  56. package/dist/src/harness-review/forward-search.d.ts +30 -0
  57. package/dist/src/harness-review/forward-search.d.ts.map +1 -0
  58. package/dist/src/harness-review/forward-search.js +381 -0
  59. package/dist/src/harness-review/forward-search.js.map +1 -0
  60. package/dist/src/harness-review/github-backend.d.ts +42 -0
  61. package/dist/src/harness-review/github-backend.d.ts.map +1 -0
  62. package/dist/src/harness-review/github-backend.js +130 -0
  63. package/dist/src/harness-review/github-backend.js.map +1 -0
  64. package/dist/src/harness-review/github-code-search.d.ts +46 -0
  65. package/dist/src/harness-review/github-code-search.d.ts.map +1 -0
  66. package/dist/src/harness-review/github-code-search.js +94 -0
  67. package/dist/src/harness-review/github-code-search.js.map +1 -0
  68. package/dist/src/harness-review/identifiers.d.ts +75 -0
  69. package/dist/src/harness-review/identifiers.d.ts.map +1 -0
  70. package/dist/src/harness-review/identifiers.js +678 -0
  71. package/dist/src/harness-review/identifiers.js.map +1 -0
  72. package/dist/src/harness-review/placeholders.d.ts +44 -0
  73. package/dist/src/harness-review/placeholders.d.ts.map +1 -0
  74. package/dist/src/harness-review/placeholders.js +138 -0
  75. package/dist/src/harness-review/placeholders.js.map +1 -0
  76. package/dist/src/harness-review/related-pr.d.ts +133 -0
  77. package/dist/src/harness-review/related-pr.d.ts.map +1 -0
  78. package/dist/src/harness-review/related-pr.js +553 -0
  79. package/dist/src/harness-review/related-pr.js.map +1 -0
  80. package/dist/src/harness-review/related-repos.d.ts +69 -0
  81. package/dist/src/harness-review/related-repos.d.ts.map +1 -0
  82. package/dist/src/harness-review/related-repos.js +430 -0
  83. package/dist/src/harness-review/related-repos.js.map +1 -0
  84. package/dist/src/harness-review/remote-url.d.ts +8 -0
  85. package/dist/src/harness-review/remote-url.d.ts.map +1 -0
  86. package/dist/src/harness-review/remote-url.js +35 -0
  87. package/dist/src/harness-review/remote-url.js.map +1 -0
  88. package/dist/src/harness-review/replay.d.ts +163 -0
  89. package/dist/src/harness-review/replay.d.ts.map +1 -0
  90. package/dist/src/harness-review/replay.js +575 -0
  91. package/dist/src/harness-review/replay.js.map +1 -0
  92. package/dist/src/harness-review/rule-id-lists.d.ts +38 -0
  93. package/dist/src/harness-review/rule-id-lists.d.ts.map +1 -0
  94. package/dist/src/harness-review/rule-id-lists.js +189 -0
  95. package/dist/src/harness-review/rule-id-lists.js.map +1 -0
  96. package/dist/src/harness-review/search-backend.d.ts +59 -0
  97. package/dist/src/harness-review/search-backend.d.ts.map +1 -0
  98. package/dist/src/harness-review/search-backend.js +178 -0
  99. package/dist/src/harness-review/search-backend.js.map +1 -0
  100. package/dist/src/harness-review/self-contamination.d.ts +83 -0
  101. package/dist/src/harness-review/self-contamination.d.ts.map +1 -0
  102. package/dist/src/harness-review/self-contamination.js +560 -0
  103. package/dist/src/harness-review/self-contamination.js.map +1 -0
  104. package/dist/src/harness-review/self-references.d.ts +20 -0
  105. package/dist/src/harness-review/self-references.d.ts.map +1 -0
  106. package/dist/src/harness-review/self-references.js +173 -0
  107. package/dist/src/harness-review/self-references.js.map +1 -0
  108. package/dist/src/harness-review/three-state.d.ts +79 -0
  109. package/dist/src/harness-review/three-state.d.ts.map +1 -0
  110. package/dist/src/harness-review/three-state.js +238 -0
  111. package/dist/src/harness-review/three-state.js.map +1 -0
  112. package/dist/src/harness-review/types.d.ts +148 -0
  113. package/dist/src/harness-review/types.d.ts.map +1 -0
  114. package/dist/src/harness-review/types.js +74 -0
  115. package/dist/src/harness-review/types.js.map +1 -0
  116. package/dist/src/index.d.ts +1 -0
  117. package/dist/src/index.d.ts.map +1 -1
  118. package/dist/src/index.js +1 -0
  119. package/dist/src/index.js.map +1 -1
  120. package/dist/src/mcp/tools/review-passthrough.js +7 -1
  121. package/dist/src/mcp/tools/review-passthrough.js.map +1 -1
  122. package/dist/src/review/agent-matcher.d.ts +16 -1
  123. package/dist/src/review/agent-matcher.d.ts.map +1 -1
  124. package/dist/src/review/agent-matcher.js +31 -4
  125. package/dist/src/review/agent-matcher.js.map +1 -1
  126. package/dist/src/review/passthrough-engine.d.ts.map +1 -1
  127. package/dist/src/review/passthrough-engine.js +40 -2
  128. package/dist/src/review/passthrough-engine.js.map +1 -1
  129. package/package.json +1 -1
  130. package/plugin/.codex-plugin/plugin.json +1 -1
  131. package/plugin/.mcp.json +1 -1
  132. package/plugin/mcp.json +1 -1
  133. package/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
  134. package/plugin/role-agents/_shared/references/comment-rules.md +1 -1
  135. package/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
  136. package/plugin/skills/_shared/proactive-routing.md +1 -0
  137. package/plugin/skills/_shared/rule-sources.md +1 -1
  138. package/plugin/skills/agent/SKILL.md +2 -0
  139. package/plugin/skills/review/SKILL.md +343 -7
  140. package/plugin/skills/review-loop/SKILL.md +124 -2
  141. package/plugin/skills/ship/SKILL.md +40 -1
  142. package/schemas/gestalt.schema.json +12 -0
@@ -0,0 +1,477 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join, posix, relative, resolve } from 'node:path';
4
+ import { queryCoChange } from '../code-graph/cochange.js';
5
+ import { CodeGraphStore } from '../code-graph/storage.js';
6
+ import { parseUnifiedDiff } from './identifiers.js';
7
+ export const COPY_DRIFT_SOURCES = [
8
+ 'identicalBlob',
9
+ 'coChange',
10
+ 'hiddenCopy',
11
+ 'syncDeclared',
12
+ ];
13
+ export const DEFAULT_CONTEXT_LINES = 2;
14
+ export const MAX_DIFF_CONTEXT_LINES = 6;
15
+ export const MAX_HIDDEN_COPY_PHRASES = 40;
16
+ export const MAX_HITS_PER_PHRASE = 20;
17
+ /** 이보다 짧은 구절은 흔한 말이라 다른 문서에 우연히 겹친다 */
18
+ export const MIN_PHRASE_CHARS = 10;
19
+ export const MIN_ASCII_PHRASE_WORDS = 4;
20
+ /**
21
+ * 문서에서 두 파일을 같게 유지하라고 적은 자리를 찾는 표현. "동일하게"는
22
+ * "규칙은 동일하게 지킨다"처럼 사본과 무관한 문장에도 흔하게 나오므로
23
+ * 이 표현만으로는 후보를 내지 않고 같은 줄에 파일 경로가 둘 있어야 낸다.
24
+ */
25
+ export const SYNC_DECLARATION_PATTERNS = [
26
+ '같게 유지',
27
+ '동일하게 유지',
28
+ '똑같이 유지',
29
+ '동일하게',
30
+ '내용 동일',
31
+ '내용이 같',
32
+ 'keep in sync',
33
+ 'kept in sync',
34
+ 'in sync with',
35
+ 'keep identical',
36
+ 'stay identical',
37
+ ];
38
+ const SELF_REFERENCE_RE = /이 파일|이 문서|this file|this document/i;
39
+ const EMPTY_BLOB = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391';
40
+ const SYMLINK_MODE = '120000';
41
+ function defaultRunGit(root, args) {
42
+ return execFileSync('git', ['-c', 'core.quotepath=false', ...args], {
43
+ cwd: root,
44
+ encoding: 'utf-8',
45
+ maxBuffer: 64 * 1024 * 1024,
46
+ stdio: ['pipe', 'pipe', 'pipe'],
47
+ });
48
+ }
49
+ function readTree(runGit, root, ref) {
50
+ const out = new Map();
51
+ for (const record of runGit(root, ['ls-tree', '-r', '-z', ref]).split('\0')) {
52
+ if (!record)
53
+ continue;
54
+ const tab = record.indexOf('\t');
55
+ const [mode, type, sha] = record.slice(0, tab).split(' ');
56
+ // 서브모듈은 commit 항목이라 blob 비교 대상이 아니다
57
+ if (type !== 'blob' || !mode || !sha)
58
+ continue;
59
+ out.set(record.slice(tab + 1), { mode, sha });
60
+ }
61
+ return out;
62
+ }
63
+ /** 파일별로 지워진 줄과 추가된 줄만 추린다. 지워진 파일은 base 경로를 키로 쓴다 */
64
+ export function summarizeDiff(raw) {
65
+ const files = new Map();
66
+ for (const f of parseUnifiedDiff(raw)) {
67
+ const path = f.newPath ?? f.oldPath;
68
+ const first = f.hunks[0];
69
+ if (path === null || !first)
70
+ continue;
71
+ const summary = {
72
+ firstLine: Math.max(first.newStart, 1),
73
+ removed: [],
74
+ added: [],
75
+ };
76
+ for (const hunk of f.hunks) {
77
+ for (const l of hunk.lines) {
78
+ if (l.type === 'removed')
79
+ summary.removed.push({ line: l.lineNumber, text: l.text });
80
+ else if (l.type === 'added')
81
+ summary.added.push({ line: l.lineNumber, text: l.text });
82
+ }
83
+ }
84
+ files.set(path, summary);
85
+ }
86
+ return files;
87
+ }
88
+ /** 목록 끼움으로 볼 최소 항목 수. 둘짜리 나열은 산문에서도 흔해 같은 목록이라고 보기 어렵다 */
89
+ export const MIN_LIST_ANCHOR_ITEMS = 3;
90
+ /** 바뀐 줄 짝을 찾는 파일당 지운 줄 한도. 넘으면 문서를 갈아엎은 것이라 줄 짝이 뜻이 없다 */
91
+ const MAX_PAIRING_LINES = 200;
92
+ const LIST_ITEM = '(?:`[^`\\n]+`|[^\\s`·,、/()|]+)';
93
+ const LIST_TAIL_RE = new RegExp(`${LIST_ITEM}(?:\\s?[·,、/]\\s?${LIST_ITEM})+$`);
94
+ const LIST_ITEM_RE = new RegExp(LIST_ITEM, 'g');
95
+ const INSERTED_ITEM_RE = new RegExp(`^\\s?[·,、/]\\s?(${LIST_ITEM})`);
96
+ /**
97
+ * 두 줄을 앞에서부터 함께 읽다가 어긋나는 자리마다 "구분자 + 항목"을 건너뛰어 본다.
98
+ * 건너뛴 뒤 다시 맞아떨어지면 끼운 것이다. 지운 쪽에 남는 글자가 생기면 바꾼 것이라 null이다
99
+ */
100
+ function insertedItems(removed, added) {
101
+ const out = [];
102
+ let i = 0;
103
+ let j = 0;
104
+ while (i < removed.length) {
105
+ if (j < added.length && removed[i] === added[j]) {
106
+ i++;
107
+ j++;
108
+ continue;
109
+ }
110
+ const m = INSERTED_ITEM_RE.exec(added.slice(j));
111
+ if (!m)
112
+ return null;
113
+ out.push({ at: i, item: m[1].replace(/`/g, '') });
114
+ j += m[0].length;
115
+ }
116
+ if (j < added.length) {
117
+ const m = INSERTED_ITEM_RE.exec(added.slice(j));
118
+ if (!m || j + m[0].length !== added.length)
119
+ return null;
120
+ out.push({ at: i, item: m[1].replace(/`/g, '') });
121
+ }
122
+ return out.length > 0 ? out : null;
123
+ }
124
+ /**
125
+ * 지운 줄과 추가 줄 짝에서 목록 끝에 항목을 더한 수정을 찾는다.
126
+ * 줄 전체에서 뽑은 구절은 새 줄에도 그대로 남아 숨은 사본 검색에 안 걸린다. 끼운 자리 앞의 목록만 떼어 찾는다
127
+ */
128
+ export function findListInsertions(diff) {
129
+ if (diff.removed.length > MAX_PAIRING_LINES)
130
+ return [];
131
+ const out = [];
132
+ const used = new Set();
133
+ for (const r of diff.removed) {
134
+ for (const [i, a] of diff.added.entries()) {
135
+ if (used.has(i))
136
+ continue;
137
+ const items = insertedItems(r.text, a.text);
138
+ if (!items)
139
+ continue;
140
+ used.add(i);
141
+ for (const { at, item } of items) {
142
+ const tail = LIST_TAIL_RE.exec(r.text.slice(0, at));
143
+ if (!tail || [...tail[0].matchAll(LIST_ITEM_RE)].length < MIN_LIST_ANCHOR_ITEMS)
144
+ continue;
145
+ out.push({ anchor: tail[0], item, sourceLine: a.line });
146
+ }
147
+ break;
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ function pairKey(a, b) {
153
+ return a < b ? `${a}\t${b}` : `${b}\t${a}`;
154
+ }
155
+ function diffPreview(diff) {
156
+ if (!diff)
157
+ return [];
158
+ return [...diff.removed.map((l) => `-${l.text}`), ...diff.added.map((l) => `+${l.text}`)].slice(0, MAX_DIFF_CONTEXT_LINES);
159
+ }
160
+ function contextAround(lines, lineNo, n) {
161
+ const start = Math.max(0, lineNo - 1 - n);
162
+ return lines.slice(start, lineNo + n);
163
+ }
164
+ /** `git grep <ref>`의 `ref:path:line:text` 출력을 푼다. 매치가 없으면 git이 1로 끝나므로 빈 결과로 본다 */
165
+ function gitGrep(runGit, root, ref, args, pathspec = []) {
166
+ let raw;
167
+ try {
168
+ raw = runGit(root, ['grep', '-n', '-I', '--no-color', ...args, ref, '--', ...pathspec]);
169
+ }
170
+ catch (e) {
171
+ if (e.status === 1)
172
+ return [];
173
+ throw e;
174
+ }
175
+ const prefix = `${ref}:`;
176
+ const hits = [];
177
+ for (const row of raw.split('\n')) {
178
+ if (!row.startsWith(prefix))
179
+ continue;
180
+ const m = /^(.*?):(\d+):(.*)$/.exec(row.slice(prefix.length));
181
+ if (!m)
182
+ continue;
183
+ hits.push({ path: m[1], line: Number(m[2]), text: m[3] });
184
+ }
185
+ return hits;
186
+ }
187
+ /**
188
+ * 삭제되거나 바뀐 규칙 줄에서 다른 문서에 그대로 남았을 법한 구절 하나를 뽑는다.
189
+ * 서식 기호에서 끊는 이유는 사본마다 백틱이나 굵게 표시가 달라서 서식을 낀 구절로는
190
+ * 고정 문자열 검색이 안 맞기 때문이다.
191
+ */
192
+ export function extractKeyPhrase(line) {
193
+ const trimmed = line.trim();
194
+ if (!trimmed || trimmed.startsWith('```') || /^\|?[\s:|-]+\|?$/.test(trimmed))
195
+ return null;
196
+ const body = trimmed.replace(/^(?:[-*+>#]+|\d+[.)])\s*/, '');
197
+ const segments = body
198
+ .split(/[`*_|"“”‘’()[\]{}<>.,;:!?。—]|\s-\s/)
199
+ .map((s) => s.trim().replace(/\s+/g, ' '))
200
+ .filter((s) => s.replace(/\s/g, '').length >= MIN_PHRASE_CHARS && s.includes(' '))
201
+ // 영어만 있는 짧은 구절은 코드 블록 안의 코드(`throw new Error`)나 흔한 용어라 사본 표지가 못 된다.
202
+ // 줄 하나만 봐서는 펜스 안인지 알 수 없어 낱말 수로 가른다
203
+ .filter((s) => /[^ -~]/.test(s) || s.split(' ').length >= MIN_ASCII_PHRASE_WORDS);
204
+ if (segments.length === 0)
205
+ return null;
206
+ return segments.reduce((a, b) => (b.length > a.length ? b : a));
207
+ }
208
+ /** 줄에 적힌 경로 꼴 토큰. 한글 조사가 붙어도 ASCII 구간에서 끊겨 경로만 남는다 */
209
+ function pathTokens(text) {
210
+ const out = [];
211
+ for (const m of text.matchAll(/[A-Za-z0-9_./-]+/g)) {
212
+ const token = m[0].replace(/^\.\/|[./]+$/g, '');
213
+ if (token.includes('/') || /\.[A-Za-z0-9]+$/.test(token))
214
+ out.push(token);
215
+ }
216
+ return out;
217
+ }
218
+ function resolveDocPath(token, docPath, tree) {
219
+ if (tree.has(token))
220
+ return token;
221
+ const rel = posix.normalize(posix.join(posix.dirname(docPath), token));
222
+ return tree.has(rel) ? rel : null;
223
+ }
224
+ /**
225
+ * base와 head 사이에서 사본 한쪽만 바뀐 자리를 후보로 모은다. 네 경로를 따로 돌리고
226
+ * 한 경로가 실패해도 나머지 결과는 살린다. 판정은 하지 않는다 — 후보만 낸다.
227
+ */
228
+ export function findCopyDrift(opts) {
229
+ const root = resolve(opts.repoRoot);
230
+ const runGit = opts.runGit ?? defaultRunGit;
231
+ const repo = opts.repo ?? '.';
232
+ const ctxN = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
233
+ const limitations = [];
234
+ const bySource = {
235
+ identicalBlob: [],
236
+ coChange: [],
237
+ hiddenCopy: [],
238
+ syncDeclared: [],
239
+ };
240
+ const coChange = { checked: false };
241
+ const baseTree = readTree(runGit, root, opts.base);
242
+ const headTree = readTree(runGit, root, opts.head);
243
+ const headPaths = new Set(headTree.keys());
244
+ const changed = new Set();
245
+ for (const [p, e] of baseTree)
246
+ if (headTree.get(p)?.sha !== e.sha)
247
+ changed.add(p);
248
+ for (const p of headTree.keys())
249
+ if (!baseTree.has(p))
250
+ changed.add(p);
251
+ const diffs = summarizeDiff(runGit(root, ['diff', '--no-color', '--no-renames', '-U0', opts.base, opts.head]));
252
+ const headContent = new Map();
253
+ const readHead = (path) => {
254
+ let lines = headContent.get(path);
255
+ if (!lines) {
256
+ lines = runGit(root, ['show', `${opts.head}:${path}`]).split('\n');
257
+ headContent.set(path, lines);
258
+ }
259
+ return lines;
260
+ };
261
+ const make = (sourceFile, targetPath, fields) => ({
262
+ kind: 'copyDrift',
263
+ sourceFile,
264
+ sourceLine: diffs.get(sourceFile)?.firstLine ?? 1,
265
+ targetRepo: repo,
266
+ targetPath,
267
+ matchedText: '',
268
+ contextLines: diffPreview(diffs.get(sourceFile)),
269
+ needsLlmJudgment: false,
270
+ ...fields,
271
+ });
272
+ // (1) base에서 blob이 같던 파일 묶음 가운데 head에서 갈라진 쌍
273
+ try {
274
+ const groups = new Map();
275
+ for (const [p, e] of baseTree) {
276
+ if (e.sha === EMPTY_BLOB || e.mode === SYMLINK_MODE)
277
+ continue;
278
+ const g = groups.get(e.sha);
279
+ if (g)
280
+ g.push(p);
281
+ else
282
+ groups.set(e.sha, [p]);
283
+ }
284
+ for (const [sha, members] of groups) {
285
+ if (members.length < 2)
286
+ continue;
287
+ // 지워진 쪽은 이동이나 폐기라서 어긋남으로 보지 않는다
288
+ const alive = members.filter((p) => headPaths.has(p));
289
+ for (const source of alive.filter((p) => changed.has(p))) {
290
+ const sourceSha = headTree.get(source).sha;
291
+ for (const target of alive) {
292
+ if (target === source || headTree.get(target).sha === sourceSha)
293
+ continue;
294
+ if (changed.has(target) && target < source)
295
+ continue;
296
+ bySource.identicalBlob.push(make(source, target, {
297
+ matchedText: `base에서 blob ${sha.slice(0, 12)}이 같던 파일이 head에서 갈라짐`,
298
+ }));
299
+ }
300
+ }
301
+ }
302
+ }
303
+ catch (e) {
304
+ limitations.push(`blob 비교 실패: ${errMessage(e)}`);
305
+ }
306
+ // (2) co-change로 함께 바뀌던 이웃 중 이번에 안 바뀐 파일
307
+ const dbPath = opts.codeGraphDbPath ?? join(root, '.gestalt', 'code-graph.db');
308
+ if (!existsSync(dbPath)) {
309
+ coChange.reason = `코드 그래프 DB가 없어 co-change 경로를 건너뛰었다 (${relOrAbs(root, dbPath)})`;
310
+ limitations.push(coChange.reason);
311
+ }
312
+ else {
313
+ let store = null;
314
+ try {
315
+ store = new CodeGraphStore(dbPath);
316
+ const seeds = [...changed].filter((p) => headPaths.has(p));
317
+ const exists = (abs) => headPaths.has(toRel(root, abs));
318
+ if (!store.getCoChangeMeta()) {
319
+ coChange.reason = '코드 그래프 DB에 co-change 이력이 수집되지 않았다';
320
+ limitations.push(coChange.reason);
321
+ }
322
+ else {
323
+ coChange.checked = true;
324
+ for (const seed of seeds) {
325
+ // seed별로 따로 묻는다. 합쳐 물으면 어느 파일의 이웃인지가 사라진다
326
+ const r = queryCoChange(store, root, { ...opts.coChange, target: seed, exists });
327
+ if (r.matchedCapped)
328
+ limitations.push(`co-change 질의가 천장에 걸려 일부만 봤다: ${seed}`);
329
+ for (const n of r.neighbors) {
330
+ const target = toRel(root, n.filePath);
331
+ if (changed.has(target))
332
+ continue;
333
+ bySource.coChange.push(make(seed, target, {
334
+ matchedText: `co-change ${n.pairCount}회, confidence ${n.confidence}, lift ${n.lift}`,
335
+ contextLines: [],
336
+ }));
337
+ }
338
+ }
339
+ }
340
+ }
341
+ catch (e) {
342
+ coChange.reason = `co-change 조회 실패: ${errMessage(e)}`;
343
+ limitations.push(coChange.reason);
344
+ }
345
+ finally {
346
+ store?.close();
347
+ }
348
+ }
349
+ // (3) 바뀐 규칙 문장의 핵심 구절이 다른 파일에 그대로 남은 숨은 사본
350
+ try {
351
+ const seen = new Set();
352
+ let phrases = 0;
353
+ // 지운 구절이 이번 diff에서 추가된 파일은 그 구절이 옮겨간 자리라 사본이 아니다.
354
+ // --no-renames라 파일을 옮기면 옛 파일은 전부 지운 줄, 새 파일은 전부 추가 줄로 나온다.
355
+ // 구절을 통째로 건너뛰면 중복을 한 곳으로 모은 PR에서 diff 밖에 남은 사본까지 놓친다
356
+ const addedByPath = new Map([...diffs].map(([path, d]) => [path, d.added.map((l) => l.text).join('\n')]));
357
+ outer: for (const [source, diff] of diffs) {
358
+ if (!source.endsWith('.md'))
359
+ continue;
360
+ const sourceNow = headPaths.has(source) ? readHead(source).join('\n') : '';
361
+ for (const removed of diff.removed) {
362
+ const phrase = extractKeyPhrase(removed.text);
363
+ // head의 같은 파일에 구절이 아직 있으면 문장을 옮긴 것일 뿐이다
364
+ if (!phrase || seen.has(phrase) || sourceNow.includes(phrase))
365
+ continue;
366
+ seen.add(phrase);
367
+ // 규칙 문장의 사본은 문서끼리의 일이다. 코드에 같은 명령어가 적힌 건 사본이 아니다
368
+ const hits = gitGrep(runGit, root, opts.head, ['-F', '-e', phrase], ['*.md']).filter((h) => h.path !== source && !addedByPath.get(h.path)?.includes(phrase));
369
+ if (hits.length === 0)
370
+ continue;
371
+ if (++phrases > MAX_HIDDEN_COPY_PHRASES) {
372
+ limitations.push(`숨은 사본 검색 구절이 ${MAX_HIDDEN_COPY_PHRASES}개를 넘어 뒤쪽은 건너뛰었다`);
373
+ break outer;
374
+ }
375
+ for (const hit of hits.slice(0, MAX_HITS_PER_PHRASE)) {
376
+ bySource.hiddenCopy.push(make(source, hit.path, {
377
+ sourceLine: removed.line,
378
+ targetLine: hit.line,
379
+ matchedText: phrase,
380
+ contextLines: contextAround(readHead(hit.path), hit.line, ctxN),
381
+ }));
382
+ }
383
+ }
384
+ }
385
+ }
386
+ catch (e) {
387
+ limitations.push(`숨은 사본 검색 실패: ${errMessage(e)}`);
388
+ }
389
+ // (3b) 목록에 항목을 끼웠는데 diff 밖의 같은 목록에는 안 끼운 자리. 목록이 원래 달라야 하는
390
+ // 자리일 수 있어 LLM 판정으로 넘긴다
391
+ try {
392
+ // 이번 diff가 이미 고친 줄은 리뷰어가 diff에서 읽는다
393
+ const addedLineSet = new Set([...diffs].flatMap(([path, d]) => d.added.map((l) => `${path}:${l.line}`)));
394
+ const reported = new Set();
395
+ for (const [source, diff] of diffs) {
396
+ if (!source.endsWith('.md'))
397
+ continue;
398
+ for (const ins of findListInsertions(diff)) {
399
+ const hits = gitGrep(runGit, root, opts.head, ['-F', '-e', ins.anchor], ['*.md']).filter((h) => !h.text.includes(ins.item) && !addedLineSet.has(`${h.path}:${h.line}`));
400
+ // 겹치는 목록(앞 셋과 앞 넷)이 같은 줄을 두 번 잡는다
401
+ const fresh = hits.filter((h) => {
402
+ const key = `${h.path}:${h.line}:${ins.item}`;
403
+ if (reported.has(key))
404
+ return false;
405
+ reported.add(key);
406
+ return true;
407
+ });
408
+ for (const hit of fresh.slice(0, MAX_HITS_PER_PHRASE)) {
409
+ bySource.hiddenCopy.push(make(source, hit.path, {
410
+ sourceLine: ins.sourceLine,
411
+ targetLine: hit.line,
412
+ matchedText: `${ins.anchor} (이번 PR은 ${ins.item}를 더함)`,
413
+ contextLines: contextAround(readHead(hit.path), hit.line, ctxN),
414
+ needsLlmJudgment: true,
415
+ }));
416
+ }
417
+ }
418
+ }
419
+ }
420
+ catch (e) {
421
+ limitations.push(`목록 끼움 검색 실패: ${errMessage(e)}`);
422
+ }
423
+ // (4) 문서가 같게 유지하라고 적은 쌍. 어느 쪽이 기준인지, 이번 변경이 그 약속을
424
+ // 깨는지는 문장을 읽어야 알 수 있어 LLM 판정으로 넘긴다
425
+ try {
426
+ const args = ['-i', '-E', ...SYNC_DECLARATION_PATTERNS.flatMap((p) => ['-e', p])];
427
+ for (const decl of gitGrep(runGit, root, opts.head, args, ['*.md'])) {
428
+ const paths = [
429
+ ...new Set(pathTokens(decl.text)
430
+ .map((t) => resolveDocPath(t, decl.path, headPaths))
431
+ .filter((p) => p !== null)),
432
+ ];
433
+ if (paths.length === 1 && SELF_REFERENCE_RE.test(decl.text))
434
+ paths.push(decl.path);
435
+ const sources = paths.filter((p) => changed.has(p));
436
+ const targets = paths.filter((p) => !changed.has(p));
437
+ for (const source of sources) {
438
+ for (const target of targets) {
439
+ bySource.syncDeclared.push(make(source, target, {
440
+ matchedText: `${decl.path}:${decl.line}: ${decl.text.trim()}`,
441
+ contextLines: contextAround(readHead(decl.path), decl.line, ctxN),
442
+ needsLlmJudgment: true,
443
+ }));
444
+ }
445
+ }
446
+ }
447
+ }
448
+ catch (e) {
449
+ limitations.push(`같게 유지 선언 검색 실패: ${errMessage(e)}`);
450
+ }
451
+ // 같은 쌍이 여러 경로에 걸리면 판정 근거가 가장 뚜렷한 경로 하나에만 남긴다.
452
+ // 선언이 있는 쌍은 LLM 판정으로 분리하기로 했으므로 맨 앞이다
453
+ const claimed = new Set();
454
+ for (const source of ['syncDeclared', 'identicalBlob', 'hiddenCopy', 'coChange']) {
455
+ const kept = bySource[source].filter((c) => !claimed.has(pairKey(c.sourceFile, c.targetPath)));
456
+ for (const c of kept)
457
+ claimed.add(pairKey(c.sourceFile, c.targetPath));
458
+ bySource[source] = kept;
459
+ }
460
+ return {
461
+ candidates: COPY_DRIFT_SOURCES.flatMap((s) => bySource[s]),
462
+ bySource,
463
+ coChange,
464
+ limitations,
465
+ };
466
+ }
467
+ function toRel(root, abs) {
468
+ return relative(root, abs).split('\\').join('/');
469
+ }
470
+ function relOrAbs(root, p) {
471
+ const abs = resolve(p);
472
+ return abs.startsWith(root) ? toRel(root, abs) : abs;
473
+ }
474
+ function errMessage(e) {
475
+ return e instanceof Error ? e.message : String(e);
476
+ }
477
+ //# sourceMappingURL=copy-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-drift.js","sourceRoot":"","sources":["../../../src/harness-review/copy-drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { FollowUpMarker } from './types.js';
2
+ export interface FollowUpPr {
3
+ repo: string;
4
+ number: number;
5
+ body: string;
6
+ diff: string;
7
+ }
8
+ export type FollowUpMatchStatus = 'fulfilled' | 'unmet' | 'wrongRepo';
9
+ export interface FollowUpMatch {
10
+ status: FollowUpMatchStatus;
11
+ mentionsOrigin: boolean;
12
+ coverage: number;
13
+ missingTerms: string[];
14
+ }
15
+ /**
16
+ * resolve 답글 본문을 만든다. 첫 줄은 기계가 읽는 HTML 주석, 둘째 줄은 사람이 읽는 문장이다.
17
+ * JSON 안의 `<`, `>`는 이스케이프해서 값이 주석을 조기에 닫지 못하게 한다.
18
+ */
19
+ export declare function buildFollowUpMarker(marker: FollowUpMarker): string;
20
+ /**
21
+ * 코멘트 본문에서 마커의 정해진 필드만 뽑는다. 주석 밖 문장과 모르는 필드는 버리고
22
+ * 필드가 하나라도 형식에 안 맞는 마커는 통째로 건너뛴다.
23
+ * 코멘트 작성자는 검증하지 않으므로 호출부가 신뢰할 작성자의 코멘트만 넘겨야 한다.
24
+ */
25
+ export declare function parseFollowUpMarkers(commentBody: string): FollowUpMarker[];
26
+ export declare function isFulfilled(marker: FollowUpMarker): boolean;
27
+ /** 후속 PR이 마커의 레포와 작업을 이행하는지 본다. 본문과 diff는 단어 매칭에만 쓴다. */
28
+ export declare function matchFollowUp(marker: FollowUpMarker, pr: FollowUpPr): FollowUpMatch;
29
+ //# sourceMappingURL=follow-up-marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follow-up-marker.d.ts","sourceRoot":"","sources":["../../../src/harness-review/follow-up-marker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA+BjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAOlE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,EAAE,CAO1E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAE3D;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,GAAG,aAAa,CAkBnF"}