cdp-mcp 0.1.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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/index.js +345 -0
- package/dist/index.js.map +1 -0
- package/dist/server.js +27 -0
- package/dist/server.js.map +1 -0
- package/dist/session/browser.js +394 -0
- package/dist/session/browser.js.map +1 -0
- package/dist/session/buffers.js +43 -0
- package/dist/session/buffers.js.map +1 -0
- package/dist/session/pause.js +99 -0
- package/dist/session/pause.js.map +1 -0
- package/dist/session/state.js +93 -0
- package/dist/session/state.js.map +1 -0
- package/dist/sourcemap/loader.js +138 -0
- package/dist/sourcemap/loader.js.map +1 -0
- package/dist/sourcemap/normalize.js +59 -0
- package/dist/sourcemap/normalize.js.map +1 -0
- package/dist/sourcemap/store.js +185 -0
- package/dist/sourcemap/store.js.map +1 -0
- package/dist/tools/_register.js +30 -0
- package/dist/tools/_register.js.map +1 -0
- package/dist/tools/breakpoints.js +164 -0
- package/dist/tools/breakpoints.js.map +1 -0
- package/dist/tools/console.js +48 -0
- package/dist/tools/console.js.map +1 -0
- package/dist/tools/dom.js +527 -0
- package/dist/tools/dom.js.map +1 -0
- package/dist/tools/execution.js +89 -0
- package/dist/tools/execution.js.map +1 -0
- package/dist/tools/inspect.js +178 -0
- package/dist/tools/inspect.js.map +1 -0
- package/dist/tools/nav.js +136 -0
- package/dist/tools/nav.js.map +1 -0
- package/dist/tools/network.js +137 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/session.js +76 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/source.js +63 -0
- package/dist/tools/source.js.map +1 -0
- package/dist/util/browser-resolve.js +263 -0
- package/dist/util/browser-resolve.js.map +1 -0
- package/dist/util/errors.js +12 -0
- package/dist/util/errors.js.map +1 -0
- package/dist/util/format.js +65 -0
- package/dist/util/format.js.map +1 -0
- package/dist/util/log.js +34 -0
- package/dist/util/log.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireSession, requirePaused } from "../session/state.js";
|
|
3
|
+
import { mapCdpToOriginal } from "../sourcemap/store.js";
|
|
4
|
+
import { registerJsonTool } from "./_register.js";
|
|
5
|
+
export function registerExecutionTools(server) {
|
|
6
|
+
registerJsonTool(server, "resume", "Resume execution. Dispatched to the session that paused (root, worker, OOPIF, …).", undefined, async () => {
|
|
7
|
+
const s = requirePaused();
|
|
8
|
+
const sid = s.pause.current().sessionId;
|
|
9
|
+
await s.client.send("Debugger.resume", undefined, sid);
|
|
10
|
+
return "resumed";
|
|
11
|
+
});
|
|
12
|
+
registerJsonTool(server, "step_over", "Step over the current line. Awaits the next pause (or returns null if execution continues).", { timeout_ms: z.number().int().positive().optional() }, async (input) => stepThen((s, sid) => s.client.send("Debugger.stepOver", undefined, sid), input.timeout_ms));
|
|
13
|
+
registerJsonTool(server, "step_into", "Step into the next function call.", { timeout_ms: z.number().int().positive().optional() }, async (input) => stepThen((s, sid) => s.client.send("Debugger.stepInto", undefined, sid), input.timeout_ms));
|
|
14
|
+
registerJsonTool(server, "step_out", "Step out of the current function.", { timeout_ms: z.number().int().positive().optional() }, async (input) => stepThen((s, sid) => s.client.send("Debugger.stepOut", undefined, sid), input.timeout_ms));
|
|
15
|
+
registerJsonTool(server, "pause", "Pause execution manually at the next statement. By default targets the root page; pass `session_id` (from list_targets or a script's session_id) to pause a specific worker/iframe/service-worker.", {
|
|
16
|
+
session_id: z.string().nullable().optional().describe("null or omitted = root."),
|
|
17
|
+
}, async (input) => {
|
|
18
|
+
const s = requireSession();
|
|
19
|
+
const sid = input.session_id ?? undefined;
|
|
20
|
+
await s.client.send("Debugger.pause", undefined, sid);
|
|
21
|
+
return { paused_session: sid ?? null };
|
|
22
|
+
});
|
|
23
|
+
registerJsonTool(server, "wait_for_pause", "Block until the debugger pauses (or times out). Returns the pause reason and a TS-mapped call stack.", { timeout_ms: z.number().int().positive().optional().describe("Default 30000") }, async (input) => {
|
|
24
|
+
const s = requireSession();
|
|
25
|
+
const state = await s.pause.waitForPause(input.timeout_ms ?? 30000);
|
|
26
|
+
return summarizePause(s, state.reason, state.hitBreakpoints, state.data, state.callFrames, state.sessionId);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function stepThen(send, timeoutMs) {
|
|
30
|
+
const s = requirePaused();
|
|
31
|
+
// Capture the paused session BEFORE marking resumed — pauseState is cleared
|
|
32
|
+
// by onResumed and we still need the sessionId to route the step command.
|
|
33
|
+
const sid = s.pause.current().sessionId;
|
|
34
|
+
s.pause.onResumed();
|
|
35
|
+
await send(s, sid);
|
|
36
|
+
const next = await s.pause.waitForPauseOrResume(timeoutMs ?? 30000);
|
|
37
|
+
if (!next)
|
|
38
|
+
return { paused: false, message: "execution did not pause within timeout" };
|
|
39
|
+
return {
|
|
40
|
+
paused: true,
|
|
41
|
+
...summarizePause(s, next.reason, next.hitBreakpoints, next.data, next.callFrames, next.sessionId),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function summarizePause(s, reason, hitBreakpoints, data, callFrames, sessionId) {
|
|
45
|
+
const userBreakpointIds = matchUserBreakpoints(s, hitBreakpoints ?? [], sessionId);
|
|
46
|
+
return {
|
|
47
|
+
reason,
|
|
48
|
+
hit_breakpoint_ids: userBreakpointIds,
|
|
49
|
+
session_id: sessionId ?? null,
|
|
50
|
+
data: data ?? null,
|
|
51
|
+
call_stack: callFrames.map((cf, i) => formatFrameForPause(s, cf, i, sessionId)),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function formatFrameForPause(s, cf, index, sessionId) {
|
|
55
|
+
const mapped = mapCdpToOriginal(s.scripts, cf.location, sessionId);
|
|
56
|
+
const script = s.scripts.get(cf.location.scriptId, sessionId);
|
|
57
|
+
return {
|
|
58
|
+
index,
|
|
59
|
+
frame_id: cf.callFrameId,
|
|
60
|
+
session_id: sessionId ?? null,
|
|
61
|
+
function_name: cf.functionName || "(anonymous)",
|
|
62
|
+
file: mapped?.file ?? script?.url ?? cf.url ?? "<unknown>",
|
|
63
|
+
line: mapped?.line ?? cf.location.lineNumber + 1,
|
|
64
|
+
column: mapped?.column ?? cf.location.columnNumber ?? 0,
|
|
65
|
+
js_url: script?.url,
|
|
66
|
+
js_line: cf.location.lineNumber + 1,
|
|
67
|
+
js_column: cf.location.columnNumber ?? 0,
|
|
68
|
+
scope_types: cf.scopeChain.map((sc) => sc.type),
|
|
69
|
+
this: cf.this ? { type: cf.this.subtype ?? cf.this.type, preview: cf.this.description ?? "" } : null,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** @internal exported for unit tests; not part of the MCP tool surface. */
|
|
73
|
+
export function matchUserBreakpoints(s, hit, pauseSessionId) {
|
|
74
|
+
if (!hit.length)
|
|
75
|
+
return [];
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const rec of s.breakpoints.values()) {
|
|
78
|
+
// Require BOTH cdpId AND sessionId match. setBreakpointByUrl derives
|
|
79
|
+
// the breakpoint ID from URL/line/column, so two sessions binding the
|
|
80
|
+
// same script can mint colliding cdpIds. Without the sessionId guard,
|
|
81
|
+
// a pause in one session would falsely be reported as a hit for
|
|
82
|
+
// another session's binding. undefined === undefined for root.
|
|
83
|
+
if (rec.bindings.some((b) => hit.includes(b.cdpId) && b.sessionId === pauseSessionId)) {
|
|
84
|
+
out.push(rec.id);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/tools/execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireSession, requirePaused } from "../session/state.js";
|
|
3
|
+
import { mapCdpToOriginal } from "../sourcemap/store.js";
|
|
4
|
+
import { describeRemote, previewRemoteObject } from "../util/format.js";
|
|
5
|
+
import { ToolError } from "../util/errors.js";
|
|
6
|
+
import { registerJsonTool } from "./_register.js";
|
|
7
|
+
// session_id provenance: objectIds, callFrameIds, and scriptIds returned by
|
|
8
|
+
// CDP are scoped per-session (per-target). The inspect tools attach
|
|
9
|
+
// `session_id` to every returned remote-object so the agent can pass it back
|
|
10
|
+
// to get_object_properties and route to the correct Runtime agent.
|
|
11
|
+
export function registerInspectTools(server) {
|
|
12
|
+
registerJsonTool(server, "get_call_stack", "Get the current call stack with TS-mapped frames. Only valid while paused. Each frame includes the session_id its Runtime/Debugger agent belongs to — pass it through to evaluate/get_object_properties for the right routing.", undefined, async () => {
|
|
13
|
+
const s = requirePaused();
|
|
14
|
+
const state = s.pause.current();
|
|
15
|
+
const sid = state.sessionId;
|
|
16
|
+
return state.callFrames.map((cf, i) => {
|
|
17
|
+
const mapped = mapCdpToOriginal(s.scripts, cf.location, sid);
|
|
18
|
+
const script = s.scripts.get(cf.location.scriptId, sid);
|
|
19
|
+
return {
|
|
20
|
+
index: i,
|
|
21
|
+
frame_id: cf.callFrameId,
|
|
22
|
+
session_id: sid ?? null,
|
|
23
|
+
function_name: cf.functionName || "(anonymous)",
|
|
24
|
+
file: mapped?.file ?? script?.url ?? cf.url ?? "<unknown>",
|
|
25
|
+
line: mapped?.line ?? cf.location.lineNumber + 1,
|
|
26
|
+
column: mapped?.column ?? cf.location.columnNumber ?? 0,
|
|
27
|
+
js_url: script?.url,
|
|
28
|
+
js_line: cf.location.lineNumber + 1,
|
|
29
|
+
scope_types: cf.scopeChain.map((sc) => sc.type),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
registerJsonTool(server, "get_scope", "Return variables visible at a paused frame. Valid only while paused. Each item includes the session_id of the originating Runtime agent — required for follow-on get_object_properties calls when paused in a worker/iframe.", {
|
|
34
|
+
frame_index: z.number().int().nonnegative().optional().describe("Default 0 (topmost frame)"),
|
|
35
|
+
scope_type: z
|
|
36
|
+
.enum(["local", "closure", "global", "block", "catch", "with", "script", "eval", "module"])
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Default: local"),
|
|
39
|
+
max_props: z.number().int().positive().optional(),
|
|
40
|
+
}, async (input) => {
|
|
41
|
+
const s = requirePaused();
|
|
42
|
+
const state = s.pause.current();
|
|
43
|
+
const sid = state.sessionId;
|
|
44
|
+
const idx = input.frame_index ?? 0;
|
|
45
|
+
const frame = state.callFrames[idx];
|
|
46
|
+
if (!frame)
|
|
47
|
+
throw new ToolError("bad_frame", `Frame ${idx} out of range (${state.callFrames.length} frames)`);
|
|
48
|
+
const targetType = input.scope_type ?? "local";
|
|
49
|
+
const scope = frame.scopeChain.find((sc) => sc.type === targetType);
|
|
50
|
+
if (!scope?.object?.objectId) {
|
|
51
|
+
throw new ToolError("no_scope", `Frame ${idx} has no '${targetType}' scope. Available: ${frame.scopeChain.map((sc) => sc.type).join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
const max = input.max_props ?? 50;
|
|
54
|
+
const result = await s.client.send("Runtime.getProperties", {
|
|
55
|
+
objectId: scope.object.objectId,
|
|
56
|
+
ownProperties: false,
|
|
57
|
+
accessorPropertiesOnly: false,
|
|
58
|
+
generatePreview: true,
|
|
59
|
+
}, sid);
|
|
60
|
+
const items = (result.result ?? [])
|
|
61
|
+
.filter((p) => !p.symbol)
|
|
62
|
+
.slice(0, max)
|
|
63
|
+
.map((p) => ({
|
|
64
|
+
name: p.name,
|
|
65
|
+
...(p.value ? describeRemote(p.value) : { type: "missing", preview: "(no value)" }),
|
|
66
|
+
session_id: sid ?? null,
|
|
67
|
+
writable: p.writable,
|
|
68
|
+
enumerable: p.enumerable,
|
|
69
|
+
}));
|
|
70
|
+
return {
|
|
71
|
+
frame_index: idx,
|
|
72
|
+
scope_type: targetType,
|
|
73
|
+
session_id: sid ?? null,
|
|
74
|
+
items,
|
|
75
|
+
truncated: (result.result?.length ?? 0) > max,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
registerJsonTool(server, "evaluate", "Evaluate a JS expression. When the debugger is paused, the expression runs in the paused frame's context via Debugger.evaluateOnCallFrame (top frame by default; override with frame_index). When not paused, runs in the page's Runtime context via Runtime.evaluate. frame_index given while not paused is a not_paused error. Note: while paused the event loop is frozen, so async expressions return the unresolved Promise object rather than awaiting it.", {
|
|
79
|
+
expression: z.string(),
|
|
80
|
+
frame_index: z.number().int().nonnegative().optional(),
|
|
81
|
+
return_by_value: z.boolean().optional(),
|
|
82
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
83
|
+
}, async (input) => {
|
|
84
|
+
const s = requireSession();
|
|
85
|
+
const paused = s.pause.isPaused();
|
|
86
|
+
if (input.frame_index !== undefined && !paused) {
|
|
87
|
+
throw new ToolError("not_paused", "frame_index requires paused state");
|
|
88
|
+
}
|
|
89
|
+
if (paused) {
|
|
90
|
+
const state = s.pause.current();
|
|
91
|
+
const sid = state.sessionId;
|
|
92
|
+
const idx = input.frame_index ?? 0;
|
|
93
|
+
const frame = state.callFrames[idx];
|
|
94
|
+
if (!frame)
|
|
95
|
+
throw new ToolError("bad_frame", `Frame ${idx} out of range (${state.callFrames.length} frames)`);
|
|
96
|
+
const res = await s.client.send("Debugger.evaluateOnCallFrame", {
|
|
97
|
+
callFrameId: frame.callFrameId,
|
|
98
|
+
expression: input.expression,
|
|
99
|
+
returnByValue: !!input.return_by_value,
|
|
100
|
+
generatePreview: true,
|
|
101
|
+
throwOnSideEffect: false,
|
|
102
|
+
...(input.timeout_ms ? { timeout: input.timeout_ms } : {}),
|
|
103
|
+
}, sid);
|
|
104
|
+
return formatEvalResult(res.result, res.exceptionDetails, sid);
|
|
105
|
+
}
|
|
106
|
+
const res = await s.client.send("Runtime.evaluate", {
|
|
107
|
+
expression: input.expression,
|
|
108
|
+
returnByValue: !!input.return_by_value,
|
|
109
|
+
generatePreview: true,
|
|
110
|
+
awaitPromise: true,
|
|
111
|
+
...(input.timeout_ms ? { timeout: input.timeout_ms } : {}),
|
|
112
|
+
});
|
|
113
|
+
return formatEvalResult(res.result, res.exceptionDetails, undefined);
|
|
114
|
+
});
|
|
115
|
+
registerJsonTool(server, "get_object_properties", "Inspect a RemoteObject by ID (from get_scope, evaluate, or a callstack frame). Pass `session_id` from the source response so the call routes to the right Runtime agent — null or omitted means root.", {
|
|
116
|
+
object_id: z.string(),
|
|
117
|
+
session_id: z.string().nullable().optional().describe("From get_scope/evaluate/get_call_stack response. null or omitted = root."),
|
|
118
|
+
own_only: z.boolean().optional().describe("Default true"),
|
|
119
|
+
max_props: z.number().int().positive().optional(),
|
|
120
|
+
}, async (input) => {
|
|
121
|
+
const s = requireSession();
|
|
122
|
+
// Strict provenance: omitted session_id means root. The previous
|
|
123
|
+
// "fall back to the paused session" behavior misrouted any
|
|
124
|
+
// root-minted objectId once a child session was paused — a root
|
|
125
|
+
// `evaluate` response carries no session_id (JSON drops undefined),
|
|
126
|
+
// so an agent could not pass it back, and the fallback then
|
|
127
|
+
// dispatched against the wrong target.
|
|
128
|
+
// null is the explicit "root" sentinel agents round-trip from responses;
|
|
129
|
+
// CDP wants undefined for root.
|
|
130
|
+
const sid = input.session_id ?? undefined;
|
|
131
|
+
const max = input.max_props ?? 50;
|
|
132
|
+
const ownProperties = input.own_only ?? true;
|
|
133
|
+
const result = await s.client.send("Runtime.getProperties", {
|
|
134
|
+
objectId: input.object_id,
|
|
135
|
+
ownProperties,
|
|
136
|
+
accessorPropertiesOnly: false,
|
|
137
|
+
generatePreview: true,
|
|
138
|
+
}, sid);
|
|
139
|
+
return {
|
|
140
|
+
session_id: sid ?? null,
|
|
141
|
+
items: (result.result ?? [])
|
|
142
|
+
.filter((p) => !p.symbol)
|
|
143
|
+
.slice(0, max)
|
|
144
|
+
.map((p) => ({
|
|
145
|
+
name: p.name,
|
|
146
|
+
...(p.value ? describeRemote(p.value) : { type: "missing", preview: "(no value)" }),
|
|
147
|
+
session_id: sid ?? null,
|
|
148
|
+
writable: p.writable,
|
|
149
|
+
enumerable: p.enumerable,
|
|
150
|
+
})),
|
|
151
|
+
truncated: (result.result?.length ?? 0) > max,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function formatEvalResult(result, exceptionDetails, sessionId) {
|
|
156
|
+
// Emit session_id as `null` for root (not undefined) so it survives JSON
|
|
157
|
+
// serialization. Agents need a value to round-trip into
|
|
158
|
+
// get_object_properties — otherwise a root-evaluate response with no
|
|
159
|
+
// session_id field has nothing for the agent to pass back, and any
|
|
160
|
+
// omit-then-default fallback misroutes when a child session is paused.
|
|
161
|
+
const sid = sessionId ?? null;
|
|
162
|
+
if (exceptionDetails) {
|
|
163
|
+
return {
|
|
164
|
+
error: true,
|
|
165
|
+
message: exceptionDetails.exception?.description ?? exceptionDetails.text,
|
|
166
|
+
...(exceptionDetails.exception?.objectId ? { object_id: exceptionDetails.exception.objectId } : {}),
|
|
167
|
+
session_id: sid,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
type: result.subtype ?? result.type,
|
|
172
|
+
preview: previewRemoteObject(result),
|
|
173
|
+
value: "value" in result ? result.value : undefined,
|
|
174
|
+
...(result.objectId ? { object_id: result.objectId } : {}),
|
|
175
|
+
session_id: sid,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/tools/inspect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireSession } from "../session/state.js";
|
|
3
|
+
import { registerJsonTool } from "./_register.js";
|
|
4
|
+
export function registerNavTools(server) {
|
|
5
|
+
registerJsonTool(server, "navigate", "Navigate the active page to a URL. Waits for the chosen load milestone.", {
|
|
6
|
+
url: z.string(),
|
|
7
|
+
wait: z.enum(["load", "domcontentloaded", "networkidle", "none"]).optional()
|
|
8
|
+
.describe("Default: load"),
|
|
9
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
10
|
+
}, async (input) => {
|
|
11
|
+
const s = requireSession();
|
|
12
|
+
const wait = input.wait ?? "load";
|
|
13
|
+
const timeout = input.timeout_ms ?? 30000;
|
|
14
|
+
const loadPromise = waitForLoad(s.client, wait, timeout);
|
|
15
|
+
await s.client.send("Page.navigate", { url: input.url });
|
|
16
|
+
await loadPromise;
|
|
17
|
+
const { frameTree } = await s.client.send("Page.getFrameTree");
|
|
18
|
+
return { url: frameTree.frame.url, wait };
|
|
19
|
+
});
|
|
20
|
+
registerJsonTool(server, "reload", "Reload the active page.", { hard: z.boolean().optional().describe("Bypass cache") }, async (input) => {
|
|
21
|
+
const s = requireSession();
|
|
22
|
+
await s.client.send("Page.reload", { ignoreCache: !!input.hard });
|
|
23
|
+
return "reloaded";
|
|
24
|
+
});
|
|
25
|
+
registerJsonTool(server, "get_url", "Return the current top-frame URL.", undefined, async () => {
|
|
26
|
+
const s = requireSession();
|
|
27
|
+
const { frameTree } = await s.client.send("Page.getFrameTree");
|
|
28
|
+
return { url: frameTree.frame.url };
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function waitForLoad(client, mode, timeoutMs) {
|
|
32
|
+
if (mode === "none")
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
// Gate to the root session: top-level navigation completion is only
|
|
35
|
+
// meaningful for the top frame. Now that the multi-target fix wires
|
|
36
|
+
// Page.enable + Network.enable for every child session (OOPIFs, workers,
|
|
37
|
+
// service workers), their events stream through the same root client
|
|
38
|
+
// tagged with their own eventSessionId. Without this gate, a cross-origin
|
|
39
|
+
// iframe firing Page.loadEventFired would prematurely settle navigate(),
|
|
40
|
+
// and an analytics iframe polling /beacon would starve `networkidle`
|
|
41
|
+
// forever.
|
|
42
|
+
const isRoot = (esid) => esid === undefined;
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
let settled = false;
|
|
45
|
+
const listeners = [];
|
|
46
|
+
const off = (api) => {
|
|
47
|
+
for (const { event, fn } of listeners) {
|
|
48
|
+
api.removeListener(event, fn);
|
|
49
|
+
}
|
|
50
|
+
listeners.length = 0;
|
|
51
|
+
};
|
|
52
|
+
const reg = (event, fn) => {
|
|
53
|
+
client.on(event, fn);
|
|
54
|
+
listeners.push({ event, fn });
|
|
55
|
+
};
|
|
56
|
+
const timer = setTimeout(() => {
|
|
57
|
+
if (settled)
|
|
58
|
+
return;
|
|
59
|
+
settled = true;
|
|
60
|
+
off(client);
|
|
61
|
+
reject(new Error(`navigate: ${mode} not reached within ${timeoutMs}ms`));
|
|
62
|
+
}, timeoutMs);
|
|
63
|
+
let idleTimer = null;
|
|
64
|
+
const done = () => {
|
|
65
|
+
if (settled)
|
|
66
|
+
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
if (idleTimer)
|
|
70
|
+
clearTimeout(idleTimer);
|
|
71
|
+
off(client);
|
|
72
|
+
resolve();
|
|
73
|
+
};
|
|
74
|
+
if (mode === "load") {
|
|
75
|
+
reg("Page.loadEventFired", (_p, esid) => {
|
|
76
|
+
if (isRoot(esid))
|
|
77
|
+
done();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else if (mode === "domcontentloaded") {
|
|
81
|
+
reg("Page.domContentEventFired", (_p, esid) => {
|
|
82
|
+
if (isRoot(esid))
|
|
83
|
+
done();
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else if (mode === "networkidle") {
|
|
87
|
+
// Track in-flight root-session requests. The previous version reset
|
|
88
|
+
// the 500ms idle timer on both requestWillBeSent and loadingFinished
|
|
89
|
+
// — which meant a slow request that took 600ms to finish would emit
|
|
90
|
+
// the start event, then 500ms later `done()` fired while the
|
|
91
|
+
// request was still loading. networkidle resolved while a request
|
|
92
|
+
// was in flight.
|
|
93
|
+
//
|
|
94
|
+
// Correct semantics: idle timer starts ONLY when the in-flight set
|
|
95
|
+
// is empty, and resets whenever a new request joins.
|
|
96
|
+
const inFlight = new Set();
|
|
97
|
+
const armIdleIfEmpty = () => {
|
|
98
|
+
if (settled)
|
|
99
|
+
return;
|
|
100
|
+
if (idleTimer)
|
|
101
|
+
clearTimeout(idleTimer);
|
|
102
|
+
if (inFlight.size === 0)
|
|
103
|
+
idleTimer = setTimeout(done, 500);
|
|
104
|
+
};
|
|
105
|
+
reg("Network.requestWillBeSent", (p, esid) => {
|
|
106
|
+
if (settled || !isRoot(esid))
|
|
107
|
+
return;
|
|
108
|
+
// Skip persistent-connection types: WebSocket and EventSource stay
|
|
109
|
+
// open until the page navigates away, so they never emit
|
|
110
|
+
// Network.loadingFinished — tracking them would hold networkidle
|
|
111
|
+
// forever. Every Vite/Next/Astro dev server opens an HMR WebSocket,
|
|
112
|
+
// so this was the universal failure mode.
|
|
113
|
+
if (p.type === "WebSocket" || p.type === "EventSource")
|
|
114
|
+
return;
|
|
115
|
+
inFlight.add(p.requestId);
|
|
116
|
+
if (idleTimer)
|
|
117
|
+
clearTimeout(idleTimer);
|
|
118
|
+
});
|
|
119
|
+
reg("Network.loadingFinished", (p, esid) => {
|
|
120
|
+
if (settled || !isRoot(esid))
|
|
121
|
+
return;
|
|
122
|
+
inFlight.delete(p.requestId);
|
|
123
|
+
armIdleIfEmpty();
|
|
124
|
+
});
|
|
125
|
+
reg("Network.loadingFailed", (p, esid) => {
|
|
126
|
+
if (settled || !isRoot(esid))
|
|
127
|
+
return;
|
|
128
|
+
inFlight.delete(p.requestId);
|
|
129
|
+
armIdleIfEmpty();
|
|
130
|
+
});
|
|
131
|
+
// Initial arm — if nothing fires, we're already idle.
|
|
132
|
+
armIdleIfEmpty();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.js","sourceRoot":"","sources":["../../src/tools/nav.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireSession } from "../session/state.js";
|
|
3
|
+
import { truncate } from "../util/format.js";
|
|
4
|
+
import { registerJsonTool } from "./_register.js";
|
|
5
|
+
export function registerNetworkTools(server) {
|
|
6
|
+
registerJsonTool(server, "get_network_requests", "Query buffered network requests. Paginate with `since`. Bodies are NOT included — fetch via get_request_body/get_response_body.", {
|
|
7
|
+
since: z.number().int().nonnegative().optional(),
|
|
8
|
+
status: z.number().int().optional(),
|
|
9
|
+
type: z.string().optional().describe("e.g. Fetch, XHR, Document, Script"),
|
|
10
|
+
url_match: z.string().optional().describe("Substring filter"),
|
|
11
|
+
finished: z.boolean().optional().describe("If true, only return entries whose lifecycle has completed (loaded OR failed — also check the `failure` field before calling get_response_body)"),
|
|
12
|
+
limit: z.number().int().positive().optional(),
|
|
13
|
+
}, async (input) => {
|
|
14
|
+
const s = requireSession();
|
|
15
|
+
const match = input.url_match;
|
|
16
|
+
const items = s.network.query({
|
|
17
|
+
since: input.since ?? 0,
|
|
18
|
+
limit: input.limit ?? 50,
|
|
19
|
+
filter: (e) => {
|
|
20
|
+
if (input.status !== undefined && e.status !== input.status)
|
|
21
|
+
return false;
|
|
22
|
+
if (input.type && e.resourceType !== input.type)
|
|
23
|
+
return false;
|
|
24
|
+
if (match && !e.url.includes(match))
|
|
25
|
+
return false;
|
|
26
|
+
if (input.finished === true && !e.finished)
|
|
27
|
+
return false;
|
|
28
|
+
if (input.finished === false && e.finished)
|
|
29
|
+
return false;
|
|
30
|
+
return true;
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
cursor: items.length ? items[items.length - 1].seq : input.since ?? 0,
|
|
35
|
+
items: items.map((e) => ({
|
|
36
|
+
seq: e.seq,
|
|
37
|
+
request_id: e.requestId,
|
|
38
|
+
// session_id is required to disambiguate when fetching the body —
|
|
39
|
+
// CDP requestIds are per-Network-agent, so two iframes can both
|
|
40
|
+
// emit requestId="123", and the root↔child case has the same
|
|
41
|
+
// collision risk. Emit `null` for root (rather than undefined) so
|
|
42
|
+
// the field survives JSON serialization and agents can round-trip
|
|
43
|
+
// it back to get_request_body / get_response_body.
|
|
44
|
+
session_id: e.sessionId ?? null,
|
|
45
|
+
ts: e.ts,
|
|
46
|
+
method: e.method,
|
|
47
|
+
url: e.url,
|
|
48
|
+
type: e.resourceType,
|
|
49
|
+
status: e.status,
|
|
50
|
+
status_text: e.statusText,
|
|
51
|
+
mime_type: e.mimeType,
|
|
52
|
+
from_cache: e.fromCache,
|
|
53
|
+
finished: !!e.finished,
|
|
54
|
+
duration_ms: e.durationMs,
|
|
55
|
+
failure: e.failureReason,
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
registerJsonTool(server, "get_request_body", "Fetch the request body for a request ID. Often empty for GETs. Pass `session_id` from the get_network_requests item to disambiguate when child sessions have colliding request_ids. `null` = root.", {
|
|
60
|
+
request_id: z.string(),
|
|
61
|
+
session_id: z.string().nullable().optional().describe("From get_network_requests. null or omitted = root."),
|
|
62
|
+
max_chars: z.number().int().positive().optional(),
|
|
63
|
+
}, async (input) => {
|
|
64
|
+
const s = requireSession();
|
|
65
|
+
const max = input.max_chars ?? 4000;
|
|
66
|
+
// Normalize null→undefined for CDP. After normalization, sid is the
|
|
67
|
+
// session the agent intends (undefined = root, string = child).
|
|
68
|
+
const sid = input.session_id ?? undefined;
|
|
69
|
+
const entry = findEntry(s, input.request_id, sid);
|
|
70
|
+
try {
|
|
71
|
+
const r = await s.client.send("Network.getRequestPostData", { requestId: input.request_id }, sid ?? entry?.sessionId);
|
|
72
|
+
const body = r.postData ?? "";
|
|
73
|
+
return {
|
|
74
|
+
request_id: input.request_id,
|
|
75
|
+
body: truncate(body, max),
|
|
76
|
+
truncated_at: body.length > max ? max : null,
|
|
77
|
+
total_length: body.length,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
return { request_id: input.request_id, body: null, error: String(e) };
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
registerJsonTool(server, "get_response_body", "Fetch the response body for a request ID. Only safe when `finished: true` AND `failure` is absent in get_network_requests — failed requests are also `finished: true` but have no body. Pass `session_id` from the get_network_requests item to disambiguate cross-session request_id collisions. Binary payloads (base64_encoded=true) are returned as a clean base64 string — call Buffer.from(body, 'base64') to get raw bytes. Server does NOT decode binary to UTF-8 (which would corrupt PNGs/fonts/wasm/etc.) and does NOT truncate base64 bodies (truncation appended text characters that were inside the base64 alphabet, silently corrupting the tail bytes).", {
|
|
85
|
+
request_id: z.string(),
|
|
86
|
+
session_id: z.string().nullable().optional().describe("From get_network_requests. null or omitted = root."),
|
|
87
|
+
max_chars: z.number().int().positive().optional().describe("Only applied to TEXT responses; base64 payloads are returned in full"),
|
|
88
|
+
}, async (input) => {
|
|
89
|
+
const s = requireSession();
|
|
90
|
+
const max = input.max_chars ?? 4000;
|
|
91
|
+
const sid = input.session_id ?? undefined;
|
|
92
|
+
const entry = findEntry(s, input.request_id, sid);
|
|
93
|
+
try {
|
|
94
|
+
const r = await s.client.send("Network.getResponseBody", { requestId: input.request_id }, sid ?? entry?.sessionId);
|
|
95
|
+
const body = r.body;
|
|
96
|
+
// Text path: truncate freely. Base64 path: NEVER truncate — the old
|
|
97
|
+
// truncate() suffix "…(+N chars)" contains characters (digits, letters,
|
|
98
|
+
// `+`) that Node's lenient base64 decoder happily consumes as extra
|
|
99
|
+
// bytes, silently corrupting the tail of any binary response.
|
|
100
|
+
// Callers wanting more than the default should pass max_chars; for
|
|
101
|
+
// binary they get the whole thing.
|
|
102
|
+
if (r.base64Encoded) {
|
|
103
|
+
return {
|
|
104
|
+
request_id: input.request_id,
|
|
105
|
+
base64_encoded: true,
|
|
106
|
+
body,
|
|
107
|
+
truncated_at: null,
|
|
108
|
+
total_length: body.length,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
request_id: input.request_id,
|
|
113
|
+
base64_encoded: false,
|
|
114
|
+
body: truncate(body, max),
|
|
115
|
+
truncated_at: body.length > max ? max : null,
|
|
116
|
+
total_length: body.length,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
return { request_id: input.request_id, body: null, error: String(e) };
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Find the most-recent entry matching (requestId, sessionId). Strict match:
|
|
125
|
+
// omitted session_id means "root" (sessionId === undefined). The earlier
|
|
126
|
+
// permissive fallback (omitted matches any) created a root↔child collision
|
|
127
|
+
// hole — get_network_requests emits session_id:null for root entries
|
|
128
|
+
// (because JSON drops undefined), agents had no value to pass back, and the
|
|
129
|
+
// permissive filter then picked the most-recent matching requestId which
|
|
130
|
+
// could be a child entry, routing the body fetch to the wrong agent.
|
|
131
|
+
function findEntry(s, requestId, sessionId) {
|
|
132
|
+
return s.network.query({
|
|
133
|
+
filter: (e) => e.requestId === requestId && (e.sessionId ?? undefined) === sessionId,
|
|
134
|
+
limit: 1,
|
|
135
|
+
}).pop();
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/tools/network.ts"],"names":[],"mappings":"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"}
|