@tienne/gestalt 0.67.0 → 0.69.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 +12 -5
- package/README.ko.md +9 -5
- package/README.md +10 -5
- package/dist/package.json +2 -1
- package/dist/plugin/review-agents/comment-reviewer/AGENT.md +2 -0
- package/dist/plugin/review-agents/quality-reviewer/AGENT.md +1 -1
- package/dist/plugin/review-agents/writing-reviewer/AGENT.md +123 -0
- package/dist/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +1 -1
- package/dist/plugin/role-agents/_shared/references/comment-rules.md +14 -0
- package/dist/plugin/skills/_shared/agent-model.md +15 -0
- package/dist/plugin/skills/blast-radius/SKILL.md +31 -0
- package/dist/plugin/skills/diff-radius/SKILL.md +1 -1
- package/dist/plugin/skills/execute/SKILL.md +15 -0
- package/dist/plugin/skills/local-pr/SKILL.md +201 -0
- package/dist/plugin/skills/pr/SKILL.md +73 -4
- package/dist/plugin/skills/review/SKILL.md +236 -22
- package/dist/plugin/skills/review-reply/SKILL.md +160 -7
- package/dist/src/agent/role-match-engine.d.ts +8 -0
- package/dist/src/agent/role-match-engine.d.ts.map +1 -1
- package/dist/src/agent/role-match-engine.js +1 -1
- package/dist/src/agent/role-match-engine.js.map +1 -1
- package/dist/src/cli/commands/interview.js +2 -2
- package/dist/src/cli/commands/interview.js.map +1 -1
- package/dist/src/cli/commands/pr.d.ts +133 -0
- package/dist/src/cli/commands/pr.d.ts.map +1 -0
- package/dist/src/cli/commands/pr.js +489 -0
- package/dist/src/cli/commands/pr.js.map +1 -0
- package/dist/src/cli/commands/spec.js +2 -2
- package/dist/src/cli/commands/spec.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +85 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/config.d.ts.map +1 -1
- package/dist/src/core/config.js +4 -3
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/home.d.ts +20 -0
- package/dist/src/core/home.d.ts.map +1 -0
- package/dist/src/core/home.js +52 -0
- package/dist/src/core/home.js.map +1 -0
- package/dist/src/core/types.d.ts +38 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/version.d.ts.map +1 -1
- package/dist/src/core/version.js +4 -7
- package/dist/src/core/version.js.map +1 -1
- package/dist/src/events/store.d.ts +32 -0
- package/dist/src/events/store.d.ts.map +1 -1
- package/dist/src/events/store.js +68 -3
- package/dist/src/events/store.js.map +1 -1
- package/dist/src/humanize/detectors.d.ts.map +1 -1
- package/dist/src/humanize/detectors.js +3 -1
- package/dist/src/humanize/detectors.js.map +1 -1
- package/dist/src/interview/engine.d.ts +6 -1
- package/dist/src/interview/engine.d.ts.map +1 -1
- package/dist/src/interview/engine.js +7 -2
- package/dist/src/interview/engine.js.map +1 -1
- package/dist/src/knowledge-base/summarizer.d.ts +22 -0
- package/dist/src/knowledge-base/summarizer.d.ts.map +1 -0
- package/dist/src/knowledge-base/summarizer.js +179 -0
- package/dist/src/knowledge-base/summarizer.js.map +1 -0
- package/dist/src/llm/factory.d.ts +9 -0
- package/dist/src/llm/factory.d.ts.map +1 -1
- package/dist/src/llm/factory.js +13 -0
- package/dist/src/llm/factory.js.map +1 -1
- package/dist/src/local-pr/engine.d.ts +176 -0
- package/dist/src/local-pr/engine.d.ts.map +1 -0
- package/dist/src/local-pr/engine.js +373 -0
- package/dist/src/local-pr/engine.js.map +1 -0
- package/dist/src/local-pr/git.d.ts +190 -0
- package/dist/src/local-pr/git.d.ts.map +1 -0
- package/dist/src/local-pr/git.js +580 -0
- package/dist/src/local-pr/git.js.map +1 -0
- package/dist/src/local-pr/index.d.ts +6 -0
- package/dist/src/local-pr/index.d.ts.map +1 -0
- package/dist/src/local-pr/index.js +8 -0
- package/dist/src/local-pr/index.js.map +1 -0
- package/dist/src/local-pr/policy.d.ts +77 -0
- package/dist/src/local-pr/policy.d.ts.map +1 -0
- package/dist/src/local-pr/policy.js +80 -0
- package/dist/src/local-pr/policy.js.map +1 -0
- package/dist/src/local-pr/registry.d.ts +79 -0
- package/dist/src/local-pr/registry.d.ts.map +1 -0
- package/dist/src/local-pr/registry.js +307 -0
- package/dist/src/local-pr/registry.js.map +1 -0
- package/dist/src/local-pr/repository.d.ts +67 -0
- package/dist/src/local-pr/repository.d.ts.map +1 -0
- package/dist/src/local-pr/repository.js +251 -0
- package/dist/src/local-pr/repository.js.map +1 -0
- package/dist/src/local-pr/types.d.ts +151 -0
- package/dist/src/local-pr/types.d.ts.map +1 -0
- package/dist/src/local-pr/types.js +9 -0
- package/dist/src/local-pr/types.js.map +1 -0
- package/dist/src/local-pr-web/engine.d.ts +24 -0
- package/dist/src/local-pr-web/engine.d.ts.map +1 -0
- package/dist/src/local-pr-web/engine.js +112 -0
- package/dist/src/local-pr-web/engine.js.map +1 -0
- package/dist/src/local-pr-web/html-generator.d.ts +24 -0
- package/dist/src/local-pr-web/html-generator.d.ts.map +1 -0
- package/dist/src/local-pr-web/html-generator.js +385 -0
- package/dist/src/local-pr-web/html-generator.js.map +1 -0
- package/dist/src/local-pr-web/index.d.ts +5 -0
- package/dist/src/local-pr-web/index.d.ts.map +1 -0
- package/dist/src/local-pr-web/index.js +5 -0
- package/dist/src/local-pr-web/index.js.map +1 -0
- package/dist/src/local-pr-web/server.d.ts +126 -0
- package/dist/src/local-pr-web/server.d.ts.map +1 -0
- package/dist/src/local-pr-web/server.js +394 -0
- package/dist/src/local-pr-web/server.js.map +1 -0
- package/dist/src/local-pr-web/types.d.ts +11 -0
- package/dist/src/local-pr-web/types.d.ts.map +1 -0
- package/dist/src/local-pr-web/types.js +2 -0
- package/dist/src/local-pr-web/types.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +79 -4
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +80 -2
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +23 -10
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/generate-kb.d.ts +10 -1
- package/dist/src/mcp/tools/generate-kb.d.ts.map +1 -1
- package/dist/src/mcp/tools/generate-kb.js +17 -1
- package/dist/src/mcp/tools/generate-kb.js.map +1 -1
- package/dist/src/mcp/tools/pr.d.ts +5 -0
- package/dist/src/mcp/tools/pr.d.ts.map +1 -0
- package/dist/src/mcp/tools/pr.js +165 -0
- package/dist/src/mcp/tools/pr.js.map +1 -0
- package/dist/src/mcp/tools/review-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/review-passthrough.js +264 -15
- package/dist/src/mcp/tools/review-passthrough.js.map +1 -1
- package/dist/src/mcp/tools/search-kb.d.ts.map +1 -1
- package/dist/src/mcp/tools/search-kb.js +5 -0
- package/dist/src/mcp/tools/search-kb.js.map +1 -1
- package/dist/src/mcp/tools/status.d.ts +16 -0
- package/dist/src/mcp/tools/status.d.ts.map +1 -1
- package/dist/src/mcp/tools/status.js +19 -4
- package/dist/src/mcp/tools/status.js.map +1 -1
- package/dist/src/memory/user-profile-store.d.ts.map +1 -1
- package/dist/src/memory/user-profile-store.js +3 -4
- package/dist/src/memory/user-profile-store.js.map +1 -1
- package/dist/src/review/context-collector.d.ts +1 -1
- package/dist/src/review/context-collector.js +1 -1
- package/dist/src/review/passthrough-engine.d.ts +1 -0
- package/dist/src/review/passthrough-engine.d.ts.map +1 -1
- package/dist/src/review/passthrough-engine.js +7 -2
- package/dist/src/review/passthrough-engine.js.map +1 -1
- package/dist/src/spec/text-based-spec-generator.d.ts.map +1 -1
- package/dist/src/spec/text-based-spec-generator.js +5 -2
- package/dist/src/spec/text-based-spec-generator.js.map +1 -1
- package/package.json +2 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/review-agents/comment-reviewer/AGENT.md +2 -0
- package/plugin/review-agents/quality-reviewer/AGENT.md +1 -1
- package/plugin/review-agents/writing-reviewer/AGENT.md +123 -0
- package/plugin/role-agents/_shared/references/ai-tell-quick-rules.md +1 -1
- package/plugin/role-agents/_shared/references/comment-rules.md +14 -0
- package/plugin/skills/_shared/agent-model.md +15 -0
- package/plugin/skills/blast-radius/SKILL.md +31 -0
- package/plugin/skills/diff-radius/SKILL.md +1 -1
- package/plugin/skills/execute/SKILL.md +15 -0
- package/plugin/skills/local-pr/SKILL.md +201 -0
- package/plugin/skills/pr/SKILL.md +73 -4
- package/plugin/skills/review/SKILL.md +236 -22
- package/plugin/skills/review-reply/SKILL.md +160 -7
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { PR_AGGREGATE } from './types.js';
|
|
2
|
+
/** 이 도메인이 쓰는 이벤트 이름 */
|
|
3
|
+
export const PrEvent = {
|
|
4
|
+
CREATED: 'pr.created',
|
|
5
|
+
UPDATED: 'pr.updated',
|
|
6
|
+
EDITED: 'pr.edited',
|
|
7
|
+
COMMENT_ADDED: 'pr.comment.added',
|
|
8
|
+
COMMENT_RESOLVED: 'pr.comment.resolved',
|
|
9
|
+
REVIEW_SUBMITTED: 'pr.review.submitted',
|
|
10
|
+
MERGED: 'pr.merged',
|
|
11
|
+
CLOSED: 'pr.closed',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* 이벤트를 접어 PR 상태를 만든다.
|
|
15
|
+
*
|
|
16
|
+
* 상태를 따로 저장하지 않아서 DB를 지우고 이벤트만 남아도 같은 결과가 나온다.
|
|
17
|
+
* ExecuteSessionRepository가 쓰는 방식과 같다.
|
|
18
|
+
*/
|
|
19
|
+
export class PullRequestRepository {
|
|
20
|
+
eventStore;
|
|
21
|
+
constructor(eventStore) {
|
|
22
|
+
this.eventStore = eventStore;
|
|
23
|
+
}
|
|
24
|
+
reconstruct(prId) {
|
|
25
|
+
const events = this.eventStore.replay(PR_AGGREGATE, prId);
|
|
26
|
+
if (events.length === 0)
|
|
27
|
+
return null;
|
|
28
|
+
return this.fold(prId, events);
|
|
29
|
+
}
|
|
30
|
+
list() {
|
|
31
|
+
return this.eventStore.listAggregates(PR_AGGREGATE);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 모든 PR을 한 번의 조회로 만든다.
|
|
35
|
+
*
|
|
36
|
+
* id를 훑어 하나씩 replay하면 PR 수만큼 쿼리가 나간다. 목록 화면과 CLI list가
|
|
37
|
+
* 부르는 자리라 PR이 늘수록 그대로 느려진다.
|
|
38
|
+
*/
|
|
39
|
+
reconstructAll() {
|
|
40
|
+
const grouped = this.eventStore.getAllByAggregateType(PR_AGGREGATE);
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const [id, events] of grouped) {
|
|
43
|
+
const pr = this.fold(id, events);
|
|
44
|
+
if (pr)
|
|
45
|
+
out.push(pr);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 상태별 개수만 센다.
|
|
51
|
+
*
|
|
52
|
+
* 배지 하나 찍자고 PR을 다 접던 자리가 있다. 코멘트와 리뷰와 라운드 배열을 만들고
|
|
53
|
+
* 개수만 읽고 버린다. 여기서는 `foldStatus`로 상태만 정하고 접기를 안 한다.
|
|
54
|
+
*/
|
|
55
|
+
countByStatus() {
|
|
56
|
+
const counts = {
|
|
57
|
+
open: 0,
|
|
58
|
+
changes_requested: 0,
|
|
59
|
+
merged: 0,
|
|
60
|
+
closed: 0,
|
|
61
|
+
};
|
|
62
|
+
for (const events of this.eventStore.getAllByAggregateType(PR_AGGREGATE).values()) {
|
|
63
|
+
const status = this.foldStatus(events);
|
|
64
|
+
if (status)
|
|
65
|
+
counts[status]++;
|
|
66
|
+
}
|
|
67
|
+
return counts;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 이 상태인 PR만 만든다.
|
|
71
|
+
*
|
|
72
|
+
* 먼저 상태만 접어 후보를 좁히고 남은 것만 통째로 접는다. 상태 필터가 붙은 호출은
|
|
73
|
+
* 대부분을 버리는데 버릴 것까지 다 만들어 놓을 이유가 없다.
|
|
74
|
+
*/
|
|
75
|
+
reconstructByStatus(status) {
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const [id, events] of this.eventStore.getAllByAggregateType(PR_AGGREGATE)) {
|
|
78
|
+
if (this.foldStatus(events) !== status)
|
|
79
|
+
continue;
|
|
80
|
+
const pr = this.fold(id, events);
|
|
81
|
+
if (pr)
|
|
82
|
+
out.push(pr);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 상태만 접는다. `fold`가 만드는 것 중 `status` 하나만 나오는 가벼운 갈래다.
|
|
88
|
+
*
|
|
89
|
+
* 상태를 정하는 이벤트는 다섯뿐이다 — created(open), updated(고쳐 올렸으니 다시
|
|
90
|
+
* open), review.submitted(request_changes일 때만), merged, closed. 코멘트를 붙이고
|
|
91
|
+
* 닫는 이벤트는 `comments`와 라운드의 코멘트 수만 건드리고 상태에는 손대지 않는다.
|
|
92
|
+
* approve와 comment 판정도 라운드의 판정만 적고 상태를 안 옮긴다.
|
|
93
|
+
*
|
|
94
|
+
* `pr.edited`도 여기 없다. 일부러 없다 — 본문 오타를 고쳤다고 리뷰어가 내린
|
|
95
|
+
* `changes_requested`가 풀리면 판정이 글자 수정으로 리셋된다. `fold`만 그 이벤트를
|
|
96
|
+
* 읽고 제목과 본문을 갈아 끼운다.
|
|
97
|
+
*
|
|
98
|
+
* 두 갈래가 갈리면 목록과 필터가 어긋난다. `list(status)`가 `list()`를 거른 것과
|
|
99
|
+
* 같은지 보는 테스트가 그 자리를 잡는데, 그 테스트는 approve와 comment 판정을 둘 다
|
|
100
|
+
* 지난다 — 위 문장이 둘을 나란히 적어 두니 밟는 것도 둘이어야 한다.
|
|
101
|
+
*/
|
|
102
|
+
foldStatus(events) {
|
|
103
|
+
let status = null;
|
|
104
|
+
for (const event of events) {
|
|
105
|
+
switch (event.eventType) {
|
|
106
|
+
case PrEvent.CREATED:
|
|
107
|
+
status ??= 'open';
|
|
108
|
+
break;
|
|
109
|
+
case PrEvent.UPDATED:
|
|
110
|
+
if (status === 'changes_requested')
|
|
111
|
+
status = 'open';
|
|
112
|
+
break;
|
|
113
|
+
case PrEvent.REVIEW_SUBMITTED:
|
|
114
|
+
if (event.payload.verdict === 'request_changes') {
|
|
115
|
+
status = 'changes_requested';
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case PrEvent.MERGED:
|
|
119
|
+
status = 'merged';
|
|
120
|
+
break;
|
|
121
|
+
case PrEvent.CLOSED:
|
|
122
|
+
status = 'closed';
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return status;
|
|
129
|
+
}
|
|
130
|
+
fold(prId, events) {
|
|
131
|
+
const created = events.find((e) => e.eventType === PrEvent.CREATED);
|
|
132
|
+
if (!created)
|
|
133
|
+
return null;
|
|
134
|
+
const head = created.payload;
|
|
135
|
+
const pr = {
|
|
136
|
+
id: prId,
|
|
137
|
+
title: head.title,
|
|
138
|
+
body: head.body,
|
|
139
|
+
author: head.author,
|
|
140
|
+
baseSha: head.baseSha,
|
|
141
|
+
headSha: head.headSha,
|
|
142
|
+
headRef: head.headRef,
|
|
143
|
+
baseRef: head.baseRef,
|
|
144
|
+
status: 'open',
|
|
145
|
+
createdAt: created.timestamp,
|
|
146
|
+
updatedAt: created.timestamp,
|
|
147
|
+
comments: [],
|
|
148
|
+
reviews: [],
|
|
149
|
+
rounds: [{ number: 1, openedAt: created.timestamp, verdict: null, commentCount: 0 }],
|
|
150
|
+
};
|
|
151
|
+
for (const event of events) {
|
|
152
|
+
this.apply(pr, event);
|
|
153
|
+
pr.updatedAt = event.timestamp;
|
|
154
|
+
}
|
|
155
|
+
return pr;
|
|
156
|
+
}
|
|
157
|
+
apply(pr, event) {
|
|
158
|
+
switch (event.eventType) {
|
|
159
|
+
case PrEvent.UPDATED: {
|
|
160
|
+
const p = event.payload;
|
|
161
|
+
pr.headSha = p.headSha;
|
|
162
|
+
pr.headRef = p.headRef;
|
|
163
|
+
// 고치고 다시 올렸으니 리뷰를 기다리는 자리로 되돌린다
|
|
164
|
+
if (pr.status === 'changes_requested')
|
|
165
|
+
pr.status = 'open';
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case PrEvent.EDITED: {
|
|
169
|
+
const p = event.payload;
|
|
170
|
+
// 안 실린 항목은 그대로 둔다. 빈 문자열은 "비워라"라서 여기서 걸러지면 안 된다
|
|
171
|
+
if (p.title !== undefined)
|
|
172
|
+
pr.title = p.title;
|
|
173
|
+
if (p.body !== undefined)
|
|
174
|
+
pr.body = p.body;
|
|
175
|
+
// 상태도 라운드도 안 건드린다. 글자를 고친 것이지 리뷰 대상을 옮긴 게 아니다
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case PrEvent.COMMENT_ADDED: {
|
|
179
|
+
const p = event.payload;
|
|
180
|
+
const comment = {
|
|
181
|
+
id: p.commentId,
|
|
182
|
+
author: p.author,
|
|
183
|
+
path: p.path,
|
|
184
|
+
line: p.line,
|
|
185
|
+
body: p.body,
|
|
186
|
+
threadId: p.threadId,
|
|
187
|
+
resolved: false,
|
|
188
|
+
headSha: p.headSha,
|
|
189
|
+
createdAt: event.timestamp,
|
|
190
|
+
...(p.marker ? { marker: p.marker } : {}),
|
|
191
|
+
};
|
|
192
|
+
pr.comments.push(comment);
|
|
193
|
+
currentRound(pr).commentCount++;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case PrEvent.COMMENT_RESOLVED: {
|
|
197
|
+
const p = event.payload;
|
|
198
|
+
// 스레드를 통째로 닫는다. 뿌리만 닫고 답글이 열린 채 남으면 미해결 수가 어긋난다
|
|
199
|
+
const target = pr.comments.find((c) => c.id === p.commentId);
|
|
200
|
+
if (target) {
|
|
201
|
+
for (const c of pr.comments) {
|
|
202
|
+
if (c.threadId === target.threadId)
|
|
203
|
+
c.resolved = true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case PrEvent.REVIEW_SUBMITTED: {
|
|
209
|
+
const p = event.payload;
|
|
210
|
+
const round = currentRound(pr);
|
|
211
|
+
const review = {
|
|
212
|
+
id: p.reviewId,
|
|
213
|
+
reviewer: p.reviewer,
|
|
214
|
+
verdict: p.verdict,
|
|
215
|
+
summary: p.summary,
|
|
216
|
+
round: round.number,
|
|
217
|
+
headSha: p.headSha,
|
|
218
|
+
createdAt: event.timestamp,
|
|
219
|
+
};
|
|
220
|
+
pr.reviews.push(review);
|
|
221
|
+
// comment 판정은 라운드를 닫지 않는다. 의견만 남기는 자리다
|
|
222
|
+
if (p.verdict === 'request_changes') {
|
|
223
|
+
pr.status = 'changes_requested';
|
|
224
|
+
round.verdict = p.verdict;
|
|
225
|
+
pr.rounds.push({
|
|
226
|
+
number: round.number + 1,
|
|
227
|
+
openedAt: event.timestamp,
|
|
228
|
+
verdict: null,
|
|
229
|
+
commentCount: 0,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
else if (p.verdict === 'approve') {
|
|
233
|
+
round.verdict = p.verdict;
|
|
234
|
+
}
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case PrEvent.MERGED:
|
|
238
|
+
pr.status = 'merged';
|
|
239
|
+
break;
|
|
240
|
+
case PrEvent.CLOSED:
|
|
241
|
+
pr.status = 'closed';
|
|
242
|
+
break;
|
|
243
|
+
default:
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function currentRound(pr) {
|
|
249
|
+
return pr.rounds[pr.rounds.length - 1];
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/local-pr/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 로컬 PR 리뷰의 도메인 타입.
|
|
3
|
+
*
|
|
4
|
+
* 원격 GitHub PR은 사람에게 넘기는 자리다. 여기는 에이전트가 쪼갠 작업을 다른
|
|
5
|
+
* 에이전트에게 리뷰받고 주고받는 자리다. 한 작업 단위가 PR 하나다.
|
|
6
|
+
*/
|
|
7
|
+
/** 이벤트 저장소에서 이 도메인을 가리키는 이름 */
|
|
8
|
+
export declare const PR_AGGREGATE = "local-pr";
|
|
9
|
+
export type PrStatus = 'open' | 'changes_requested' | 'merged' | 'closed';
|
|
10
|
+
export type ReviewVerdict = 'approve' | 'request_changes' | 'comment';
|
|
11
|
+
/**
|
|
12
|
+
* 누가 했는지.
|
|
13
|
+
*
|
|
14
|
+
* `claude-code:main`, `codex:worker-2`, `human:tienne` 같은 형태다. 에이전트끼리
|
|
15
|
+
* 주고받는 자리라 작성자와 리뷰어가 갈려야 "누가 짚었고 누가 답했나"가 남는다.
|
|
16
|
+
*/
|
|
17
|
+
export type Actor = string;
|
|
18
|
+
export interface PullRequest {
|
|
19
|
+
id: string;
|
|
20
|
+
title: string;
|
|
21
|
+
body: string;
|
|
22
|
+
author: Actor;
|
|
23
|
+
/** 갈라져 나온 지점. merge-base로 잡는다 */
|
|
24
|
+
baseSha: string;
|
|
25
|
+
/** 지금 리뷰 대상인 커밋. update로 옮겨간다 */
|
|
26
|
+
headSha: string;
|
|
27
|
+
/** head를 만들어낸 브랜치 이름. 지워질 수 있어 참고용이다 */
|
|
28
|
+
headRef: string | null;
|
|
29
|
+
baseRef: string | null;
|
|
30
|
+
status: PrStatus;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
comments: Comment[];
|
|
34
|
+
reviews: Review[];
|
|
35
|
+
rounds: Round[];
|
|
36
|
+
}
|
|
37
|
+
export interface Comment {
|
|
38
|
+
id: string;
|
|
39
|
+
author: Actor;
|
|
40
|
+
path: string;
|
|
41
|
+
/** head 기준 라인. 파일 전반이면 null */
|
|
42
|
+
line: number | null;
|
|
43
|
+
body: string;
|
|
44
|
+
/** 스레드의 첫 코멘트 id. 자기 자신이면 스레드의 뿌리다 */
|
|
45
|
+
threadId: string;
|
|
46
|
+
resolved: boolean;
|
|
47
|
+
/** 이 코멘트가 달린 시점의 head. 이후 update로 라인이 밀렸는지 가린다 */
|
|
48
|
+
headSha: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
/**
|
|
51
|
+
* 이 코멘트를 붙인 자동화가 남긴 자국.
|
|
52
|
+
*
|
|
53
|
+
* 사람이 읽을 내용이 아니라 본문 밖에 둔다. 본문에 실으면 CLI가 평문으로 찍고
|
|
54
|
+
* 웹은 이스케이프해서 화면에 그대로 내보낸다 — 리뷰 코멘트마다 읽을 이유가 없는
|
|
55
|
+
* 해시 줄이 붙는다. 손으로 단 코멘트에는 없다.
|
|
56
|
+
*/
|
|
57
|
+
marker?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface Review {
|
|
60
|
+
id: string;
|
|
61
|
+
reviewer: Actor;
|
|
62
|
+
verdict: ReviewVerdict;
|
|
63
|
+
summary: string;
|
|
64
|
+
/** 이 판정이 속한 라운드 번호 */
|
|
65
|
+
round: number;
|
|
66
|
+
headSha: string;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 리뷰 한 바퀴.
|
|
71
|
+
*
|
|
72
|
+
* 리젝이 새 PR을 만들지 않고 같은 PR에서 라운드를 늘린다. 3차에서 다시 열린 코멘트가
|
|
73
|
+
* 어느 라운드에서 났고 어디서 닫혔는지가 이 단위로 보인다.
|
|
74
|
+
*/
|
|
75
|
+
export interface Round {
|
|
76
|
+
number: number;
|
|
77
|
+
openedAt: string;
|
|
78
|
+
/** 이 라운드를 닫은 판정. 아직 안 닫혔으면 null */
|
|
79
|
+
verdict: ReviewVerdict | null;
|
|
80
|
+
/** 이 라운드에서 새로 달린 코멘트 수 */
|
|
81
|
+
commentCount: number;
|
|
82
|
+
}
|
|
83
|
+
export interface PrCreatedPayload {
|
|
84
|
+
title: string;
|
|
85
|
+
body: string;
|
|
86
|
+
author: Actor;
|
|
87
|
+
baseSha: string;
|
|
88
|
+
headSha: string;
|
|
89
|
+
headRef: string | null;
|
|
90
|
+
baseRef: string | null;
|
|
91
|
+
}
|
|
92
|
+
export interface PrUpdatedPayload {
|
|
93
|
+
headSha: string;
|
|
94
|
+
headRef: string | null;
|
|
95
|
+
}
|
|
96
|
+
export interface CommentAddedPayload {
|
|
97
|
+
commentId: string;
|
|
98
|
+
author: Actor;
|
|
99
|
+
path: string;
|
|
100
|
+
line: number | null;
|
|
101
|
+
body: string;
|
|
102
|
+
threadId: string;
|
|
103
|
+
headSha: string;
|
|
104
|
+
/** 자동화가 남긴 자국. 사람이 단 코멘트에는 없다 */
|
|
105
|
+
marker?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface CommentResolvedPayload {
|
|
108
|
+
commentId: string;
|
|
109
|
+
by: Actor;
|
|
110
|
+
}
|
|
111
|
+
export interface ReviewSubmittedPayload {
|
|
112
|
+
reviewId: string;
|
|
113
|
+
reviewer: Actor;
|
|
114
|
+
verdict: ReviewVerdict;
|
|
115
|
+
summary: string;
|
|
116
|
+
headSha: string;
|
|
117
|
+
}
|
|
118
|
+
export interface PrMergedPayload {
|
|
119
|
+
by: Actor;
|
|
120
|
+
mergeSha: string;
|
|
121
|
+
/**
|
|
122
|
+
* 머지한 시점의 미해결 스레드 수.
|
|
123
|
+
*
|
|
124
|
+
* 코멘트가 아니라 스레드를 센다 — 답글이 달릴수록 수가 늘면 주고받을수록 나빠
|
|
125
|
+
* 보이는 신호가 된다. 계산은 `policy.unresolvedCount` 하나에서 나온다.
|
|
126
|
+
*
|
|
127
|
+
* 승인 게이트가 없어서 막지는 않는다. 대신 "스레드 세 개 남은 채 머지됨"이
|
|
128
|
+
* 이력에 남아야 나중에 그 판단을 되짚을 수 있다.
|
|
129
|
+
*/
|
|
130
|
+
unresolvedCount: number;
|
|
131
|
+
}
|
|
132
|
+
export interface PrClosedPayload {
|
|
133
|
+
by: Actor;
|
|
134
|
+
reason: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 본문(과 제목)을 고친 기록.
|
|
138
|
+
*
|
|
139
|
+
* `PrUpdatedPayload`와 갈라 둔다. head를 옮기는 건 "고쳐서 다시 올렸다"는 뜻이라
|
|
140
|
+
* 리뷰 판정을 되돌리지만 본문 오타를 고친 건 리뷰 대상 코드에 손을 안 댄 것이다.
|
|
141
|
+
* 한 이벤트로 합치면 오타 수정이 `changes_requested`를 `open`으로 풀어 버린다.
|
|
142
|
+
*
|
|
143
|
+
* 안 고친 항목은 아예 안 싣는다. `undefined`가 "그대로 둬라"고, 빈 문자열이
|
|
144
|
+
* "본문을 비워라"다 — 둘을 같은 값으로 두면 본문을 못 지운다.
|
|
145
|
+
*/
|
|
146
|
+
export interface PrEditedPayload {
|
|
147
|
+
by: Actor;
|
|
148
|
+
title?: string;
|
|
149
|
+
body?: string;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/local-pr/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/local-pr/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+BAA+B;AAC/B,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PrWebServerOptions, PrWebServerResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 로컬 PR 웹 UI 파이프라인을 조립한다: LocalPrEngine 생성 → 빈 포트 탐색 →
|
|
4
|
+
* PrWebServer 기동 → (선택) 브라우저 열기.
|
|
5
|
+
*
|
|
6
|
+
* graph-viz/engine.ts와 같은 자리다. graph-viz는 정적 그래프 스냅샷을 한 번 굳혀
|
|
7
|
+
* 넘기지만 여기는 PrWebServer가 매 요청마다 LocalPrEngine을 다시 읽으므로
|
|
8
|
+
* 서버가 떠 있는 동안 달린 코멘트나 판정도 새로고침하면 바로 보인다.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PrWebEngine {
|
|
11
|
+
private server;
|
|
12
|
+
private engines;
|
|
13
|
+
start(opts: PrWebServerOptions): Promise<PrWebServerResult>;
|
|
14
|
+
/** Stop the server and release resources. Safe to call even if never started. */
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 프로세스 하나가 서버를 하나만 띄우도록 공유하는 인스턴스.
|
|
19
|
+
*
|
|
20
|
+
* 아직 부르는 자리가 없다. `pr serve`는 `new PrWebEngine()`으로 직접 만들고 MCP는
|
|
21
|
+
* 이 모듈을 안 가져간다. 여러 표면이 서버를 공유해야 할 때를 위해 남겨 둔 진입점이다.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getPrWebEngine(): PrWebEngine;
|
|
24
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/local-pr-web/engine.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;GAOG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,OAAO,CAAsE;IAE/E,KAAK,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsEjE,iFAAiF;IAC3E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5B;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { findAvailablePort } from '../graph-viz/port-finder.js';
|
|
2
|
+
import { LocalPrEngine } from '../local-pr/engine.js';
|
|
3
|
+
import { listRepos, registerRepo } from '../local-pr/registry.js';
|
|
4
|
+
import { PrWebServer } from './server.js';
|
|
5
|
+
/**
|
|
6
|
+
* 로컬 PR 웹 UI 파이프라인을 조립한다: LocalPrEngine 생성 → 빈 포트 탐색 →
|
|
7
|
+
* PrWebServer 기동 → (선택) 브라우저 열기.
|
|
8
|
+
*
|
|
9
|
+
* graph-viz/engine.ts와 같은 자리다. graph-viz는 정적 그래프 스냅샷을 한 번 굳혀
|
|
10
|
+
* 넘기지만 여기는 PrWebServer가 매 요청마다 LocalPrEngine을 다시 읽으므로
|
|
11
|
+
* 서버가 떠 있는 동안 달린 코멘트나 판정도 새로고침하면 바로 보인다.
|
|
12
|
+
*/
|
|
13
|
+
export class PrWebEngine {
|
|
14
|
+
server = null;
|
|
15
|
+
engines = new Map();
|
|
16
|
+
async start(opts) {
|
|
17
|
+
const { repoRoot, port: preferredPort, openBrowser = true } = opts;
|
|
18
|
+
// 같은 인스턴스로 start를 다시 부를 수 있다. 먼저 걷어내지 않으면 앞서 뜬 서버가
|
|
19
|
+
// 참조에서만 밀려나고 소켓과 포트, SIGINT 리스너는 그대로 남는다
|
|
20
|
+
await this.stop();
|
|
21
|
+
// 지금 자리를 먼저 목록에 넣는다. PR을 한 번도 안 만든 레포에서 serve를 쳐도
|
|
22
|
+
// 자기 레포는 보여야 한다.
|
|
23
|
+
//
|
|
24
|
+
// 여기서 던지는 건 대개 git이다 — .git이 깨졌거나 레포가 아니다. 그 원문을 그대로
|
|
25
|
+
// 올리면 사용자는 rev-parse 실패만 본다. 어느 자리를 못 열었는지로 바꿔 던진다
|
|
26
|
+
let primary;
|
|
27
|
+
try {
|
|
28
|
+
primary = registerRepo(repoRoot);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
throw new Error(`이 레포를 못 열었어요: ${repoRoot}`, { cause: e });
|
|
32
|
+
}
|
|
33
|
+
// 레포 하나가 못 열려도 서버는 떠야 한다. 목록에는 남의 레포가 섞여 있고 그중
|
|
34
|
+
// 하나가 옮겨지거나 .git이 깨졌다고 나머지를 못 보는 건 말이 안 된다.
|
|
35
|
+
// 조용히 빼지는 않는다 — 안 보이는 이유를 알려야 사용자가 고칠 수 있다
|
|
36
|
+
const broken = [];
|
|
37
|
+
for (const repo of listRepos()) {
|
|
38
|
+
try {
|
|
39
|
+
this.engines.set(repo.key, { repo, engine: new LocalPrEngine(repo.path) });
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
broken.push(repo.name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (broken.length > 0) {
|
|
46
|
+
process.stderr.write(`[local-pr-web] 못 연 레포 ${broken.length}개: ${broken.join(', ')}\n`);
|
|
47
|
+
}
|
|
48
|
+
const held = this.engines.get(primary.key);
|
|
49
|
+
if (!held)
|
|
50
|
+
throw new Error(`이 레포를 못 열었어요: ${repoRoot}`);
|
|
51
|
+
const count = held.engine.list().length;
|
|
52
|
+
// 0은 "아무 빈 포트나"라는 뜻이라 탐색할 게 없다. 탐색을 태우면 isPortAvailable(0)이
|
|
53
|
+
// 늘 통과해 0을 그대로 돌려준다. 그 0이 URL에 박혀 죽은 주소가 나간다
|
|
54
|
+
const requested = preferredPort ?? 7892;
|
|
55
|
+
// 여기서부터는 이미 sqlite 핸들이 레포 수만큼 열려 있다. 포트를 못 잡거나 listen이
|
|
56
|
+
// 거부하면 그것들이 참조만 남고 안 닫힌다 — 같은 인스턴스로 재시도하면 누적된다
|
|
57
|
+
let port;
|
|
58
|
+
try {
|
|
59
|
+
port = requested === 0 ? 0 : await findAvailablePort(requested);
|
|
60
|
+
this.server = new PrWebServer(this.engines, primary.key);
|
|
61
|
+
await this.server.start(port);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
await this.stop();
|
|
65
|
+
throw e;
|
|
66
|
+
}
|
|
67
|
+
// listen(0)이면 실제 포트는 OS가 정한다. 요청값이 아니라 뜬 자리를 알려준다
|
|
68
|
+
const actualPort = this.server.port ?? port;
|
|
69
|
+
const url = `http://127.0.0.1:${actualPort}`;
|
|
70
|
+
process.stderr.write(`[local-pr-web] server running at ${url}\n`);
|
|
71
|
+
if (openBrowser) {
|
|
72
|
+
await openUrl(url);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
url,
|
|
76
|
+
port: actualPort,
|
|
77
|
+
message: `로컬 PR 웹 UI가 ${url}에서 돈다 (PR ${count}개)`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** Stop the server and release resources. Safe to call even if never started. */
|
|
81
|
+
async stop() {
|
|
82
|
+
if (this.server) {
|
|
83
|
+
await this.server.stop();
|
|
84
|
+
this.server = null;
|
|
85
|
+
}
|
|
86
|
+
for (const { engine } of this.engines.values())
|
|
87
|
+
engine.dispose();
|
|
88
|
+
this.engines.clear();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let _instance = null;
|
|
92
|
+
/**
|
|
93
|
+
* 프로세스 하나가 서버를 하나만 띄우도록 공유하는 인스턴스.
|
|
94
|
+
*
|
|
95
|
+
* 아직 부르는 자리가 없다. `pr serve`는 `new PrWebEngine()`으로 직접 만들고 MCP는
|
|
96
|
+
* 이 모듈을 안 가져간다. 여러 표면이 서버를 공유해야 할 때를 위해 남겨 둔 진입점이다.
|
|
97
|
+
*/
|
|
98
|
+
export function getPrWebEngine() {
|
|
99
|
+
if (!_instance)
|
|
100
|
+
_instance = new PrWebEngine();
|
|
101
|
+
return _instance;
|
|
102
|
+
}
|
|
103
|
+
async function openUrl(url) {
|
|
104
|
+
try {
|
|
105
|
+
const { default: open } = await import('open');
|
|
106
|
+
await open(url);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
process.stderr.write(`[local-pr-web] could not open browser automatically: ${err.message}\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/local-pr-web/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PullRequest } from '../local-pr/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 로컬 PR 웹 UI의 HTML을 만드는 순수 함수 모음.
|
|
4
|
+
*
|
|
5
|
+
* graph-viz/html-generator.ts와 같은 자리다 — 프레임워크 없이 문자열을 이어 붙여
|
|
6
|
+
* 자기완결적인 HTML을 만든다. 다른 점은 여기 들어가는 텍스트(제목, 코멘트 본문)는
|
|
7
|
+
* 전부 리뷰어가 입력한 신뢰할 수 없는 값이라는 것이다. escapeHtml을 거치지 않은
|
|
8
|
+
* 텍스트를 그대로 꽂으면 코멘트에 심은 `<script>`가 브라우저에서 그대로 실행된다.
|
|
9
|
+
*/
|
|
10
|
+
/** HTML 텍스트 노드/속성에 안전하게 꽂도록 이스케이프한다 */
|
|
11
|
+
export declare function escapeHtml(input: string): string;
|
|
12
|
+
export declare function toEmbeddableJson(value: unknown): string;
|
|
13
|
+
export interface RepoTab {
|
|
14
|
+
key: string;
|
|
15
|
+
name: string;
|
|
16
|
+
active: boolean;
|
|
17
|
+
/** 아직 안 닫힌 PR 수. 어디에 일이 쌓였는지 한눈에 보이라고 함께 그린다 */
|
|
18
|
+
openCount: number;
|
|
19
|
+
}
|
|
20
|
+
/** `GET /r/:key` — PR 목록 페이지 */
|
|
21
|
+
export declare function generatePrListHtml(prs: PullRequest[], repos?: RepoTab[]): string;
|
|
22
|
+
/** `GET /prs/:id` — diff와 코멘트 스레드, 라운드별 판정 이력 */
|
|
23
|
+
export declare function generatePrDetailHtml(pr: PullRequest, diff: string, repoKey?: string, repoName?: string, nonce?: string): string;
|
|
24
|
+
//# sourceMappingURL=html-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-generator.d.ts","sourceRoot":"","sources":["../../../src/local-pr-web/html-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,sBAAsB,CAAC;AAEhE;;;;;;;GAOG;AAEH,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOhD;AAgBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIvD;AAwKD,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB;AAuBD,gCAAgC;AAChC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,KAAK,GAAE,OAAO,EAAO,GAAG,MAAM,CAmCpF;AA6DD,iDAAiD;AACjD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,SAAK,EACZ,QAAQ,SAAK,EACb,KAAK,SAAK,GACT,MAAM,CA+FR"}
|