@codesherlock/codesherlock-beta-mcp-server 0.0.1
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/.env +9 -0
- package/README.md +185 -0
- package/build/handlers/analyzeCommitHandler.d.ts +36 -0
- package/build/handlers/analyzeCommitHandler.d.ts.map +1 -0
- package/build/handlers/analyzeCommitHandler.js +397 -0
- package/build/handlers/analyzeCommitHandler.js.map +1 -0
- package/build/handlers/events.d.ts +7 -0
- package/build/handlers/events.d.ts.map +1 -0
- package/build/handlers/events.js +15 -0
- package/build/handlers/events.js.map +1 -0
- package/build/handlers/resources.d.ts +10 -0
- package/build/handlers/resources.d.ts.map +1 -0
- package/build/handlers/resources.js +14 -0
- package/build/handlers/resources.js.map +1 -0
- package/build/handlers/tools.d.ts +6 -0
- package/build/handlers/tools.d.ts.map +1 -0
- package/build/handlers/tools.js +29 -0
- package/build/handlers/tools.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +82 -0
- package/build/index.js.map +1 -0
- package/build/schemas/toolSchemas.d.ts +50 -0
- package/build/schemas/toolSchemas.d.ts.map +1 -0
- package/build/schemas/toolSchemas.js +48 -0
- package/build/schemas/toolSchemas.js.map +1 -0
- package/build/services/backendApiService.d.ts +81 -0
- package/build/services/backendApiService.d.ts.map +1 -0
- package/build/services/backendApiService.js +265 -0
- package/build/services/backendApiService.js.map +1 -0
- package/build/services/commitReviewService.d.ts +71 -0
- package/build/services/commitReviewService.d.ts.map +1 -0
- package/build/services/commitReviewService.js +506 -0
- package/build/services/commitReviewService.js.map +1 -0
- package/build/services/gitService.d.ts +159 -0
- package/build/services/gitService.d.ts.map +1 -0
- package/build/services/gitService.js +778 -0
- package/build/services/gitService.js.map +1 -0
- package/build/services/loggingService.d.ts +64 -0
- package/build/services/loggingService.d.ts.map +1 -0
- package/build/services/loggingService.js +185 -0
- package/build/services/loggingService.js.map +1 -0
- package/build/services/zipService.d.ts +9 -0
- package/build/services/zipService.d.ts.map +1 -0
- package/build/services/zipService.js +47 -0
- package/build/services/zipService.js.map +1 -0
- package/build/tests/analysisFormatter.test.d.ts +2 -0
- package/build/tests/analysisFormatter.test.d.ts.map +1 -0
- package/build/tests/analysisFormatter.test.js +92 -0
- package/build/tests/analysisFormatter.test.js.map +1 -0
- package/build/tests/analyzeCommitHandler.test.d.ts +2 -0
- package/build/tests/analyzeCommitHandler.test.d.ts.map +1 -0
- package/build/tests/analyzeCommitHandler.test.js +111 -0
- package/build/tests/analyzeCommitHandler.test.js.map +1 -0
- package/build/tests/backendApiService.test.d.ts +2 -0
- package/build/tests/backendApiService.test.d.ts.map +1 -0
- package/build/tests/backendApiService.test.js +109 -0
- package/build/tests/backendApiService.test.js.map +1 -0
- package/build/tests/commitReviewService.test.d.ts +2 -0
- package/build/tests/commitReviewService.test.d.ts.map +1 -0
- package/build/tests/commitReviewService.test.js +120 -0
- package/build/tests/commitReviewService.test.js.map +1 -0
- package/build/tests/errorExtractor.test.d.ts +2 -0
- package/build/tests/errorExtractor.test.d.ts.map +1 -0
- package/build/tests/errorExtractor.test.js +61 -0
- package/build/tests/errorExtractor.test.js.map +1 -0
- package/build/tests/loggingService.test.d.ts +2 -0
- package/build/tests/loggingService.test.d.ts.map +1 -0
- package/build/tests/loggingService.test.js +153 -0
- package/build/tests/loggingService.test.js.map +1 -0
- package/build/tests/setup.test.d.ts +2 -0
- package/build/tests/setup.test.d.ts.map +1 -0
- package/build/tests/setup.test.js +7 -0
- package/build/tests/setup.test.js.map +1 -0
- package/build/tests/tools.test.d.ts +2 -0
- package/build/tests/tools.test.d.ts.map +1 -0
- package/build/tests/tools.test.js +58 -0
- package/build/tests/tools.test.js.map +1 -0
- package/build/utils/analysisFormatter.d.ts +40 -0
- package/build/utils/analysisFormatter.d.ts.map +1 -0
- package/build/utils/analysisFormatter.js +97 -0
- package/build/utils/analysisFormatter.js.map +1 -0
- package/build/utils/errorExtractor.d.ts +36 -0
- package/build/utils/errorExtractor.d.ts.map +1 -0
- package/build/utils/errorExtractor.js +178 -0
- package/build/utils/errorExtractor.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { logger } from "./loggingService.js";
|
|
2
|
+
import WebSocket from "ws";
|
|
3
|
+
/**
|
|
4
|
+
* Commit Review Service
|
|
5
|
+
* Handles the full flow of submitting commit review and receiving results via WebSocket
|
|
6
|
+
*/
|
|
7
|
+
export class CommitReviewService {
|
|
8
|
+
backendApiService;
|
|
9
|
+
constructor(backendApiService) {
|
|
10
|
+
this.backendApiService = backendApiService;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Submit commit review and wait for analysis results via WebSocket
|
|
14
|
+
* @param params - Commit review parameters
|
|
15
|
+
* @returns Analysis results
|
|
16
|
+
*/
|
|
17
|
+
async submitAndWaitForResults(params) {
|
|
18
|
+
let wsConnection;
|
|
19
|
+
try {
|
|
20
|
+
// IMPORTANT: Establish WebSocket connection (and listeners) BEFORE
|
|
21
|
+
// calling the backend HTTP API so we don't miss any early messages.
|
|
22
|
+
logger.logInfo("Step 1: Establishing WebSocket connection BEFORE submitting review", {
|
|
23
|
+
user_id: params.user_id,
|
|
24
|
+
});
|
|
25
|
+
// Step 1: Establish WebSocket connection FIRST and wait for it to be fully connected
|
|
26
|
+
const wsConnectionPromise = new Promise((resolve, reject) => {
|
|
27
|
+
this.backendApiService.connectWebSocket(params.user_id, () => { }, // onMessage will be handled by collectResultsViaWebSocket
|
|
28
|
+
(error) => {
|
|
29
|
+
logger.logError("WebSocket connection failed before submit", error, { user_id: params.user_id });
|
|
30
|
+
reject(error);
|
|
31
|
+
}, () => { } // onClose will be handled by collectResultsViaWebSocket
|
|
32
|
+
).then((ws) => {
|
|
33
|
+
// Verify WebSocket is actually open
|
|
34
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
35
|
+
wsConnection = ws;
|
|
36
|
+
logger.logInfo("✅ WebSocket connection fully established and verified OPEN", {
|
|
37
|
+
user_id: params.user_id,
|
|
38
|
+
readyState: String(ws.readyState)
|
|
39
|
+
});
|
|
40
|
+
resolve(ws);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const error = new Error(`WebSocket connection not fully open. ReadyState: ${ws.readyState}`);
|
|
44
|
+
logger.logError("❌ WebSocket not in OPEN state", error, {
|
|
45
|
+
user_id: params.user_id,
|
|
46
|
+
readyState: String(ws.readyState)
|
|
47
|
+
});
|
|
48
|
+
reject(error);
|
|
49
|
+
}
|
|
50
|
+
}).catch(reject);
|
|
51
|
+
});
|
|
52
|
+
// CRITICAL: Wait for WebSocket to be fully connected before proceeding
|
|
53
|
+
const establishedWs = await wsConnectionPromise;
|
|
54
|
+
logger.logInfo("✅ WebSocket connection confirmed OPEN, proceeding with HTTP call", {
|
|
55
|
+
user_id: params.user_id,
|
|
56
|
+
});
|
|
57
|
+
// Step 2: Start collecting results via WebSocket (reuse the established connection)
|
|
58
|
+
// We'll set up message handlers on the already-established connection
|
|
59
|
+
const analysisResultsPromise = this.collectResultsViaEstablishedWebSocket(establishedWs, params.user_id);
|
|
60
|
+
// Step 3: Submit commit review via HTTP POST (WebSocket is now connected and ready)
|
|
61
|
+
logger.logInfo("Submitting commit review to backend", {
|
|
62
|
+
user_id: params.user_id,
|
|
63
|
+
factor: params.factor,
|
|
64
|
+
fileCount: String(params.file_changes.length),
|
|
65
|
+
});
|
|
66
|
+
const submitResponse = await this.backendApiService.submitCommitReview({
|
|
67
|
+
factor: params.factor,
|
|
68
|
+
user_id: params.user_id,
|
|
69
|
+
repo_name: params.repo_name,
|
|
70
|
+
commit_id: params.commit_id,
|
|
71
|
+
username: params.username,
|
|
72
|
+
files_json: JSON.stringify(params.file_changes),
|
|
73
|
+
organization_name: params.organization_name,
|
|
74
|
+
});
|
|
75
|
+
logger.logInfo("Commit review submitted", {
|
|
76
|
+
analysisId: submitResponse.analysisId || "none",
|
|
77
|
+
});
|
|
78
|
+
// Step 2: Wait for WebSocket‑delivered analysis results
|
|
79
|
+
const analysisResults = await analysisResultsPromise;
|
|
80
|
+
// Handle edge case: WebSocket completed but no results received
|
|
81
|
+
// This can happen when:
|
|
82
|
+
// 1. No relevant code files were found (all files are deleted or non-code files)
|
|
83
|
+
// 2. All file processing failed silently
|
|
84
|
+
// 3. Backend pipeline completed but didn't send any analysis results
|
|
85
|
+
if (!analysisResults || analysisResults.length === 0) {
|
|
86
|
+
logger.logWarning("WebSocket completed but no analysis results received", {
|
|
87
|
+
user_id: params.user_id,
|
|
88
|
+
commit_id: params.commit_id,
|
|
89
|
+
fileCount: String(params.file_changes.length),
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: "No analysis results received. This may occur if no valid code files were found in the commit, or if all file processing failed. Please ensure your commit contains code files that can be analyzed.",
|
|
94
|
+
analysisId: submitResponse.analysisId,
|
|
95
|
+
results: [],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// Filter out any invalid results (files with no analysis data)
|
|
99
|
+
const validResults = analysisResults.filter(result => result &&
|
|
100
|
+
result.file_name &&
|
|
101
|
+
(result.analysis !== undefined && result.analysis !== null));
|
|
102
|
+
if (validResults.length === 0) {
|
|
103
|
+
logger.logWarning("All analysis results were invalid or empty", {
|
|
104
|
+
user_id: params.user_id,
|
|
105
|
+
commit_id: params.commit_id,
|
|
106
|
+
totalResults: String(analysisResults.length),
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: "Analysis completed but no valid results were generated. This may occur if the files could not be analyzed or if the analysis pipeline encountered errors.",
|
|
111
|
+
analysisId: submitResponse.analysisId,
|
|
112
|
+
results: analysisResults,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
logger.logInfo("Analysis results received successfully", {
|
|
116
|
+
user_id: params.user_id,
|
|
117
|
+
commit_id: params.commit_id,
|
|
118
|
+
resultCount: String(validResults.length),
|
|
119
|
+
totalResults: String(analysisResults.length),
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
analysisId: submitResponse.analysisId,
|
|
124
|
+
message: submitResponse.message,
|
|
125
|
+
results: validResults,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
logger.logError("Error in commit review flow", error);
|
|
130
|
+
// If we get a 401 (Unauthorized) from the backend, close the WebSocket connection
|
|
131
|
+
// because the backend won't be sending any analysis results.
|
|
132
|
+
if (error instanceof Error && error.message.includes("status: 401")) {
|
|
133
|
+
if (wsConnection) {
|
|
134
|
+
logger.logInfo("Closing WebSocket connection due to 401 Unauthorized error");
|
|
135
|
+
wsConnection.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
success: false,
|
|
140
|
+
error: error instanceof Error ? error.message : String(error),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Collect analysis results via an already-established WebSocket connection
|
|
146
|
+
* This method reuses an existing WebSocket connection instead of creating a new one
|
|
147
|
+
* @param ws - Already-established WebSocket connection (must be in OPEN state)
|
|
148
|
+
* @param userId - User ID for logging
|
|
149
|
+
* @param timeoutMs - Maximum time to wait for results (default: 10 minutes)
|
|
150
|
+
* @returns Array of analysis results
|
|
151
|
+
*/
|
|
152
|
+
async collectResultsViaEstablishedWebSocket(ws, userId, timeoutMs = 10 * 60 * 1000 // 10 minutes default timeout
|
|
153
|
+
) {
|
|
154
|
+
const analysisResults = [];
|
|
155
|
+
let wsError = null;
|
|
156
|
+
let wsStatusCode;
|
|
157
|
+
let wsErrorMessage;
|
|
158
|
+
let isComplete = false;
|
|
159
|
+
let timeoutId;
|
|
160
|
+
// Verify WebSocket is open
|
|
161
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
162
|
+
throw new Error(`WebSocket must be in OPEN state. Current state: ${ws.readyState}`);
|
|
163
|
+
}
|
|
164
|
+
// Set up timeout to prevent indefinite waiting
|
|
165
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
166
|
+
timeoutId = setTimeout(() => {
|
|
167
|
+
if (!isComplete) {
|
|
168
|
+
wsError = "Analysis timeout: The analysis took too long to complete. Please try again with fewer files or contact support if the issue persists.";
|
|
169
|
+
logger.logError("WebSocket timeout", new Error(wsError), {
|
|
170
|
+
user_id: userId,
|
|
171
|
+
timeoutMs: String(timeoutMs),
|
|
172
|
+
});
|
|
173
|
+
ws.close();
|
|
174
|
+
reject(new Error(wsError));
|
|
175
|
+
}
|
|
176
|
+
}, timeoutMs);
|
|
177
|
+
});
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
// Set up message handler
|
|
180
|
+
const messageHandler = (data) => {
|
|
181
|
+
try {
|
|
182
|
+
const message = JSON.parse(data.toString());
|
|
183
|
+
// Clear timeout on first message (analysis has started)
|
|
184
|
+
if (timeoutId) {
|
|
185
|
+
clearTimeout(timeoutId);
|
|
186
|
+
// Reset timeout to allow more time for completion
|
|
187
|
+
timeoutId = setTimeout(() => {
|
|
188
|
+
if (!isComplete) {
|
|
189
|
+
wsError = "Analysis timeout: The analysis is taking longer than expected. Please try again or contact support.";
|
|
190
|
+
logger.logError("WebSocket timeout after receiving initial results", new Error(wsError), {
|
|
191
|
+
user_id: userId,
|
|
192
|
+
resultsReceived: String(analysisResults.length),
|
|
193
|
+
});
|
|
194
|
+
ws.close();
|
|
195
|
+
cleanup();
|
|
196
|
+
reject(new Error(wsError));
|
|
197
|
+
}
|
|
198
|
+
}, timeoutMs);
|
|
199
|
+
}
|
|
200
|
+
// Handle WebSocket error messages from backend
|
|
201
|
+
if (message.status_code !== 200 && message.status_code !== undefined) {
|
|
202
|
+
wsStatusCode = message.status_code;
|
|
203
|
+
wsErrorMessage = message.error_message || "Unknown error from backend";
|
|
204
|
+
wsError = wsErrorMessage || "Unknown error from backend";
|
|
205
|
+
isComplete = true;
|
|
206
|
+
if (timeoutId)
|
|
207
|
+
clearTimeout(timeoutId);
|
|
208
|
+
// Log full WebSocket error payload from backend for debugging
|
|
209
|
+
logger.logError("WebSocket error message received", new Error(wsErrorMessage), {
|
|
210
|
+
status_code: String(wsStatusCode),
|
|
211
|
+
user_id: userId,
|
|
212
|
+
raw_message: JSON.stringify(message),
|
|
213
|
+
});
|
|
214
|
+
cleanup();
|
|
215
|
+
reject(new Error(wsError || "Unknown error from backend"));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (message.content) {
|
|
219
|
+
const isCommitReview = message.content.analysis_type === "commit_review";
|
|
220
|
+
if (isCommitReview) {
|
|
221
|
+
const file_name = message.content.file_name?.replace(/\\/g, "/") || "";
|
|
222
|
+
const analysis = message.content.analysis;
|
|
223
|
+
if (file_name && analysis !== undefined && analysis !== null) {
|
|
224
|
+
analysisResults.push({
|
|
225
|
+
analysis: analysis,
|
|
226
|
+
language: message.content.language,
|
|
227
|
+
file_name: file_name,
|
|
228
|
+
analysisId: message.analysis_id ?? 0,
|
|
229
|
+
});
|
|
230
|
+
logger.logInfo("Analysis result received for file", {
|
|
231
|
+
user_id: userId,
|
|
232
|
+
file_name: file_name,
|
|
233
|
+
result_count: String(analysisResults.length),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// Check if analysis is complete
|
|
237
|
+
if (message.content.is_complete || message.content.status === "complete") {
|
|
238
|
+
isComplete = true;
|
|
239
|
+
if (timeoutId)
|
|
240
|
+
clearTimeout(timeoutId);
|
|
241
|
+
logger.logInfo("Analysis marked as complete", {
|
|
242
|
+
user_id: userId,
|
|
243
|
+
total_results: String(analysisResults.length),
|
|
244
|
+
});
|
|
245
|
+
cleanup();
|
|
246
|
+
resolve(analysisResults);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
logger.logError("Error parsing WebSocket message", error);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const errorHandler = (error) => {
|
|
256
|
+
if (timeoutId)
|
|
257
|
+
clearTimeout(timeoutId);
|
|
258
|
+
wsError = error.message;
|
|
259
|
+
logger.logError("WebSocket connection error", error, { user_id: userId });
|
|
260
|
+
cleanup();
|
|
261
|
+
reject(error);
|
|
262
|
+
};
|
|
263
|
+
const closeHandler = (code, reason) => {
|
|
264
|
+
if (timeoutId)
|
|
265
|
+
clearTimeout(timeoutId);
|
|
266
|
+
const reasonStr = reason.toString();
|
|
267
|
+
if (code !== 1000 && !isComplete) {
|
|
268
|
+
wsError = `Connection closed unexpectedly: ${reasonStr}`;
|
|
269
|
+
logger.logWarning("WebSocket closed unexpectedly", {
|
|
270
|
+
code: String(code),
|
|
271
|
+
reason: reasonStr,
|
|
272
|
+
user_id: userId,
|
|
273
|
+
isComplete: String(isComplete),
|
|
274
|
+
results_received: String(analysisResults.length),
|
|
275
|
+
});
|
|
276
|
+
cleanup();
|
|
277
|
+
reject(new Error(wsError));
|
|
278
|
+
}
|
|
279
|
+
else if (code === 1000 && !isComplete) {
|
|
280
|
+
logger.logInfo("WebSocket closed normally, treating as completion", {
|
|
281
|
+
user_id: userId,
|
|
282
|
+
results_received: String(analysisResults.length),
|
|
283
|
+
});
|
|
284
|
+
isComplete = true;
|
|
285
|
+
cleanup();
|
|
286
|
+
resolve(analysisResults);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
cleanup();
|
|
290
|
+
resolve(analysisResults);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
const cleanup = () => {
|
|
294
|
+
ws.removeListener("message", messageHandler);
|
|
295
|
+
ws.removeListener("error", errorHandler);
|
|
296
|
+
ws.removeListener("close", closeHandler);
|
|
297
|
+
};
|
|
298
|
+
// Attach event handlers to the already-established connection
|
|
299
|
+
ws.on("message", messageHandler);
|
|
300
|
+
ws.on("error", errorHandler);
|
|
301
|
+
ws.on("close", closeHandler);
|
|
302
|
+
// Race timeout - will be resolved by handlers
|
|
303
|
+
timeoutPromise.catch(() => {
|
|
304
|
+
// Timeout already handled in timeoutPromise
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Connect to WebSocket and collect analysis results
|
|
310
|
+
* Handles edge cases:
|
|
311
|
+
* - Timeout scenarios (backend takes too long)
|
|
312
|
+
* - Empty results (no files to analyze)
|
|
313
|
+
* - Partial results (some files succeed, others fail)
|
|
314
|
+
* - WebSocket completion without explicit completion signal
|
|
315
|
+
* @param userId - User ID for WebSocket connection
|
|
316
|
+
* @param onConnection - Callback when connection is established
|
|
317
|
+
* @param timeoutMs - Maximum time to wait for results (default: 10 minutes)
|
|
318
|
+
* @returns Array of analysis results
|
|
319
|
+
*/
|
|
320
|
+
async collectResultsViaWebSocket(userId, onConnection, timeoutMs = 10 * 60 * 1000 // 10 minutes default timeout
|
|
321
|
+
) {
|
|
322
|
+
const analysisResults = [];
|
|
323
|
+
let wsError = null;
|
|
324
|
+
let wsStatusCode;
|
|
325
|
+
let wsErrorMessage;
|
|
326
|
+
let isComplete = false;
|
|
327
|
+
let timeoutId;
|
|
328
|
+
let wsConnection;
|
|
329
|
+
// Set up timeout to prevent indefinite waiting
|
|
330
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
331
|
+
timeoutId = setTimeout(() => {
|
|
332
|
+
if (!isComplete) {
|
|
333
|
+
wsError = "Analysis timeout: The analysis took too long to complete. Please try again with fewer files or contact support if the issue persists.";
|
|
334
|
+
logger.logError("WebSocket timeout", new Error(wsError), {
|
|
335
|
+
user_id: userId,
|
|
336
|
+
timeoutMs: String(timeoutMs),
|
|
337
|
+
});
|
|
338
|
+
if (wsConnection) {
|
|
339
|
+
wsConnection.close();
|
|
340
|
+
}
|
|
341
|
+
reject(new Error(wsError));
|
|
342
|
+
}
|
|
343
|
+
}, timeoutMs);
|
|
344
|
+
});
|
|
345
|
+
try {
|
|
346
|
+
await Promise.race([
|
|
347
|
+
new Promise((resolve, reject) => {
|
|
348
|
+
this.backendApiService.connectWebSocket(userId, (message) => {
|
|
349
|
+
// Clear timeout on first message (analysis has started)
|
|
350
|
+
if (timeoutId) {
|
|
351
|
+
clearTimeout(timeoutId);
|
|
352
|
+
// Reset timeout to allow more time for completion
|
|
353
|
+
timeoutId = setTimeout(() => {
|
|
354
|
+
if (!isComplete) {
|
|
355
|
+
wsError = "Analysis timeout: The analysis is taking longer than expected. Please try again or contact support.";
|
|
356
|
+
logger.logError("WebSocket timeout after receiving initial results", new Error(wsError), {
|
|
357
|
+
user_id: userId,
|
|
358
|
+
resultsReceived: String(analysisResults.length),
|
|
359
|
+
});
|
|
360
|
+
if (wsConnection) {
|
|
361
|
+
wsConnection.close();
|
|
362
|
+
}
|
|
363
|
+
reject(new Error(wsError));
|
|
364
|
+
}
|
|
365
|
+
}, timeoutMs);
|
|
366
|
+
}
|
|
367
|
+
// Handle WebSocket error messages from backend
|
|
368
|
+
// Backend sends errors via WebSocket with status_code and error_message
|
|
369
|
+
if (message.status_code !== 200 && message.status_code !== undefined) {
|
|
370
|
+
wsStatusCode = message.status_code;
|
|
371
|
+
wsErrorMessage = message.error_message || "Unknown error from backend";
|
|
372
|
+
wsError = wsErrorMessage;
|
|
373
|
+
isComplete = true;
|
|
374
|
+
if (timeoutId)
|
|
375
|
+
clearTimeout(timeoutId);
|
|
376
|
+
// Log full WebSocket error payload from backend for debugging
|
|
377
|
+
logger.logError("WebSocket error message received", new Error(wsErrorMessage), {
|
|
378
|
+
status_code: String(wsStatusCode),
|
|
379
|
+
user_id: userId,
|
|
380
|
+
raw_message: JSON.stringify(message),
|
|
381
|
+
});
|
|
382
|
+
resolve();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (message.content) {
|
|
386
|
+
const isCommitReview = message.content.analysis_type === "commit_review";
|
|
387
|
+
if (isCommitReview) {
|
|
388
|
+
// Validate analysis data before storing
|
|
389
|
+
const file_name = message.content.file_name?.replace(/\\/g, "/") || "";
|
|
390
|
+
const analysis = message.content.analysis;
|
|
391
|
+
if (file_name && analysis !== undefined && analysis !== null) {
|
|
392
|
+
// Store commit review analysis
|
|
393
|
+
analysisResults.push({
|
|
394
|
+
analysis: analysis,
|
|
395
|
+
language: message.content.language,
|
|
396
|
+
file_name: file_name,
|
|
397
|
+
analysisId: message.analysis_id ?? 0,
|
|
398
|
+
});
|
|
399
|
+
logger.logInfo("Analysis result received for file", {
|
|
400
|
+
user_id: userId,
|
|
401
|
+
file_name: file_name,
|
|
402
|
+
result_count: String(analysisResults.length),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
logger.logWarning("Received invalid analysis result (missing file_name or analysis)", {
|
|
407
|
+
user_id: userId,
|
|
408
|
+
has_file_name: String(!!file_name),
|
|
409
|
+
has_analysis: String(analysis !== undefined && analysis !== null),
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
// Check if analysis is complete
|
|
413
|
+
if (message.content.is_complete || message.content.status === "complete") {
|
|
414
|
+
isComplete = true;
|
|
415
|
+
if (timeoutId)
|
|
416
|
+
clearTimeout(timeoutId);
|
|
417
|
+
logger.logInfo("Analysis marked as complete", {
|
|
418
|
+
user_id: userId,
|
|
419
|
+
total_results: String(analysisResults.length),
|
|
420
|
+
});
|
|
421
|
+
resolve();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
// Non-commit-review message, log for debugging
|
|
426
|
+
logger.logInfo("Received non-commit-review WebSocket message", {
|
|
427
|
+
user_id: userId,
|
|
428
|
+
analysis_type: message.content.analysis_type || "unknown",
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
// Content is null - backend may be signaling completion
|
|
434
|
+
// Wait a bit to see if more messages come, but don't resolve immediately
|
|
435
|
+
// The WebSocket close handler will handle this case
|
|
436
|
+
logger.logInfo("Received WebSocket message with null content", {
|
|
437
|
+
user_id: userId,
|
|
438
|
+
results_so_far: String(analysisResults.length),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}, (error) => {
|
|
442
|
+
// WebSocket connection error
|
|
443
|
+
if (timeoutId)
|
|
444
|
+
clearTimeout(timeoutId);
|
|
445
|
+
wsError = error.message;
|
|
446
|
+
logger.logError("WebSocket connection error", error, { user_id: userId });
|
|
447
|
+
reject(error);
|
|
448
|
+
}, (code, reason) => {
|
|
449
|
+
// WebSocket closed
|
|
450
|
+
if (timeoutId)
|
|
451
|
+
clearTimeout(timeoutId);
|
|
452
|
+
if (code !== 1000 && !isComplete) {
|
|
453
|
+
wsError = `Connection closed unexpectedly: ${reason}`;
|
|
454
|
+
logger.logWarning("WebSocket closed unexpectedly", {
|
|
455
|
+
code: String(code),
|
|
456
|
+
reason: reason.toString(),
|
|
457
|
+
user_id: userId,
|
|
458
|
+
isComplete: String(isComplete),
|
|
459
|
+
results_received: String(analysisResults.length),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
else if (code === 1000 && !isComplete) {
|
|
463
|
+
// Normal closure but no completion signal received
|
|
464
|
+
// This can happen when backend completes but doesn't send explicit completion
|
|
465
|
+
logger.logInfo("WebSocket closed normally, treating as completion", {
|
|
466
|
+
user_id: userId,
|
|
467
|
+
results_received: String(analysisResults.length),
|
|
468
|
+
});
|
|
469
|
+
isComplete = true;
|
|
470
|
+
}
|
|
471
|
+
resolve();
|
|
472
|
+
}).then((ws) => {
|
|
473
|
+
wsConnection = ws;
|
|
474
|
+
if (onConnection) {
|
|
475
|
+
onConnection(ws);
|
|
476
|
+
}
|
|
477
|
+
}).catch(reject);
|
|
478
|
+
}),
|
|
479
|
+
timeoutPromise
|
|
480
|
+
]);
|
|
481
|
+
}
|
|
482
|
+
catch (error) {
|
|
483
|
+
if (timeoutId)
|
|
484
|
+
clearTimeout(timeoutId);
|
|
485
|
+
throw error;
|
|
486
|
+
}
|
|
487
|
+
if (wsError) {
|
|
488
|
+
// Create error with status code and message for proper error extraction
|
|
489
|
+
const error = new Error(wsError);
|
|
490
|
+
if (wsStatusCode !== undefined) {
|
|
491
|
+
error.statusCode = wsStatusCode;
|
|
492
|
+
}
|
|
493
|
+
if (wsErrorMessage) {
|
|
494
|
+
error.errorDetail = wsErrorMessage;
|
|
495
|
+
}
|
|
496
|
+
throw error;
|
|
497
|
+
}
|
|
498
|
+
logger.logInfo("WebSocket collection completed", {
|
|
499
|
+
user_id: userId,
|
|
500
|
+
results_count: String(analysisResults.length),
|
|
501
|
+
isComplete: String(isComplete),
|
|
502
|
+
});
|
|
503
|
+
return analysisResults;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
//# sourceMappingURL=commitReviewService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commitReviewService.js","sourceRoot":"","sources":["../../src/services/commitReviewService.ts"],"names":[],"mappings":"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"}
|