@debugg-ai/debugg-ai-mcp 1.0.59 → 1.0.61
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/listExecutionsHandler.js +6 -2
- package/dist/handlers/testPageChangesHandler.js +5 -6
- package/dist/index.js +7 -8
- package/dist/services/index.js +9 -21
- package/dist/services/workflows.js +2 -0
- package/dist/tools/listExecutions.js +2 -1
- package/dist/types/index.js +1 -0
- package/package.json +1 -1
|
@@ -7,17 +7,21 @@ const logger = new Logger({ module: 'listExecutionsHandler' });
|
|
|
7
7
|
export async function listExecutionsHandler(input, _context) {
|
|
8
8
|
const start = Date.now();
|
|
9
9
|
const pagination = toPaginationParams({ page: input.page, pageSize: input.pageSize });
|
|
10
|
-
logger.toolStart('list_executions', { status: input.status, ...pagination });
|
|
10
|
+
logger.toolStart('list_executions', { status: input.status, projectUuid: input.projectUuid, ...pagination });
|
|
11
11
|
try {
|
|
12
12
|
const client = new DebuggAIServerClient(config.api.key);
|
|
13
13
|
await client.init();
|
|
14
14
|
const { pageInfo, executions } = await client.workflows.listExecutions({
|
|
15
15
|
status: input.status,
|
|
16
|
+
projectId: input.projectUuid,
|
|
16
17
|
page: pagination.page,
|
|
17
18
|
pageSize: pagination.pageSize,
|
|
18
19
|
});
|
|
19
20
|
const payload = {
|
|
20
|
-
filter: {
|
|
21
|
+
filter: {
|
|
22
|
+
status: input.status ?? null,
|
|
23
|
+
projectUuid: input.projectUuid ?? null,
|
|
24
|
+
},
|
|
21
25
|
pageInfo,
|
|
22
26
|
executions,
|
|
23
27
|
};
|
|
@@ -10,7 +10,6 @@ import { fetchImageAsBase64, imageContentBlock } from '../utils/imageUtils.js';
|
|
|
10
10
|
import { DebuggAIServerClient } from '../services/index.js';
|
|
11
11
|
import { resolveTargetUrl, buildContext, findExistingTunnel, ensureTunnel, sanitizeResponseUrls, touchTunnelById, } from '../utils/tunnelContext.js';
|
|
12
12
|
import { detectRepoName } from '../utils/gitContext.js';
|
|
13
|
-
import { tunnelManager } from '../services/ngrok/tunnelManager.js';
|
|
14
13
|
const logger = new Logger({ module: 'testPageChangesHandler' });
|
|
15
14
|
// Cache the template UUID and project UUIDs within a server session to avoid re-fetching
|
|
16
15
|
let cachedTemplateUuid = null;
|
|
@@ -376,11 +375,11 @@ async function testPageChangesHandlerInner(input, context, progressCallback) {
|
|
|
376
375
|
}
|
|
377
376
|
finally {
|
|
378
377
|
process.stdin.removeListener('close', onStdinClose);
|
|
379
|
-
//
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
378
|
+
// Tunnel is intentionally NOT torn down here — tunnelManager reuses it on
|
|
379
|
+
// subsequent calls to the same port and auto-shutoffs after 55 min idle.
|
|
380
|
+
// Process-exit cleanup happens via stopAllTunnels() in the SIGINT/SIGTERM
|
|
381
|
+
// handlers in index.ts.
|
|
382
|
+
if (!ctx.tunnelId && keyId) {
|
|
384
383
|
// Provisioned a key but tunnel creation failed — revoke the orphaned key.
|
|
385
384
|
client.revokeNgrokKey(keyId).catch(err => logger.warn(`Failed to revoke unused ngrok key ${keyId}: ${err}`));
|
|
386
385
|
}
|
package/dist/index.js
CHANGED
|
@@ -191,16 +191,15 @@ function safeLog(level, message, meta) {
|
|
|
191
191
|
/**
|
|
192
192
|
* Handle graceful shutdown
|
|
193
193
|
*/
|
|
194
|
-
|
|
195
|
-
safeLog('info',
|
|
194
|
+
async function gracefulShutdown(signal) {
|
|
195
|
+
safeLog('info', `Received ${signal}, shutting down gracefully`);
|
|
196
|
+
const { tunnelManager } = await import('./services/ngrok/tunnelManager.js');
|
|
197
|
+
await tunnelManager.stopAllTunnels().catch((err) => safeLog('warn', 'stopAllTunnels failed during shutdown', { error: String(err) }));
|
|
196
198
|
await Telemetry.shutdown();
|
|
197
199
|
process.exit(0);
|
|
198
|
-
}
|
|
199
|
-
process.on('
|
|
200
|
-
|
|
201
|
-
await Telemetry.shutdown();
|
|
202
|
-
process.exit(0);
|
|
203
|
-
});
|
|
200
|
+
}
|
|
201
|
+
process.on('SIGINT', () => { gracefulShutdown('SIGINT'); });
|
|
202
|
+
process.on('SIGTERM', () => { gracefulShutdown('SIGTERM'); });
|
|
204
203
|
process.on('unhandledRejection', (reason) => {
|
|
205
204
|
safeLog('error', 'Unhandled promise rejection', {
|
|
206
205
|
error: reason instanceof Error ? reason.message : String(reason),
|
package/dist/services/index.js
CHANGED
|
@@ -297,18 +297,20 @@ export class DebuggAIServerClient {
|
|
|
297
297
|
}
|
|
298
298
|
/**
|
|
299
299
|
* List credentials for a specific environment. Unpaginated (fetches up to
|
|
300
|
-
* backend max pageSize). q filters label/username
|
|
301
|
-
*
|
|
302
|
-
*
|
|
300
|
+
* backend max pageSize). q filters label/username server-side via ?search=;
|
|
301
|
+
* role filters server-side. Used internally by list_credentials when
|
|
302
|
+
* iterating across envs.
|
|
303
303
|
*/
|
|
304
304
|
async listCredentialsForEnvironment(projectUuid, envUuid, q, role) {
|
|
305
305
|
if (!this.tx)
|
|
306
306
|
throw new Error('Client not initialized — call init() first');
|
|
307
307
|
const params = { pageSize: 200 };
|
|
308
|
+
if (q)
|
|
309
|
+
params.search = q;
|
|
308
310
|
if (role)
|
|
309
311
|
params.role = role;
|
|
310
312
|
const response = await this.tx.get(`api/v1/projects/${projectUuid}/environments/${envUuid}/credentials/`, params);
|
|
311
|
-
|
|
313
|
+
return (response?.results ?? [])
|
|
312
314
|
.filter((c) => c.isActive)
|
|
313
315
|
.map((c) => ({
|
|
314
316
|
uuid: c.uuid,
|
|
@@ -317,24 +319,18 @@ export class DebuggAIServerClient {
|
|
|
317
319
|
role: c.role,
|
|
318
320
|
environmentUuid: envUuid,
|
|
319
321
|
}));
|
|
320
|
-
if (q) {
|
|
321
|
-
const needle = q.toLowerCase();
|
|
322
|
-
creds = creds.filter(c => c.label.toLowerCase().includes(needle) ||
|
|
323
|
-
c.username.toLowerCase().includes(needle));
|
|
324
|
-
}
|
|
325
|
-
return creds;
|
|
326
322
|
}
|
|
327
323
|
async listCredentialsPaginated(projectUuid, envUuid, pagination, q, role) {
|
|
328
324
|
if (!this.tx)
|
|
329
325
|
throw new Error('Client not initialized — call init() first');
|
|
330
326
|
const { makePageInfo } = await import('../utils/pagination.js');
|
|
331
327
|
const params = { page: pagination.page, pageSize: pagination.pageSize };
|
|
332
|
-
|
|
333
|
-
|
|
328
|
+
if (q)
|
|
329
|
+
params.search = q;
|
|
334
330
|
if (role)
|
|
335
331
|
params.role = role;
|
|
336
332
|
const response = await this.tx.get(`api/v1/projects/${projectUuid}/environments/${envUuid}/credentials/`, params);
|
|
337
|
-
|
|
333
|
+
const creds = (response?.results ?? [])
|
|
338
334
|
.filter((c) => c.isActive)
|
|
339
335
|
.map((c) => ({
|
|
340
336
|
uuid: c.uuid,
|
|
@@ -343,14 +339,6 @@ export class DebuggAIServerClient {
|
|
|
343
339
|
role: c.role,
|
|
344
340
|
environmentUuid: envUuid,
|
|
345
341
|
}));
|
|
346
|
-
if (q) {
|
|
347
|
-
const needle = q.toLowerCase();
|
|
348
|
-
creds = creds.filter(c => c.label.toLowerCase().includes(needle) ||
|
|
349
|
-
c.username.toLowerCase().includes(needle));
|
|
350
|
-
}
|
|
351
|
-
if (role) {
|
|
352
|
-
creds = creds.filter(c => c.role === role);
|
|
353
|
-
}
|
|
354
342
|
return {
|
|
355
343
|
pageInfo: makePageInfo(pagination.page, pagination.pageSize, response?.count ?? 0, response?.next),
|
|
356
344
|
credentials: creds,
|
|
@@ -52,6 +52,8 @@ export const createWorkflowsService = (tx) => {
|
|
|
52
52
|
const params = { page: filters.page, pageSize: filters.pageSize };
|
|
53
53
|
if (filters.status)
|
|
54
54
|
params.status = filters.status;
|
|
55
|
+
if (filters.projectId)
|
|
56
|
+
params.projectId = filters.projectId;
|
|
55
57
|
const response = await tx.get('api/v1/workflows/executions/', params);
|
|
56
58
|
return {
|
|
57
59
|
pageInfo: makePageInfo(filters.page, filters.pageSize, response?.count ?? 0, response?.next),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ListExecutionsInputSchema } from '../types/index.js';
|
|
2
2
|
import { listExecutionsHandler } from '../handlers/listExecutionsHandler.js';
|
|
3
|
-
const DESCRIPTION = `List workflow execution history. Paginated — every response includes pageInfo {page, pageSize, totalCount, totalPages, hasMore}; default pageSize 20, max 200. Optional status filter (e.g. "completed", "running", "failed", "cancelled")
|
|
3
|
+
const DESCRIPTION = `List workflow execution history. Paginated — every response includes pageInfo {page, pageSize, totalCount, totalPages, hasMore}; default pageSize 20, max 200. Optional status filter (e.g. "completed", "running", "failed", "cancelled"). Optional projectUuid scopes to a single project. Returns summary shape; use get_execution for full detail on a single uuid.`;
|
|
4
4
|
export function buildListExecutionsTool() {
|
|
5
5
|
return {
|
|
6
6
|
name: 'list_executions',
|
|
@@ -10,6 +10,7 @@ export function buildListExecutionsTool() {
|
|
|
10
10
|
type: 'object',
|
|
11
11
|
properties: {
|
|
12
12
|
status: { type: 'string', description: 'Optional: filter by execution status.' },
|
|
13
|
+
projectUuid: { type: 'string', description: 'Optional: scope results to a specific project.' },
|
|
13
14
|
page: { type: 'number', description: 'Optional: 1-indexed page number. Default 1.', minimum: 1 },
|
|
14
15
|
pageSize: { type: 'number', description: 'Optional: items per page. Default 20, max 200.', minimum: 1, maximum: 200 },
|
|
15
16
|
},
|
package/dist/types/index.js
CHANGED
|
@@ -76,6 +76,7 @@ export const DeleteProjectInputSchema = z.object({
|
|
|
76
76
|
}).strict();
|
|
77
77
|
export const ListExecutionsInputSchema = z.object({
|
|
78
78
|
status: z.string().min(1).optional(),
|
|
79
|
+
projectUuid: z.string().uuid().optional(),
|
|
79
80
|
page: z.number().int().min(1).optional(),
|
|
80
81
|
pageSize: z.number().int().min(1).optional(),
|
|
81
82
|
}).strict();
|