@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.
- package/CLAUDE.md +2 -2
- package/README.ko.md +3 -1
- package/README.md +3 -1
- package/dist/package.json +1 -1
- package/dist/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
- package/dist/plugin/role-agents/_shared/references/comment-rules.md +1 -1
- package/dist/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
- package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
- package/dist/plugin/skills/_shared/rule-sources.md +1 -1
- package/dist/plugin/skills/agent/SKILL.md +2 -0
- package/dist/plugin/skills/review/SKILL.md +343 -7
- package/dist/plugin/skills/review-loop/SKILL.md +124 -2
- package/dist/plugin/skills/ship/SKILL.md +40 -1
- package/dist/schemas/gestalt.schema.json +12 -0
- package/dist/src/cli/commands/approve-gate.d.ts +24 -0
- package/dist/src/cli/commands/approve-gate.d.ts.map +1 -0
- package/dist/src/cli/commands/approve-gate.js +90 -0
- package/dist/src/cli/commands/approve-gate.js.map +1 -0
- package/dist/src/cli/commands/harness-refs-cross-pr.d.ts +218 -0
- package/dist/src/cli/commands/harness-refs-cross-pr.d.ts.map +1 -0
- package/dist/src/cli/commands/harness-refs-cross-pr.js +934 -0
- package/dist/src/cli/commands/harness-refs-cross-pr.js.map +1 -0
- package/dist/src/cli/commands/harness-refs.d.ts +19 -0
- package/dist/src/cli/commands/harness-refs.d.ts.map +1 -0
- package/dist/src/cli/commands/harness-refs.js +51 -0
- package/dist/src/cli/commands/harness-refs.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +97 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/config.d.ts +3 -0
- package/dist/src/core/config.d.ts.map +1 -1
- package/dist/src/core/config.js +23 -0
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/types.d.ts +2 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/harness-review/approve-gate.d.ts +53 -0
- package/dist/src/harness-review/approve-gate.d.ts.map +1 -0
- package/dist/src/harness-review/approve-gate.js +148 -0
- package/dist/src/harness-review/approve-gate.js.map +1 -0
- package/dist/src/harness-review/backward-search.d.ts +50 -0
- package/dist/src/harness-review/backward-search.d.ts.map +1 -0
- package/dist/src/harness-review/backward-search.js +183 -0
- package/dist/src/harness-review/backward-search.js.map +1 -0
- package/dist/src/harness-review/collect.d.ts +75 -0
- package/dist/src/harness-review/collect.d.ts.map +1 -0
- package/dist/src/harness-review/collect.js +253 -0
- package/dist/src/harness-review/collect.js.map +1 -0
- package/dist/src/harness-review/copy-drift.d.ts +83 -0
- package/dist/src/harness-review/copy-drift.d.ts.map +1 -0
- package/dist/src/harness-review/copy-drift.js +477 -0
- package/dist/src/harness-review/copy-drift.js.map +1 -0
- package/dist/src/harness-review/follow-up-marker.d.ts +29 -0
- package/dist/src/harness-review/follow-up-marker.d.ts.map +1 -0
- package/dist/src/harness-review/follow-up-marker.js +143 -0
- package/dist/src/harness-review/follow-up-marker.js.map +1 -0
- package/dist/src/harness-review/forward-search.d.ts +30 -0
- package/dist/src/harness-review/forward-search.d.ts.map +1 -0
- package/dist/src/harness-review/forward-search.js +381 -0
- package/dist/src/harness-review/forward-search.js.map +1 -0
- package/dist/src/harness-review/github-backend.d.ts +42 -0
- package/dist/src/harness-review/github-backend.d.ts.map +1 -0
- package/dist/src/harness-review/github-backend.js +130 -0
- package/dist/src/harness-review/github-backend.js.map +1 -0
- package/dist/src/harness-review/github-code-search.d.ts +46 -0
- package/dist/src/harness-review/github-code-search.d.ts.map +1 -0
- package/dist/src/harness-review/github-code-search.js +94 -0
- package/dist/src/harness-review/github-code-search.js.map +1 -0
- package/dist/src/harness-review/identifiers.d.ts +75 -0
- package/dist/src/harness-review/identifiers.d.ts.map +1 -0
- package/dist/src/harness-review/identifiers.js +678 -0
- package/dist/src/harness-review/identifiers.js.map +1 -0
- package/dist/src/harness-review/placeholders.d.ts +44 -0
- package/dist/src/harness-review/placeholders.d.ts.map +1 -0
- package/dist/src/harness-review/placeholders.js +138 -0
- package/dist/src/harness-review/placeholders.js.map +1 -0
- package/dist/src/harness-review/related-pr.d.ts +133 -0
- package/dist/src/harness-review/related-pr.d.ts.map +1 -0
- package/dist/src/harness-review/related-pr.js +553 -0
- package/dist/src/harness-review/related-pr.js.map +1 -0
- package/dist/src/harness-review/related-repos.d.ts +69 -0
- package/dist/src/harness-review/related-repos.d.ts.map +1 -0
- package/dist/src/harness-review/related-repos.js +430 -0
- package/dist/src/harness-review/related-repos.js.map +1 -0
- package/dist/src/harness-review/remote-url.d.ts +8 -0
- package/dist/src/harness-review/remote-url.d.ts.map +1 -0
- package/dist/src/harness-review/remote-url.js +35 -0
- package/dist/src/harness-review/remote-url.js.map +1 -0
- package/dist/src/harness-review/replay.d.ts +163 -0
- package/dist/src/harness-review/replay.d.ts.map +1 -0
- package/dist/src/harness-review/replay.js +575 -0
- package/dist/src/harness-review/replay.js.map +1 -0
- package/dist/src/harness-review/rule-id-lists.d.ts +38 -0
- package/dist/src/harness-review/rule-id-lists.d.ts.map +1 -0
- package/dist/src/harness-review/rule-id-lists.js +189 -0
- package/dist/src/harness-review/rule-id-lists.js.map +1 -0
- package/dist/src/harness-review/search-backend.d.ts +59 -0
- package/dist/src/harness-review/search-backend.d.ts.map +1 -0
- package/dist/src/harness-review/search-backend.js +178 -0
- package/dist/src/harness-review/search-backend.js.map +1 -0
- package/dist/src/harness-review/self-contamination.d.ts +83 -0
- package/dist/src/harness-review/self-contamination.d.ts.map +1 -0
- package/dist/src/harness-review/self-contamination.js +560 -0
- package/dist/src/harness-review/self-contamination.js.map +1 -0
- package/dist/src/harness-review/self-references.d.ts +20 -0
- package/dist/src/harness-review/self-references.d.ts.map +1 -0
- package/dist/src/harness-review/self-references.js +173 -0
- package/dist/src/harness-review/self-references.js.map +1 -0
- package/dist/src/harness-review/three-state.d.ts +79 -0
- package/dist/src/harness-review/three-state.d.ts.map +1 -0
- package/dist/src/harness-review/three-state.js +238 -0
- package/dist/src/harness-review/three-state.js.map +1 -0
- package/dist/src/harness-review/types.d.ts +148 -0
- package/dist/src/harness-review/types.d.ts.map +1 -0
- package/dist/src/harness-review/types.js +74 -0
- package/dist/src/harness-review/types.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/tools/review-passthrough.js +7 -1
- package/dist/src/mcp/tools/review-passthrough.js.map +1 -1
- package/dist/src/review/agent-matcher.d.ts +16 -1
- package/dist/src/review/agent-matcher.d.ts.map +1 -1
- package/dist/src/review/agent-matcher.js +31 -4
- package/dist/src/review/agent-matcher.js.map +1 -1
- package/dist/src/review/passthrough-engine.d.ts.map +1 -1
- package/dist/src/review/passthrough-engine.js +40 -2
- package/dist/src/review/passthrough-engine.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
- package/plugin/role-agents/_shared/references/comment-rules.md +1 -1
- package/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
- package/plugin/skills/_shared/proactive-routing.md +1 -0
- package/plugin/skills/_shared/rule-sources.md +1 -1
- package/plugin/skills/agent/SKILL.md +2 -0
- package/plugin/skills/review/SKILL.md +343 -7
- package/plugin/skills/review-loop/SKILL.md +124 -2
- package/plugin/skills/ship/SKILL.md +40 -1
- 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"}
|