diffprism 0.34.1 → 0.35.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/dist/bin.js +126 -224
- package/dist/chunk-DHCVZGHE.js +501 -0
- package/dist/chunk-JSBRDJBE.js +30 -0
- package/dist/{chunk-VASCXEMN.js → chunk-LUUR6LNP.js} +307 -1801
- package/dist/chunk-QGWYCEJN.js +448 -0
- package/dist/mcp-server.js +75 -280
- package/dist/src-AMCPIYDZ.js +19 -0
- package/dist/src-JMPTSU3P.js +27 -0
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -1,119 +1,33 @@
|
|
|
1
1
|
import {
|
|
2
|
-
analyze,
|
|
3
|
-
consumeReviewResult,
|
|
4
2
|
createGitHubClient,
|
|
5
|
-
|
|
3
|
+
ensureServer,
|
|
6
4
|
fetchPullRequest,
|
|
7
5
|
fetchPullRequestDiff,
|
|
8
|
-
getCurrentBranch,
|
|
9
|
-
getDiff,
|
|
10
6
|
isServerAlive,
|
|
11
7
|
normalizePr,
|
|
12
8
|
parsePrRef,
|
|
13
|
-
readReviewResult,
|
|
14
|
-
readWatchFile,
|
|
15
9
|
resolveGitHubToken,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./chunk-
|
|
10
|
+
submitGitHubReview,
|
|
11
|
+
submitReviewToServer
|
|
12
|
+
} from "./chunk-LUUR6LNP.js";
|
|
13
|
+
import {
|
|
14
|
+
getDiff
|
|
15
|
+
} from "./chunk-QGWYCEJN.js";
|
|
16
|
+
import {
|
|
17
|
+
analyze
|
|
18
|
+
} from "./chunk-DHCVZGHE.js";
|
|
19
|
+
import "./chunk-JSBRDJBE.js";
|
|
19
20
|
|
|
20
21
|
// packages/mcp-server/src/index.ts
|
|
21
|
-
import fs from "fs";
|
|
22
|
-
import path from "path";
|
|
23
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
24
23
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
24
|
import { z } from "zod";
|
|
26
25
|
var lastGlobalSessionId = null;
|
|
27
26
|
var lastGlobalServerInfo = null;
|
|
28
|
-
async function reviewViaGlobalServer(serverInfo, diffRef, options) {
|
|
29
|
-
const cwd = options.cwd ?? process.cwd();
|
|
30
|
-
const { diffSet, rawDiff } = getDiff(diffRef, { cwd });
|
|
31
|
-
const currentBranch = getCurrentBranch({ cwd });
|
|
32
|
-
if (diffSet.files.length === 0) {
|
|
33
|
-
return {
|
|
34
|
-
decision: "approved",
|
|
35
|
-
comments: [],
|
|
36
|
-
summary: "No changes to review."
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const briefing = analyze(diffSet);
|
|
40
|
-
const worktreeInfo = detectWorktree({ cwd });
|
|
41
|
-
const payload = {
|
|
42
|
-
reviewId: "",
|
|
43
|
-
// Server assigns the real ID
|
|
44
|
-
diffSet,
|
|
45
|
-
rawDiff,
|
|
46
|
-
briefing,
|
|
47
|
-
metadata: {
|
|
48
|
-
title: options.title,
|
|
49
|
-
description: options.description,
|
|
50
|
-
reasoning: options.reasoning,
|
|
51
|
-
currentBranch,
|
|
52
|
-
worktree: worktreeInfo.isWorktree ? {
|
|
53
|
-
isWorktree: true,
|
|
54
|
-
worktreePath: worktreeInfo.worktreePath,
|
|
55
|
-
mainWorktreePath: worktreeInfo.mainWorktreePath
|
|
56
|
-
} : void 0
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const createResponse = await fetch(
|
|
60
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews`,
|
|
61
|
-
{
|
|
62
|
-
method: "POST",
|
|
63
|
-
headers: { "Content-Type": "application/json" },
|
|
64
|
-
body: JSON.stringify({ payload, projectPath: cwd, diffRef })
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
if (!createResponse.ok) {
|
|
68
|
-
throw new Error(`Global server returned ${createResponse.status} on create`);
|
|
69
|
-
}
|
|
70
|
-
const { sessionId } = await createResponse.json();
|
|
71
|
-
lastGlobalSessionId = sessionId;
|
|
72
|
-
lastGlobalServerInfo = serverInfo;
|
|
73
|
-
if (options.annotations?.length) {
|
|
74
|
-
for (const ann of options.annotations) {
|
|
75
|
-
await fetch(
|
|
76
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/annotations`,
|
|
77
|
-
{
|
|
78
|
-
method: "POST",
|
|
79
|
-
headers: { "Content-Type": "application/json" },
|
|
80
|
-
body: JSON.stringify({
|
|
81
|
-
file: ann.file,
|
|
82
|
-
line: ann.line,
|
|
83
|
-
body: ann.body,
|
|
84
|
-
type: ann.type,
|
|
85
|
-
confidence: ann.confidence ?? 1,
|
|
86
|
-
category: ann.category ?? "other",
|
|
87
|
-
source: {
|
|
88
|
-
agent: ann.source_agent ?? "unknown",
|
|
89
|
-
tool: "open_review"
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const pollIntervalMs = 2e3;
|
|
97
|
-
const maxWaitMs = 600 * 1e3;
|
|
98
|
-
const start = Date.now();
|
|
99
|
-
while (Date.now() - start < maxWaitMs) {
|
|
100
|
-
const resultResponse = await fetch(
|
|
101
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/result`
|
|
102
|
-
);
|
|
103
|
-
if (resultResponse.ok) {
|
|
104
|
-
const data = await resultResponse.json();
|
|
105
|
-
if (data.result) {
|
|
106
|
-
return data.result;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
110
|
-
}
|
|
111
|
-
throw new Error("Review timed out waiting for submission.");
|
|
112
|
-
}
|
|
113
27
|
async function startMcpServer() {
|
|
114
28
|
const server = new McpServer({
|
|
115
29
|
name: "diffprism",
|
|
116
|
-
version: true ? "0.
|
|
30
|
+
version: true ? "0.35.0" : "0.0.0-dev"
|
|
117
31
|
});
|
|
118
32
|
server.tool(
|
|
119
33
|
"open_review",
|
|
@@ -148,36 +62,21 @@ async function startMcpServer() {
|
|
|
148
62
|
},
|
|
149
63
|
async ({ diff_ref, title, description, reasoning, annotations }) => {
|
|
150
64
|
try {
|
|
151
|
-
const serverInfo = await
|
|
152
|
-
|
|
153
|
-
|
|
65
|
+
const serverInfo = await ensureServer({ silent: true });
|
|
66
|
+
const { result, sessionId } = await submitReviewToServer(
|
|
67
|
+
serverInfo,
|
|
68
|
+
diff_ref,
|
|
69
|
+
{
|
|
154
70
|
title,
|
|
155
71
|
description,
|
|
156
72
|
reasoning,
|
|
157
73
|
cwd: process.cwd(),
|
|
158
|
-
annotations
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
content: [
|
|
162
|
-
{
|
|
163
|
-
type: "text",
|
|
164
|
-
text: JSON.stringify(result2, null, 2)
|
|
165
|
-
}
|
|
166
|
-
]
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
const isDev = fs.existsSync(
|
|
170
|
-
path.join(process.cwd(), "packages", "ui", "src", "App.tsx")
|
|
74
|
+
annotations,
|
|
75
|
+
diffRef: diff_ref
|
|
76
|
+
}
|
|
171
77
|
);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
title,
|
|
175
|
-
description,
|
|
176
|
-
reasoning,
|
|
177
|
-
cwd: process.cwd(),
|
|
178
|
-
silent: true,
|
|
179
|
-
dev: isDev
|
|
180
|
-
});
|
|
78
|
+
lastGlobalSessionId = sessionId;
|
|
79
|
+
lastGlobalServerInfo = serverInfo;
|
|
181
80
|
return {
|
|
182
81
|
content: [
|
|
183
82
|
{
|
|
@@ -202,7 +101,7 @@ async function startMcpServer() {
|
|
|
202
101
|
);
|
|
203
102
|
server.tool(
|
|
204
103
|
"update_review_context",
|
|
205
|
-
"Push reasoning/context to a running DiffPrism review session. Non-blocking \u2014 returns immediately.
|
|
104
|
+
"Push reasoning/context to a running DiffPrism review session. Non-blocking \u2014 returns immediately. Updates the review UI with agent reasoning without opening a new review. Requires a prior `open_review` call in this session.",
|
|
206
105
|
{
|
|
207
106
|
reasoning: z.string().optional().describe("Agent reasoning about the current changes"),
|
|
208
107
|
title: z.string().optional().describe("Updated title for the review"),
|
|
@@ -214,42 +113,19 @@ async function startMcpServer() {
|
|
|
214
113
|
if (reasoning !== void 0) payload.reasoning = reasoning;
|
|
215
114
|
if (title !== void 0) payload.title = title;
|
|
216
115
|
if (description !== void 0) payload.description = description;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (serverInfo) {
|
|
220
|
-
const response2 = await fetch(
|
|
221
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${lastGlobalSessionId}/context`,
|
|
222
|
-
{
|
|
223
|
-
method: "POST",
|
|
224
|
-
headers: { "Content-Type": "application/json" },
|
|
225
|
-
body: JSON.stringify(payload)
|
|
226
|
-
}
|
|
227
|
-
);
|
|
228
|
-
if (response2.ok) {
|
|
229
|
-
return {
|
|
230
|
-
content: [
|
|
231
|
-
{
|
|
232
|
-
type: "text",
|
|
233
|
-
text: "Context updated in DiffPrism global server session."
|
|
234
|
-
}
|
|
235
|
-
]
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const watchInfo = readWatchFile();
|
|
241
|
-
if (!watchInfo) {
|
|
116
|
+
const serverInfo = lastGlobalServerInfo ?? await isServerAlive();
|
|
117
|
+
if (!serverInfo || !lastGlobalSessionId) {
|
|
242
118
|
return {
|
|
243
119
|
content: [
|
|
244
120
|
{
|
|
245
121
|
type: "text",
|
|
246
|
-
text: "No DiffPrism session is running.
|
|
122
|
+
text: "No DiffPrism session is running. Use `open_review` to start a review."
|
|
247
123
|
}
|
|
248
124
|
]
|
|
249
125
|
};
|
|
250
126
|
}
|
|
251
127
|
const response = await fetch(
|
|
252
|
-
`http://localhost:${
|
|
128
|
+
`http://localhost:${serverInfo.httpPort}/api/reviews/${lastGlobalSessionId}/context`,
|
|
253
129
|
{
|
|
254
130
|
method: "POST",
|
|
255
131
|
headers: { "Content-Type": "application/json" },
|
|
@@ -257,13 +133,13 @@ async function startMcpServer() {
|
|
|
257
133
|
}
|
|
258
134
|
);
|
|
259
135
|
if (!response.ok) {
|
|
260
|
-
throw new Error(`
|
|
136
|
+
throw new Error(`Server returned ${response.status}`);
|
|
261
137
|
}
|
|
262
138
|
return {
|
|
263
139
|
content: [
|
|
264
140
|
{
|
|
265
141
|
type: "text",
|
|
266
|
-
text: "Context updated in DiffPrism
|
|
142
|
+
text: "Context updated in DiffPrism session."
|
|
267
143
|
}
|
|
268
144
|
]
|
|
269
145
|
};
|
|
@@ -283,7 +159,7 @@ async function startMcpServer() {
|
|
|
283
159
|
);
|
|
284
160
|
server.tool(
|
|
285
161
|
"get_review_result",
|
|
286
|
-
"Fetch the most recent review result from a DiffPrism session. Returns the reviewer's decision and comments if a review has been submitted, or a message indicating no pending result.
|
|
162
|
+
"Fetch the most recent review result from a DiffPrism session. Returns the reviewer's decision and comments if a review has been submitted, or a message indicating no pending result. Use wait=true to block until a result is available. Note: `open_review` already blocks and returns the result \u2014 this tool is only needed for advanced workflows where you want to check results separately.",
|
|
287
163
|
{
|
|
288
164
|
wait: z.boolean().optional().describe("If true, poll until a review result is available (blocks up to timeout)"),
|
|
289
165
|
timeout: z.number().optional().describe("Max wait time in seconds when wait=true (default: 300, max: 600)")
|
|
@@ -292,80 +168,36 @@ async function startMcpServer() {
|
|
|
292
168
|
try {
|
|
293
169
|
const maxWaitMs = Math.min(timeout ?? 300, 600) * 1e3;
|
|
294
170
|
const pollIntervalMs = 2e3;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${lastGlobalSessionId}/result`
|
|
303
|
-
);
|
|
304
|
-
if (response2.ok) {
|
|
305
|
-
const data2 = await response2.json();
|
|
306
|
-
if (data2.result) {
|
|
307
|
-
return {
|
|
308
|
-
content: [
|
|
309
|
-
{
|
|
310
|
-
type: "text",
|
|
311
|
-
text: JSON.stringify(data2.result, null, 2)
|
|
312
|
-
}
|
|
313
|
-
]
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
171
|
+
const serverInfo = lastGlobalServerInfo ?? await isServerAlive();
|
|
172
|
+
if (!serverInfo || !lastGlobalSessionId) {
|
|
173
|
+
return {
|
|
174
|
+
content: [
|
|
175
|
+
{
|
|
176
|
+
type: "text",
|
|
177
|
+
text: "No DiffPrism session is running. Use `open_review` to start a review."
|
|
318
178
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
const response = await fetch(
|
|
179
|
+
]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (wait) {
|
|
183
|
+
const start = Date.now();
|
|
184
|
+
while (Date.now() - start < maxWaitMs) {
|
|
185
|
+
const response2 = await fetch(
|
|
329
186
|
`http://localhost:${serverInfo.httpPort}/api/reviews/${lastGlobalSessionId}/result`
|
|
330
187
|
);
|
|
331
|
-
if (
|
|
332
|
-
const
|
|
333
|
-
if (
|
|
188
|
+
if (response2.ok) {
|
|
189
|
+
const data = await response2.json();
|
|
190
|
+
if (data.result) {
|
|
334
191
|
return {
|
|
335
192
|
content: [
|
|
336
193
|
{
|
|
337
194
|
type: "text",
|
|
338
|
-
text: JSON.stringify(
|
|
195
|
+
text: JSON.stringify(data.result, null, 2)
|
|
339
196
|
}
|
|
340
197
|
]
|
|
341
198
|
};
|
|
342
199
|
}
|
|
343
200
|
}
|
|
344
|
-
return {
|
|
345
|
-
content: [
|
|
346
|
-
{
|
|
347
|
-
type: "text",
|
|
348
|
-
text: "No pending review result."
|
|
349
|
-
}
|
|
350
|
-
]
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
if (wait) {
|
|
355
|
-
const start = Date.now();
|
|
356
|
-
while (Date.now() - start < maxWaitMs) {
|
|
357
|
-
const data2 = readReviewResult();
|
|
358
|
-
if (data2) {
|
|
359
|
-
consumeReviewResult();
|
|
360
|
-
return {
|
|
361
|
-
content: [
|
|
362
|
-
{
|
|
363
|
-
type: "text",
|
|
364
|
-
text: JSON.stringify(data2.result, null, 2)
|
|
365
|
-
}
|
|
366
|
-
]
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
201
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
370
202
|
}
|
|
371
203
|
return {
|
|
@@ -377,23 +209,27 @@ async function startMcpServer() {
|
|
|
377
209
|
]
|
|
378
210
|
};
|
|
379
211
|
}
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
212
|
+
const response = await fetch(
|
|
213
|
+
`http://localhost:${serverInfo.httpPort}/api/reviews/${lastGlobalSessionId}/result`
|
|
214
|
+
);
|
|
215
|
+
if (response.ok) {
|
|
216
|
+
const data = await response.json();
|
|
217
|
+
if (data.result) {
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: "text",
|
|
222
|
+
text: JSON.stringify(data.result, null, 2)
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
};
|
|
226
|
+
}
|
|
390
227
|
}
|
|
391
|
-
consumeReviewResult();
|
|
392
228
|
return {
|
|
393
229
|
content: [
|
|
394
230
|
{
|
|
395
231
|
type: "text",
|
|
396
|
-
text:
|
|
232
|
+
text: "No pending review result."
|
|
397
233
|
}
|
|
398
234
|
]
|
|
399
235
|
};
|
|
@@ -814,59 +650,18 @@ async function startMcpServer() {
|
|
|
814
650
|
};
|
|
815
651
|
}
|
|
816
652
|
const { payload } = normalizePr(rawDiff, prMetadata, { title, reasoning });
|
|
817
|
-
const serverInfo = await
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
body: JSON.stringify({
|
|
826
|
-
payload,
|
|
827
|
-
projectPath: `github:${owner}/${repo}`,
|
|
828
|
-
diffRef: `PR #${number}`
|
|
829
|
-
})
|
|
830
|
-
}
|
|
831
|
-
);
|
|
832
|
-
if (!createResponse.ok) {
|
|
833
|
-
throw new Error(`Global server returned ${createResponse.status}`);
|
|
834
|
-
}
|
|
835
|
-
const { sessionId } = await createResponse.json();
|
|
836
|
-
lastGlobalSessionId = sessionId;
|
|
837
|
-
lastGlobalServerInfo = serverInfo;
|
|
838
|
-
const pollIntervalMs = 2e3;
|
|
839
|
-
const maxWaitMs = 600 * 1e3;
|
|
840
|
-
const start = Date.now();
|
|
841
|
-
while (Date.now() - start < maxWaitMs) {
|
|
842
|
-
const resultResponse = await fetch(
|
|
843
|
-
`http://localhost:${serverInfo.httpPort}/api/reviews/${sessionId}/result`
|
|
844
|
-
);
|
|
845
|
-
if (resultResponse.ok) {
|
|
846
|
-
const data = await resultResponse.json();
|
|
847
|
-
if (data.result) {
|
|
848
|
-
result = data.result;
|
|
849
|
-
break;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
653
|
+
const serverInfo = await ensureServer({ silent: true });
|
|
654
|
+
const { result, sessionId } = await submitReviewToServer(
|
|
655
|
+
serverInfo,
|
|
656
|
+
`PR #${number}`,
|
|
657
|
+
{
|
|
658
|
+
injectedPayload: payload,
|
|
659
|
+
projectPath: `github:${owner}/${repo}`,
|
|
660
|
+
diffRef: `PR #${number}`
|
|
853
661
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
path.join(process.cwd(), "packages", "ui", "src", "App.tsx")
|
|
858
|
-
);
|
|
859
|
-
result = await startReview({
|
|
860
|
-
diffRef: `PR #${number}`,
|
|
861
|
-
title: payload.metadata.title,
|
|
862
|
-
description: payload.metadata.description,
|
|
863
|
-
reasoning: payload.metadata.reasoning,
|
|
864
|
-
cwd: process.cwd(),
|
|
865
|
-
silent: true,
|
|
866
|
-
dev: isDev,
|
|
867
|
-
injectedPayload: payload
|
|
868
|
-
});
|
|
869
|
-
}
|
|
662
|
+
);
|
|
663
|
+
lastGlobalSessionId = sessionId;
|
|
664
|
+
lastGlobalServerInfo = serverInfo;
|
|
870
665
|
if ((post_to_github || result.postToGithub) && result.decision !== "dismissed") {
|
|
871
666
|
const posted = await submitGitHubReview(client, owner, repo, number, result);
|
|
872
667
|
if (posted) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectWorktree,
|
|
3
|
+
getCurrentBranch,
|
|
4
|
+
getDiff,
|
|
5
|
+
getGitDiff,
|
|
6
|
+
listBranches,
|
|
7
|
+
listCommits,
|
|
8
|
+
parseDiff
|
|
9
|
+
} from "./chunk-QGWYCEJN.js";
|
|
10
|
+
import "./chunk-JSBRDJBE.js";
|
|
11
|
+
export {
|
|
12
|
+
detectWorktree,
|
|
13
|
+
getCurrentBranch,
|
|
14
|
+
getDiff,
|
|
15
|
+
getGitDiff,
|
|
16
|
+
listBranches,
|
|
17
|
+
listCommits,
|
|
18
|
+
parseDiff
|
|
19
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyze,
|
|
3
|
+
categorizeFiles,
|
|
4
|
+
computeComplexityScores,
|
|
5
|
+
computeFileStats,
|
|
6
|
+
detectAffectedModules,
|
|
7
|
+
detectAffectedTests,
|
|
8
|
+
detectNewDependencies,
|
|
9
|
+
detectPatterns,
|
|
10
|
+
detectSecurityPatterns,
|
|
11
|
+
detectTestCoverageGaps,
|
|
12
|
+
generateSummary
|
|
13
|
+
} from "./chunk-DHCVZGHE.js";
|
|
14
|
+
import "./chunk-JSBRDJBE.js";
|
|
15
|
+
export {
|
|
16
|
+
analyze,
|
|
17
|
+
categorizeFiles,
|
|
18
|
+
computeComplexityScores,
|
|
19
|
+
computeFileStats,
|
|
20
|
+
detectAffectedModules,
|
|
21
|
+
detectAffectedTests,
|
|
22
|
+
detectNewDependencies,
|
|
23
|
+
detectPatterns,
|
|
24
|
+
detectSecurityPatterns,
|
|
25
|
+
detectTestCoverageGaps,
|
|
26
|
+
generateSummary
|
|
27
|
+
};
|