@debugg-ai/debugg-ai-mcp 1.0.34 → 1.0.36
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/handlers/testPageChangesHandler.js +21 -3
- package/dist/tools/testPageChanges.js +2 -2
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/dist/handlers/e2eSuiteHandlers.js +0 -526
- package/dist/handlers/liveSessionHandlers.js +0 -272
- package/dist/services/browserSessions.js +0 -282
- package/dist/services/caddy/caddyProxy.js +0 -236
- package/dist/services/e2es.js +0 -290
- package/dist/tools/e2eSuites.js +0 -259
- package/dist/tools/liveSession.js +0 -217
- package/dist/tools/quickScreenshot.js +0 -203
|
@@ -35,10 +35,28 @@ export async function testPageChangesHandler(input, context, progressCallback) {
|
|
|
35
35
|
logger.info(`Reusing tunnel: ${ctx.targetUrl} (id: ${ctx.tunnelId})`);
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
|
-
|
|
38
|
+
let tunnel;
|
|
39
|
+
try {
|
|
40
|
+
tunnel = await client.tunnels.provision();
|
|
41
|
+
}
|
|
42
|
+
catch (provisionError) {
|
|
43
|
+
const msg = provisionError instanceof Error ? provisionError.message : String(provisionError);
|
|
44
|
+
throw new Error(`Failed to provision tunnel for ${ctx.originalUrl}. ` +
|
|
45
|
+
`The remote browser needs a secure tunnel to reach your local dev server. ` +
|
|
46
|
+
`Make sure your dev server is running on the specified port and try again. ` +
|
|
47
|
+
`(Detail: ${msg})`);
|
|
48
|
+
}
|
|
39
49
|
keyId = tunnel.keyId;
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
try {
|
|
51
|
+
ctx = await ensureTunnel(ctx, tunnel.tunnelKey, tunnel.tunnelId, tunnel.keyId, () => client.revokeNgrokKey(tunnel.keyId));
|
|
52
|
+
}
|
|
53
|
+
catch (tunnelError) {
|
|
54
|
+
const msg = tunnelError instanceof Error ? tunnelError.message : String(tunnelError);
|
|
55
|
+
throw new Error(`Tunnel creation failed for ${ctx.originalUrl}. ` +
|
|
56
|
+
`Could not establish a secure connection between the remote browser and your local port. ` +
|
|
57
|
+
`Verify your dev server is running and the port is accessible. ` +
|
|
58
|
+
`(Detail: ${msg})`);
|
|
59
|
+
}
|
|
42
60
|
logger.info(`Tunnel ready: ${ctx.targetUrl} (id: ${ctx.tunnelId})`);
|
|
43
61
|
}
|
|
44
62
|
}
|
|
@@ -10,7 +10,7 @@ import { testPageChangesHandler } from '../handlers/testPageChangesHandler.js';
|
|
|
10
10
|
export const testPageChangesTool = {
|
|
11
11
|
name: "check_app_in_browser",
|
|
12
12
|
title: "Run E2E Browser Test",
|
|
13
|
-
description: "Give an AI agent eyes on a live website or app. The agent browses it, interacts with it, and tells you whether a given task or check passed. Works on localhost or any URL. Use for visual QA, flow validation, regression checks, or anything that needs a real browser to verify.",
|
|
13
|
+
description: "Give an AI agent eyes on a live website or app. The agent browses it, interacts with it, and tells you whether a given task or check passed. Works on localhost or any URL. Use for visual QA, flow validation, regression checks, or anything that needs a real browser to verify.\n\nLOCALHOST SUPPORT: Pass any localhost URL (e.g. http://localhost:3000) and it Just Works. A secure tunnel is automatically created so the remote browser can reach your local dev server — no manual ngrok setup, no port forwarding, no config. Supports localhost, 127.0.0.1, 0.0.0.0, [::1], and private IPs (192.168.x.x, 10.x.x.x). The tunnel stays alive for 55 minutes and is reused across calls to the same port.",
|
|
14
14
|
inputSchema: {
|
|
15
15
|
type: "object",
|
|
16
16
|
properties: {
|
|
@@ -21,7 +21,7 @@ export const testPageChangesTool = {
|
|
|
21
21
|
},
|
|
22
22
|
url: {
|
|
23
23
|
type: "string",
|
|
24
|
-
description: "URL to navigate to.
|
|
24
|
+
description: "URL to navigate to. Can be any public URL (https://example.com) OR a localhost/local dev server URL. For localhost URLs (http://localhost:3000, http://127.0.0.1:8080, etc.), a secure tunnel is automatically created so the remote browser can reach your machine — just make sure your dev server is running on that port. No extra setup needed."
|
|
25
25
|
},
|
|
26
26
|
environmentId: {
|
|
27
27
|
type: "string",
|
package/dist/types/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { normalizeUrl } from '../utils/urlParser.js';
|
|
|
8
8
|
*/
|
|
9
9
|
export const TestPageChangesInputSchema = z.object({
|
|
10
10
|
description: z.string().min(1, 'Description is required'),
|
|
11
|
-
url: z.preprocess(normalizeUrl, z.string().url('
|
|
11
|
+
url: z.preprocess(normalizeUrl, z.string().url('Invalid URL. Pass a full URL like "http://localhost:3000" or "https://example.com". Localhost URLs are auto-tunneled to the remote browser — no extra setup needed.')),
|
|
12
12
|
// Credential/environment resolution
|
|
13
13
|
environmentId: z.string().uuid().optional(),
|
|
14
14
|
credentialId: z.string().uuid().optional(),
|
package/package.json
CHANGED
|
@@ -1,526 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E Suite Handlers
|
|
3
|
-
* Handles E2E test suite creation, commit suite creation, and test status retrieval
|
|
4
|
-
*/
|
|
5
|
-
import { config } from '../config/index.js';
|
|
6
|
-
import { Logger } from '../utils/logger.js';
|
|
7
|
-
import { handleExternalServiceError } from '../utils/errors.js';
|
|
8
|
-
import { DebuggAIServerClient } from '../services/index.js';
|
|
9
|
-
const logger = new Logger({ module: 'e2eSuiteHandlers' });
|
|
10
|
-
/**
|
|
11
|
-
* Handler for creating test suites
|
|
12
|
-
*/
|
|
13
|
-
export async function createTestSuiteHandler(input, context) {
|
|
14
|
-
const startTime = Date.now();
|
|
15
|
-
logger.toolStart('create_test_suite', input);
|
|
16
|
-
try {
|
|
17
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
18
|
-
await client.init();
|
|
19
|
-
if (!client.e2es) {
|
|
20
|
-
throw new Error('E2Es service not initialized');
|
|
21
|
-
}
|
|
22
|
-
// Merge input with config defaults
|
|
23
|
-
const params = {
|
|
24
|
-
repoName: input.repoName ?? config.defaults.repoName,
|
|
25
|
-
branchName: input.branchName ?? config.defaults.branchName,
|
|
26
|
-
repoPath: input.repoPath ?? config.defaults.repoPath,
|
|
27
|
-
filePath: input.filePath ?? config.defaults.filePath,
|
|
28
|
-
};
|
|
29
|
-
if (!params.repoName || !params.repoPath) {
|
|
30
|
-
throw new Error('repoName and repoPath are required to generate tests. ' +
|
|
31
|
-
'Pass them as tool arguments or set DEBUGGAI_LOCAL_REPO_NAME and DEBUGGAI_LOCAL_REPO_PATH.');
|
|
32
|
-
}
|
|
33
|
-
logger.info('Creating E2E test suite', {
|
|
34
|
-
description: input.description,
|
|
35
|
-
...params
|
|
36
|
-
});
|
|
37
|
-
// Create test suite
|
|
38
|
-
const testSuite = await client.e2es.createE2eTestSuite(input.description, params);
|
|
39
|
-
if (!testSuite) {
|
|
40
|
-
throw new Error('Failed to create test suite - no response from service');
|
|
41
|
-
}
|
|
42
|
-
const duration = Date.now() - startTime;
|
|
43
|
-
const responseContent = {
|
|
44
|
-
success: true,
|
|
45
|
-
testSuite: {
|
|
46
|
-
uuid: testSuite.uuid,
|
|
47
|
-
id: testSuite.id,
|
|
48
|
-
name: testSuite.name,
|
|
49
|
-
description: testSuite.description,
|
|
50
|
-
project: testSuite.project,
|
|
51
|
-
key: testSuite.key,
|
|
52
|
-
completed: testSuite.completed,
|
|
53
|
-
completedAt: testSuite.completedAt,
|
|
54
|
-
testsCount: testSuite.tests?.length || 0,
|
|
55
|
-
feature: testSuite.feature,
|
|
56
|
-
testType: testSuite.testType,
|
|
57
|
-
timestamp: testSuite.timestamp,
|
|
58
|
-
lastMod: testSuite.lastMod
|
|
59
|
-
},
|
|
60
|
-
context: {
|
|
61
|
-
repoName: params.repoName,
|
|
62
|
-
branchName: params.branchName,
|
|
63
|
-
filePath: params.filePath
|
|
64
|
-
},
|
|
65
|
-
executionTime: `${duration}ms`,
|
|
66
|
-
timestamp: new Date().toISOString()
|
|
67
|
-
};
|
|
68
|
-
logger.info('Test suite created successfully', {
|
|
69
|
-
testSuiteUuid: testSuite.uuid,
|
|
70
|
-
testsCount: testSuite.tests?.length || 0,
|
|
71
|
-
duration: `${duration}ms`
|
|
72
|
-
});
|
|
73
|
-
logger.toolComplete('create_test_suite', duration);
|
|
74
|
-
return {
|
|
75
|
-
content: [{
|
|
76
|
-
type: 'text',
|
|
77
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
78
|
-
}]
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
const duration = Date.now() - startTime;
|
|
83
|
-
logger.toolError('create_test_suite', error, duration);
|
|
84
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'test suite creation');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Handler for creating commit suites
|
|
89
|
-
*/
|
|
90
|
-
export async function createCommitSuiteHandler(input, context) {
|
|
91
|
-
const startTime = Date.now();
|
|
92
|
-
logger.toolStart('create_commit_suite', input);
|
|
93
|
-
try {
|
|
94
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
95
|
-
await client.init();
|
|
96
|
-
if (!client.e2es) {
|
|
97
|
-
throw new Error('E2Es service not initialized');
|
|
98
|
-
}
|
|
99
|
-
// Merge input with config defaults
|
|
100
|
-
const params = {
|
|
101
|
-
repoName: input.repoName ?? config.defaults.repoName,
|
|
102
|
-
branchName: input.branchName ?? config.defaults.branchName,
|
|
103
|
-
repoPath: input.repoPath ?? config.defaults.repoPath,
|
|
104
|
-
filePath: input.filePath ?? config.defaults.filePath,
|
|
105
|
-
};
|
|
106
|
-
if (!params.repoName || !params.repoPath) {
|
|
107
|
-
throw new Error('repoName and repoPath are required to generate commit tests. ' +
|
|
108
|
-
'Pass them as tool arguments or set DEBUGGAI_LOCAL_REPO_NAME and DEBUGGAI_LOCAL_REPO_PATH.');
|
|
109
|
-
}
|
|
110
|
-
logger.info('Creating E2E commit suite', {
|
|
111
|
-
description: input.description,
|
|
112
|
-
...params
|
|
113
|
-
});
|
|
114
|
-
// Create commit suite
|
|
115
|
-
const commitSuite = await client.e2es.createE2eCommitSuite(input.description, params);
|
|
116
|
-
if (!commitSuite) {
|
|
117
|
-
throw new Error('Failed to create commit suite - no response from service');
|
|
118
|
-
}
|
|
119
|
-
const duration = Date.now() - startTime;
|
|
120
|
-
const responseContent = {
|
|
121
|
-
success: true,
|
|
122
|
-
commitSuite: {
|
|
123
|
-
id: commitSuite.id,
|
|
124
|
-
uuid: commitSuite.uuid,
|
|
125
|
-
commitHash: commitSuite.commitHash,
|
|
126
|
-
commitHashShort: commitSuite.commitHashShort,
|
|
127
|
-
project: commitSuite.project,
|
|
128
|
-
projectName: commitSuite.projectName,
|
|
129
|
-
description: commitSuite.description,
|
|
130
|
-
summarizedChanges: commitSuite.summarizedChanges,
|
|
131
|
-
key: commitSuite.key,
|
|
132
|
-
tunnelKey: commitSuite.tunnelKey,
|
|
133
|
-
runStatus: commitSuite.runStatus,
|
|
134
|
-
testsCount: commitSuite.tests?.length || 0,
|
|
135
|
-
createdBy: commitSuite.createdBy,
|
|
136
|
-
timestamp: commitSuite.timestamp,
|
|
137
|
-
lastMod: commitSuite.lastMod
|
|
138
|
-
},
|
|
139
|
-
context: {
|
|
140
|
-
repoName: params.repoName,
|
|
141
|
-
branchName: params.branchName,
|
|
142
|
-
filePath: params.filePath
|
|
143
|
-
},
|
|
144
|
-
executionTime: `${duration}ms`,
|
|
145
|
-
timestamp: new Date().toISOString()
|
|
146
|
-
};
|
|
147
|
-
logger.info('Commit suite created successfully', {
|
|
148
|
-
commitSuiteUuid: commitSuite.uuid,
|
|
149
|
-
testsCount: commitSuite.tests?.length || 0,
|
|
150
|
-
commitHash: commitSuite.commitHashShort,
|
|
151
|
-
duration: `${duration}ms`
|
|
152
|
-
});
|
|
153
|
-
logger.toolComplete('create_commit_suite', duration);
|
|
154
|
-
return {
|
|
155
|
-
content: [{
|
|
156
|
-
type: 'text',
|
|
157
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
158
|
-
}]
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
const duration = Date.now() - startTime;
|
|
163
|
-
logger.toolError('create_commit_suite', error, duration);
|
|
164
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'commit suite creation');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Handler for getting test status
|
|
169
|
-
*/
|
|
170
|
-
export async function getTestStatusHandler(input, context) {
|
|
171
|
-
const startTime = Date.now();
|
|
172
|
-
logger.toolStart('get_test_status', input);
|
|
173
|
-
try {
|
|
174
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
175
|
-
await client.init();
|
|
176
|
-
if (!client.e2es) {
|
|
177
|
-
throw new Error('E2Es service not initialized');
|
|
178
|
-
}
|
|
179
|
-
logger.info('Getting test status', {
|
|
180
|
-
suiteUuid: input.suiteUuid,
|
|
181
|
-
suiteType: input.suiteType
|
|
182
|
-
});
|
|
183
|
-
let suiteData;
|
|
184
|
-
let responseContent;
|
|
185
|
-
if (input.suiteType === 'commit') {
|
|
186
|
-
// Get commit suite status
|
|
187
|
-
suiteData = await client.e2es.getE2eCommitSuite(input.suiteUuid);
|
|
188
|
-
if (!suiteData) {
|
|
189
|
-
throw new Error(`Commit suite not found: ${input.suiteUuid}`);
|
|
190
|
-
}
|
|
191
|
-
responseContent = {
|
|
192
|
-
success: true,
|
|
193
|
-
suiteType: 'commit',
|
|
194
|
-
commitSuite: {
|
|
195
|
-
id: suiteData.id,
|
|
196
|
-
uuid: suiteData.uuid,
|
|
197
|
-
commitHash: suiteData.commitHash,
|
|
198
|
-
commitHashShort: suiteData.commitHashShort,
|
|
199
|
-
project: suiteData.project,
|
|
200
|
-
projectName: suiteData.projectName,
|
|
201
|
-
description: suiteData.description,
|
|
202
|
-
summarizedChanges: suiteData.summarizedChanges,
|
|
203
|
-
runStatus: suiteData.runStatus,
|
|
204
|
-
testsCount: suiteData.tests?.length || 0,
|
|
205
|
-
tests: suiteData.tests?.map((test) => ({
|
|
206
|
-
uuid: test.uuid,
|
|
207
|
-
name: test.name,
|
|
208
|
-
description: test.description,
|
|
209
|
-
currentRun: test.curRun ? {
|
|
210
|
-
uuid: test.curRun.uuid,
|
|
211
|
-
status: test.curRun.status,
|
|
212
|
-
outcome: test.curRun.outcome,
|
|
213
|
-
runType: test.curRun.runType
|
|
214
|
-
} : null
|
|
215
|
-
})) || [],
|
|
216
|
-
createdBy: suiteData.createdBy,
|
|
217
|
-
timestamp: suiteData.timestamp,
|
|
218
|
-
lastMod: suiteData.lastMod
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
// Get test suite status
|
|
224
|
-
suiteData = await client.e2es.getE2eTestSuite(input.suiteUuid);
|
|
225
|
-
if (!suiteData) {
|
|
226
|
-
throw new Error(`Test suite not found: ${input.suiteUuid}`);
|
|
227
|
-
}
|
|
228
|
-
responseContent = {
|
|
229
|
-
success: true,
|
|
230
|
-
suiteType: 'test',
|
|
231
|
-
testSuite: {
|
|
232
|
-
uuid: suiteData.uuid,
|
|
233
|
-
id: suiteData.id,
|
|
234
|
-
name: suiteData.name,
|
|
235
|
-
description: suiteData.description,
|
|
236
|
-
project: suiteData.project,
|
|
237
|
-
key: suiteData.key,
|
|
238
|
-
completed: suiteData.completed,
|
|
239
|
-
completedAt: suiteData.completedAt,
|
|
240
|
-
testsCount: suiteData.tests?.length || 0,
|
|
241
|
-
tests: suiteData.tests?.map((test) => ({
|
|
242
|
-
uuid: test.uuid,
|
|
243
|
-
name: test.name,
|
|
244
|
-
description: test.description,
|
|
245
|
-
currentRun: test.curRun ? {
|
|
246
|
-
uuid: test.curRun.uuid,
|
|
247
|
-
status: test.curRun.status,
|
|
248
|
-
outcome: test.curRun.outcome,
|
|
249
|
-
runType: test.curRun.runType
|
|
250
|
-
} : null
|
|
251
|
-
})) || [],
|
|
252
|
-
feature: suiteData.feature,
|
|
253
|
-
testType: suiteData.testType,
|
|
254
|
-
timestamp: suiteData.timestamp,
|
|
255
|
-
lastMod: suiteData.lastMod
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
const duration = Date.now() - startTime;
|
|
260
|
-
responseContent.executionTime = `${duration}ms`;
|
|
261
|
-
responseContent.timestamp = new Date().toISOString();
|
|
262
|
-
logger.info('Test status retrieved successfully', {
|
|
263
|
-
suiteUuid: input.suiteUuid,
|
|
264
|
-
suiteType: input.suiteType,
|
|
265
|
-
testsCount: suiteData.tests?.length || 0,
|
|
266
|
-
duration: `${duration}ms`
|
|
267
|
-
});
|
|
268
|
-
logger.toolComplete('get_test_status', duration);
|
|
269
|
-
return {
|
|
270
|
-
content: [{
|
|
271
|
-
type: 'text',
|
|
272
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
273
|
-
}]
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
catch (error) {
|
|
277
|
-
const duration = Date.now() - startTime;
|
|
278
|
-
logger.toolError('get_test_status', error, duration);
|
|
279
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'test status retrieval');
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Handler for listing E2E tests
|
|
284
|
-
*/
|
|
285
|
-
export async function listTestsHandler(input, context, progressCallback) {
|
|
286
|
-
const startTime = Date.now();
|
|
287
|
-
logger.toolStart('list_tests', input);
|
|
288
|
-
try {
|
|
289
|
-
if (progressCallback) {
|
|
290
|
-
await progressCallback({ progress: 1, total: 3, message: 'Initializing client...' });
|
|
291
|
-
}
|
|
292
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
293
|
-
await client.init();
|
|
294
|
-
if (!client.e2es) {
|
|
295
|
-
throw new Error('E2Es service not initialized');
|
|
296
|
-
}
|
|
297
|
-
if (progressCallback) {
|
|
298
|
-
await progressCallback({ progress: 2, total: 3, message: 'Fetching tests...' });
|
|
299
|
-
}
|
|
300
|
-
// Merge input with config defaults
|
|
301
|
-
const params = {
|
|
302
|
-
...input,
|
|
303
|
-
repoName: input.repoName ?? config.defaults.repoName,
|
|
304
|
-
branchName: input.branchName ?? config.defaults.branchName,
|
|
305
|
-
};
|
|
306
|
-
logger.info('Listing E2E tests', params);
|
|
307
|
-
const testsList = await client.e2es.listE2eTests(params);
|
|
308
|
-
if (progressCallback) {
|
|
309
|
-
await progressCallback({ progress: 3, total: 3, message: 'Tests retrieved successfully' });
|
|
310
|
-
}
|
|
311
|
-
if (!testsList) {
|
|
312
|
-
throw new Error('Failed to retrieve tests - no response from service');
|
|
313
|
-
}
|
|
314
|
-
const duration = Date.now() - startTime;
|
|
315
|
-
const responseContent = {
|
|
316
|
-
success: true,
|
|
317
|
-
tests: testsList.results.map((test) => ({
|
|
318
|
-
uuid: test.uuid,
|
|
319
|
-
name: test.name,
|
|
320
|
-
description: test.description,
|
|
321
|
-
currentRun: test.curRun ? {
|
|
322
|
-
uuid: test.curRun.uuid,
|
|
323
|
-
status: test.curRun.status,
|
|
324
|
-
outcome: test.curRun.outcome,
|
|
325
|
-
runType: test.curRun.runType
|
|
326
|
-
} : null,
|
|
327
|
-
timestamp: test.timestamp,
|
|
328
|
-
lastMod: test.lastMod
|
|
329
|
-
})),
|
|
330
|
-
pagination: {
|
|
331
|
-
total: testsList.count,
|
|
332
|
-
page: input.page || 1,
|
|
333
|
-
limit: input.limit || 20
|
|
334
|
-
},
|
|
335
|
-
filters: {
|
|
336
|
-
repoName: params.repoName,
|
|
337
|
-
branchName: params.branchName,
|
|
338
|
-
status: input.status
|
|
339
|
-
},
|
|
340
|
-
executionTime: `${duration}ms`,
|
|
341
|
-
timestamp: new Date().toISOString()
|
|
342
|
-
};
|
|
343
|
-
logger.info('Tests listed successfully', {
|
|
344
|
-
testsCount: testsList.results.length,
|
|
345
|
-
totalTests: testsList.count,
|
|
346
|
-
duration: `${duration}ms`
|
|
347
|
-
});
|
|
348
|
-
logger.toolComplete('list_tests', duration);
|
|
349
|
-
return {
|
|
350
|
-
content: [{
|
|
351
|
-
type: 'text',
|
|
352
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
353
|
-
}]
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
catch (error) {
|
|
357
|
-
const duration = Date.now() - startTime;
|
|
358
|
-
logger.toolError('list_tests', error, duration);
|
|
359
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'test listing');
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Handler for listing E2E test suites
|
|
364
|
-
*/
|
|
365
|
-
export async function listTestSuitesHandler(input, context, progressCallback) {
|
|
366
|
-
const startTime = Date.now();
|
|
367
|
-
logger.toolStart('list_test_suites', input);
|
|
368
|
-
try {
|
|
369
|
-
if (progressCallback) {
|
|
370
|
-
await progressCallback({ progress: 1, total: 3, message: 'Initializing client...' });
|
|
371
|
-
}
|
|
372
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
373
|
-
await client.init();
|
|
374
|
-
if (!client.e2es) {
|
|
375
|
-
throw new Error('E2Es service not initialized');
|
|
376
|
-
}
|
|
377
|
-
if (progressCallback) {
|
|
378
|
-
await progressCallback({ progress: 2, total: 3, message: 'Fetching test suites...' });
|
|
379
|
-
}
|
|
380
|
-
// Merge input with config defaults
|
|
381
|
-
const params = {
|
|
382
|
-
...input,
|
|
383
|
-
repoName: input.repoName ?? config.defaults.repoName,
|
|
384
|
-
branchName: input.branchName ?? config.defaults.branchName,
|
|
385
|
-
};
|
|
386
|
-
logger.info('Listing E2E test suites', params);
|
|
387
|
-
const suitesList = await client.e2es.listE2eTestSuites(params);
|
|
388
|
-
if (progressCallback) {
|
|
389
|
-
await progressCallback({ progress: 3, total: 3, message: 'Test suites retrieved successfully' });
|
|
390
|
-
}
|
|
391
|
-
if (!suitesList) {
|
|
392
|
-
throw new Error('Failed to retrieve test suites - no response from service');
|
|
393
|
-
}
|
|
394
|
-
const duration = Date.now() - startTime;
|
|
395
|
-
const responseContent = {
|
|
396
|
-
success: true,
|
|
397
|
-
testSuites: suitesList.results.map((suite) => ({
|
|
398
|
-
uuid: suite.uuid,
|
|
399
|
-
id: suite.id,
|
|
400
|
-
name: suite.name,
|
|
401
|
-
description: suite.description,
|
|
402
|
-
project: suite.project,
|
|
403
|
-
key: suite.key,
|
|
404
|
-
completed: suite.completed,
|
|
405
|
-
completedAt: suite.completedAt,
|
|
406
|
-
testsCount: suite.tests?.length || 0,
|
|
407
|
-
feature: suite.feature,
|
|
408
|
-
testType: suite.testType,
|
|
409
|
-
timestamp: suite.timestamp,
|
|
410
|
-
lastMod: suite.lastMod
|
|
411
|
-
})),
|
|
412
|
-
pagination: {
|
|
413
|
-
total: suitesList.count,
|
|
414
|
-
page: input.page || 1,
|
|
415
|
-
limit: input.limit || 20
|
|
416
|
-
},
|
|
417
|
-
filters: {
|
|
418
|
-
repoName: params.repoName,
|
|
419
|
-
branchName: params.branchName,
|
|
420
|
-
status: input.status
|
|
421
|
-
},
|
|
422
|
-
executionTime: `${duration}ms`,
|
|
423
|
-
timestamp: new Date().toISOString()
|
|
424
|
-
};
|
|
425
|
-
logger.info('Test suites listed successfully', {
|
|
426
|
-
suitesCount: suitesList.results.length,
|
|
427
|
-
totalSuites: suitesList.count,
|
|
428
|
-
duration: `${duration}ms`
|
|
429
|
-
});
|
|
430
|
-
logger.toolComplete('list_test_suites', duration);
|
|
431
|
-
return {
|
|
432
|
-
content: [{
|
|
433
|
-
type: 'text',
|
|
434
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
435
|
-
}]
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
catch (error) {
|
|
439
|
-
const duration = Date.now() - startTime;
|
|
440
|
-
logger.toolError('list_test_suites', error, duration);
|
|
441
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'test suite listing');
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Handler for listing E2E commit suites
|
|
446
|
-
*/
|
|
447
|
-
export async function listCommitSuitesHandler(input, context, progressCallback) {
|
|
448
|
-
const startTime = Date.now();
|
|
449
|
-
logger.toolStart('list_commit_suites', input);
|
|
450
|
-
try {
|
|
451
|
-
if (progressCallback) {
|
|
452
|
-
await progressCallback({ progress: 1, total: 3, message: 'Initializing client...' });
|
|
453
|
-
}
|
|
454
|
-
const client = new DebuggAIServerClient(config.api.key);
|
|
455
|
-
await client.init();
|
|
456
|
-
if (!client.e2es) {
|
|
457
|
-
throw new Error('E2Es service not initialized');
|
|
458
|
-
}
|
|
459
|
-
if (progressCallback) {
|
|
460
|
-
await progressCallback({ progress: 2, total: 3, message: 'Fetching commit suites...' });
|
|
461
|
-
}
|
|
462
|
-
// Merge input with config defaults
|
|
463
|
-
const params = {
|
|
464
|
-
...input,
|
|
465
|
-
repoName: input.repoName ?? config.defaults.repoName,
|
|
466
|
-
branchName: input.branchName ?? config.defaults.branchName,
|
|
467
|
-
};
|
|
468
|
-
logger.info('Listing E2E commit suites', params);
|
|
469
|
-
const suitesList = await client.e2es.listE2eCommitSuites(params);
|
|
470
|
-
if (progressCallback) {
|
|
471
|
-
await progressCallback({ progress: 3, total: 3, message: 'Commit suites retrieved successfully' });
|
|
472
|
-
}
|
|
473
|
-
if (!suitesList) {
|
|
474
|
-
throw new Error('Failed to retrieve commit suites - no response from service');
|
|
475
|
-
}
|
|
476
|
-
const duration = Date.now() - startTime;
|
|
477
|
-
const responseContent = {
|
|
478
|
-
success: true,
|
|
479
|
-
commitSuites: suitesList.results.map((suite) => ({
|
|
480
|
-
id: suite.id,
|
|
481
|
-
uuid: suite.uuid,
|
|
482
|
-
commitHash: suite.commitHash,
|
|
483
|
-
commitHashShort: suite.commitHashShort,
|
|
484
|
-
project: suite.project,
|
|
485
|
-
projectName: suite.projectName,
|
|
486
|
-
description: suite.description,
|
|
487
|
-
summarizedChanges: suite.summarizedChanges,
|
|
488
|
-
key: suite.key,
|
|
489
|
-
runStatus: suite.runStatus,
|
|
490
|
-
testsCount: suite.tests?.length || 0,
|
|
491
|
-
createdBy: suite.createdBy,
|
|
492
|
-
timestamp: suite.timestamp,
|
|
493
|
-
lastMod: suite.lastMod
|
|
494
|
-
})),
|
|
495
|
-
pagination: {
|
|
496
|
-
total: suitesList.count,
|
|
497
|
-
page: input.page || 1,
|
|
498
|
-
limit: input.limit || 20
|
|
499
|
-
},
|
|
500
|
-
filters: {
|
|
501
|
-
repoName: params.repoName,
|
|
502
|
-
branchName: params.branchName,
|
|
503
|
-
status: input.status
|
|
504
|
-
},
|
|
505
|
-
executionTime: `${duration}ms`,
|
|
506
|
-
timestamp: new Date().toISOString()
|
|
507
|
-
};
|
|
508
|
-
logger.info('Commit suites listed successfully', {
|
|
509
|
-
suitesCount: suitesList.results.length,
|
|
510
|
-
totalSuites: suitesList.count,
|
|
511
|
-
duration: `${duration}ms`
|
|
512
|
-
});
|
|
513
|
-
logger.toolComplete('list_commit_suites', duration);
|
|
514
|
-
return {
|
|
515
|
-
content: [{
|
|
516
|
-
type: 'text',
|
|
517
|
-
text: JSON.stringify(responseContent, null, 2)
|
|
518
|
-
}]
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
catch (error) {
|
|
522
|
-
const duration = Date.now() - startTime;
|
|
523
|
-
logger.toolError('list_commit_suites', error, duration);
|
|
524
|
-
throw handleExternalServiceError(error, 'DebuggAI', 'commit suite listing');
|
|
525
|
-
}
|
|
526
|
-
}
|