@debugg-ai/debugg-ai-mcp 4.4.1 → 5.0.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/README.md +9 -7
- package/dist/handlers/probePageHandler.js +2 -2
- package/dist/handlers/runTestSuiteHandler.js +5 -5
- package/dist/handlers/testPageChangesHandler.js +25 -25
- package/dist/handlers/triggerCrawlHandler.js +3 -3
- package/dist/index.js +1 -1
- package/dist/services/caddy/caddyProxy.js +7 -6
- package/dist/services/index.js +0 -9
- package/dist/services/tunnel/debuggTransport.js +9 -9
- package/dist/services/tunnel/protocol/constants.js +3 -3
- package/dist/services/tunnel/transport.js +28 -9
- package/dist/services/{ngrok → tunnel}/tunnelFaultInjection.js +9 -15
- package/dist/services/{ngrok → tunnel}/tunnelManager.js +65 -131
- package/dist/services/{ngrok → tunnel}/tunnelRegistry.js +2 -2
- package/dist/services/tunnels.js +64 -46
- package/dist/tools/testPageChanges.js +1 -1
- package/dist/utils/imageUtils.js +2 -1
- package/dist/utils/localReachability.js +62 -341
- package/dist/utils/telemetry.js +4 -4
- package/dist/utils/tunnelContext.js +11 -9
- package/dist/utils/tunnelDisposition.js +51 -69
- package/dist/utils/tunnelDomains.js +30 -21
- package/dist/utils/urlParser.js +5 -6
- package/package.json +2 -3
- package/dist/services/ngrok/error.js +0 -3
- package/dist/services/ngrok/ngrokAgentInspector.js +0 -210
- package/dist/services/ngrok/ngrokAgentSession.js +0 -49
- package/dist/services/ngrok/types.js +0 -1
- package/dist/services/tunnel/ngrokTransport.js +0 -165
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ngrokTransport — today's ngrok client, behind the TunnelTransport seam.
|
|
3
|
-
*
|
|
4
|
-
* This is a MOVE, not a rewrite. Every line here came out of
|
|
5
|
-
* services/ngrok/tunnelManager.ts unchanged, because the whole point of the
|
|
6
|
-
* extraction is that the ngrok path keeps behaving exactly as it did while the
|
|
7
|
-
* debugg transport is rolled out (design §5, bead debugg_ai_mcp-xkoh.5.5): the
|
|
8
|
-
* lazy module load, `getApi()` bootstrap, the agent pre-warm, the connect
|
|
9
|
-
* options (including the `https://` addr form), disconnect, and the
|
|
10
|
-
* module-reset-when-no-tunnels-remain behaviour.
|
|
11
|
-
*
|
|
12
|
-
* It exists so that nothing on the debugg path can reach the `ngrok` package.
|
|
13
|
-
* Until this file was split out, `import('ngrok')` ran on every tunnel
|
|
14
|
-
* creation, every teardown and every retry, which would have meant a binary
|
|
15
|
-
* download on machines that never use ngrok again.
|
|
16
|
-
*
|
|
17
|
-
* Deleted wholesale in the rollout arc's last step, along with
|
|
18
|
-
* services/ngrok/ngrokAgentSession.ts and the `ngrok` dependency.
|
|
19
|
-
*/
|
|
20
|
-
import { Logger } from '../../utils/logger.js';
|
|
21
|
-
import { startAgentSession } from '../ngrok/ngrokAgentSession.js';
|
|
22
|
-
const logger = new Logger({ module: 'ngrokTransport' });
|
|
23
|
-
let ngrokModule = null;
|
|
24
|
-
async function getNgrok() {
|
|
25
|
-
if (!ngrokModule) {
|
|
26
|
-
try {
|
|
27
|
-
ngrokModule = await import('ngrok');
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
throw new Error(`Failed to load ngrok module: ${error}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return ngrokModule;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Reset the cached ngrok module so the next connect() bootstraps a fresh agent.
|
|
37
|
-
* Called when the last tunnel is disconnected and the agent process may have died.
|
|
38
|
-
*/
|
|
39
|
-
function resetNgrokModule() {
|
|
40
|
-
ngrokModule = null;
|
|
41
|
-
}
|
|
42
|
-
class NgrokTransport {
|
|
43
|
-
kind = 'ngrok';
|
|
44
|
-
/** Public so TunnelManager can keep exposing its existing test seams. */
|
|
45
|
-
agentSessionStarter;
|
|
46
|
-
agentSessionTimeoutMs;
|
|
47
|
-
/** Whether the ngrok agent's client session is established (bead pqgj). */
|
|
48
|
-
agentSessionReady = false;
|
|
49
|
-
/** In-flight session bootstrap, so concurrent tunnels wait on one spawn. */
|
|
50
|
-
agentSessionPromise = null;
|
|
51
|
-
initialized = false;
|
|
52
|
-
constructor(opts = {}) {
|
|
53
|
-
this.agentSessionStarter = opts.agentSessionStarter ?? startAgentSession;
|
|
54
|
-
this.agentSessionTimeoutMs = opts.agentSessionTimeoutMs ?? 5000;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Bead pqgj: make sure the ngrok agent's client session is established before
|
|
58
|
-
* we ask it for a tunnel, so attempt 1 lands on a ready agent instead of the
|
|
59
|
-
* ~293ms not-ready window that made every single run fail its first connect.
|
|
60
|
-
*
|
|
61
|
-
* Never throws: if the agent can't be pre-warmed (ngrok internals moved, slow
|
|
62
|
-
* session, dead token) we fall through and let the retry ladder do what it
|
|
63
|
-
* did before this fix. The ladder stays a genuine safety net.
|
|
64
|
-
*/
|
|
65
|
-
async prepare(authtoken) {
|
|
66
|
-
await this.ensureInitialized();
|
|
67
|
-
if (this.agentSessionReady)
|
|
68
|
-
return;
|
|
69
|
-
if (!this.agentSessionPromise) {
|
|
70
|
-
this.agentSessionPromise = (async () => {
|
|
71
|
-
let markEstablished;
|
|
72
|
-
const established = new Promise((resolve) => { markEstablished = resolve; });
|
|
73
|
-
await this.agentSessionStarter({
|
|
74
|
-
authtoken,
|
|
75
|
-
onStatusChange: (status) => {
|
|
76
|
-
if (status === 'connected') {
|
|
77
|
-
this.agentSessionReady = true;
|
|
78
|
-
markEstablished();
|
|
79
|
-
}
|
|
80
|
-
else if (status === 'closed') {
|
|
81
|
-
this.agentSessionReady = false;
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
onTerminated: () => {
|
|
85
|
-
// Agent process died — next tunnel must re-warm.
|
|
86
|
-
this.agentSessionReady = false;
|
|
87
|
-
this.agentSessionPromise = null;
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
let capTimer;
|
|
91
|
-
const cap = new Promise((resolve) => {
|
|
92
|
-
capTimer = setTimeout(resolve, this.agentSessionTimeoutMs);
|
|
93
|
-
});
|
|
94
|
-
try {
|
|
95
|
-
await Promise.race([established, cap]);
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
if (capTimer)
|
|
99
|
-
clearTimeout(capTimer);
|
|
100
|
-
}
|
|
101
|
-
})().catch((err) => {
|
|
102
|
-
// Pre-warm unavailable — not fatal, the ladder covers it.
|
|
103
|
-
this.agentSessionPromise = null;
|
|
104
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
105
|
-
logger.debug(`ngrok agent pre-warm unavailable, relying on connect retry ladder: ${msg}`);
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
await this.agentSessionPromise;
|
|
109
|
-
}
|
|
110
|
-
/** Whether the pre-warm believes the agent session is live (trace/diagnostics). */
|
|
111
|
-
get sessionReady() {
|
|
112
|
-
return this.agentSessionReady;
|
|
113
|
-
}
|
|
114
|
-
async connect(localAddr, hostname, token, _opts) {
|
|
115
|
-
const ngrok = await getNgrok();
|
|
116
|
-
const url = await ngrok.connect({
|
|
117
|
-
proto: 'http',
|
|
118
|
-
addr: localAddr,
|
|
119
|
-
hostname,
|
|
120
|
-
authtoken: token,
|
|
121
|
-
});
|
|
122
|
-
if (!url) {
|
|
123
|
-
throw new Error('ngrok.connect() returned empty URL');
|
|
124
|
-
}
|
|
125
|
-
return url;
|
|
126
|
-
}
|
|
127
|
-
async disconnect(publicUrl) {
|
|
128
|
-
const ngrok = await getNgrok();
|
|
129
|
-
await ngrok.disconnect(publicUrl);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* The agent-reset the retry ladder does between attempts 1 and 2 — the
|
|
133
|
-
* "agent died" recovery path that used to be the only retried case.
|
|
134
|
-
*/
|
|
135
|
-
async resetAfterFailedAttempt() {
|
|
136
|
-
resetNgrokModule();
|
|
137
|
-
this.initialized = false;
|
|
138
|
-
await this.ensureInitialized();
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* No ngrok tunnels remain, so the agent process may have exited. Reset the
|
|
142
|
-
* module and init state so the next connect() bootstraps a fresh agent.
|
|
143
|
-
*/
|
|
144
|
-
onAllTunnelsStopped() {
|
|
145
|
-
resetNgrokModule();
|
|
146
|
-
this.initialized = false;
|
|
147
|
-
this.agentSessionReady = false;
|
|
148
|
-
this.agentSessionPromise = null;
|
|
149
|
-
}
|
|
150
|
-
async ensureInitialized() {
|
|
151
|
-
if (this.initialized)
|
|
152
|
-
return;
|
|
153
|
-
try {
|
|
154
|
-
const ngrok = await getNgrok();
|
|
155
|
-
ngrok.getApi();
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
// ignore — let connect surface real errors
|
|
159
|
-
}
|
|
160
|
-
this.initialized = true;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
export function createNgrokTransport(opts = {}) {
|
|
164
|
-
return new NgrokTransport(opts);
|
|
165
|
-
}
|