@debugg-ai/debugg-ai-mcp 1.0.42 → 1.0.44
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.
|
@@ -9,6 +9,7 @@ import { handleExternalServiceError } from '../utils/errors.js';
|
|
|
9
9
|
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
|
+
import { detectRepoName } from '../utils/gitContext.js';
|
|
12
13
|
import { tunnelManager } from '../services/ngrok/tunnelManager.js';
|
|
13
14
|
const logger = new Logger({ module: 'testPageChangesHandler' });
|
|
14
15
|
// Cache the template UUID and project UUIDs within a server session to avoid re-fetching
|
|
@@ -80,23 +81,25 @@ export async function testPageChangesHandler(input, context, progressCallback) {
|
|
|
80
81
|
logger.info(`Using workflow template: ${template.name} (${template.uuid})`);
|
|
81
82
|
}
|
|
82
83
|
// --- Resolve project UUID (best-effort, non-blocking) ---
|
|
84
|
+
// Use explicit repoName if provided, otherwise auto-detect from git remote
|
|
85
|
+
const repoName = input.repoName || detectRepoName();
|
|
83
86
|
let projectUuid;
|
|
84
|
-
if (
|
|
85
|
-
projectUuid = projectUuidCache.get(
|
|
87
|
+
if (repoName) {
|
|
88
|
+
projectUuid = projectUuidCache.get(repoName);
|
|
86
89
|
if (!projectUuid) {
|
|
87
90
|
try {
|
|
88
|
-
const project = await client.findProjectByRepoName(
|
|
91
|
+
const project = await client.findProjectByRepoName(repoName);
|
|
89
92
|
if (project) {
|
|
90
93
|
projectUuid = project.uuid;
|
|
91
|
-
projectUuidCache.set(
|
|
94
|
+
projectUuidCache.set(repoName, projectUuid);
|
|
92
95
|
logger.info(`Resolved project: ${project.name} (${project.uuid})`);
|
|
93
96
|
}
|
|
94
97
|
else {
|
|
95
|
-
logger.info(`No project found for repo "${
|
|
98
|
+
logger.info(`No project found for repo "${repoName}" — proceeding without project_id`);
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
101
|
catch (err) {
|
|
99
|
-
logger.warn(`Failed to look up project for repo "${
|
|
102
|
+
logger.warn(`Failed to look up project for repo "${repoName}": ${err}`);
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
}
|
|
@@ -197,14 +200,6 @@ export async function testPageChangesHandler(input, context, progressCallback) {
|
|
|
197
200
|
}
|
|
198
201
|
}, abortController.signal);
|
|
199
202
|
const duration = Date.now() - startTime;
|
|
200
|
-
// If the execution failed because the tunnel URL was unreachable, evict the dead tunnel
|
|
201
|
-
// so the next call re-provisions a fresh one instead of reusing a dead entry.
|
|
202
|
-
const tunnelErrorMsg = finalExecution.errorMessage ?? finalExecution.state?.error ?? '';
|
|
203
|
-
if (ctx.tunnelId && tunnelErrorMsg.includes('unreachable') && tunnelErrorMsg.includes('ngrok')) {
|
|
204
|
-
logger.warn(`Tunnel ${ctx.tunnelId} appears dead (unreachable) — evicting from cache`);
|
|
205
|
-
tunnelManager.stopTunnel(ctx.tunnelId).catch(() => { });
|
|
206
|
-
ctx = { ...ctx, tunnelId: undefined };
|
|
207
|
-
}
|
|
208
203
|
// --- Format result ---
|
|
209
204
|
const outcome = finalExecution.state?.outcome ?? finalExecution.status;
|
|
210
205
|
const nodes = finalExecution.nodeExecutions ?? [];
|
|
@@ -352,12 +347,12 @@ export async function testPageChangesHandler(input, context, progressCallback) {
|
|
|
352
347
|
}
|
|
353
348
|
finally {
|
|
354
349
|
process.stdin.removeListener('close', onStdinClose);
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
350
|
+
// Always tear down the tunnel when the request completes.
|
|
351
|
+
if (ctx.tunnelId) {
|
|
352
|
+
tunnelManager.stopTunnel(ctx.tunnelId).catch(err => logger.warn(`Failed to stop tunnel ${ctx.tunnelId}: ${err}`));
|
|
353
|
+
}
|
|
354
|
+
else if (keyId) {
|
|
355
|
+
// Provisioned a key but tunnel creation failed — revoke the orphaned key.
|
|
361
356
|
client.revokeNgrokKey(keyId).catch(err => logger.warn(`Failed to revoke unused ngrok key ${keyId}: ${err}`));
|
|
362
357
|
}
|
|
363
358
|
}
|
|
@@ -45,7 +45,7 @@ export const testPageChangesTool = {
|
|
|
45
45
|
},
|
|
46
46
|
repoName: {
|
|
47
47
|
type: "string",
|
|
48
|
-
description: "GitHub repository name (e.g. 'my-org/my-repo'
|
|
48
|
+
description: "GitHub repository name (e.g. 'my-org/my-repo'). Auto-detected from the current git repo — only provide this if you want to run against a different project than the one you're in."
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
51
|
required: ["description", "url"],
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-detect git repo name from the current working directory.
|
|
3
|
+
* Parses the origin remote URL into "owner/repo" format.
|
|
4
|
+
*/
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
let cached; // undefined = not yet checked
|
|
7
|
+
/**
|
|
8
|
+
* Detect the repo name (e.g. "debugg-ai/debugg-ai-frontend") from git remote origin.
|
|
9
|
+
* Returns null if not inside a git repo or no origin is configured.
|
|
10
|
+
* Result is cached for the process lifetime.
|
|
11
|
+
*/
|
|
12
|
+
export function detectRepoName() {
|
|
13
|
+
if (cached !== undefined)
|
|
14
|
+
return cached;
|
|
15
|
+
try {
|
|
16
|
+
const raw = execSync('git remote get-url origin', {
|
|
17
|
+
encoding: 'utf-8',
|
|
18
|
+
timeout: 5000,
|
|
19
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
20
|
+
}).trim();
|
|
21
|
+
cached = parseRepoName(raw);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
cached = null;
|
|
25
|
+
}
|
|
26
|
+
return cached;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse an origin URL into "owner/repo" format.
|
|
30
|
+
* Handles SSH (git@github.com:owner/repo.git) and HTTPS (https://github.com/owner/repo.git).
|
|
31
|
+
*/
|
|
32
|
+
function parseRepoName(remoteUrl) {
|
|
33
|
+
// SSH: git@github.com:owner/repo.git
|
|
34
|
+
const sshMatch = remoteUrl.match(/[:\/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
35
|
+
if (sshMatch)
|
|
36
|
+
return sshMatch[1];
|
|
37
|
+
return null;
|
|
38
|
+
}
|