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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/dist/index.js +345 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/server.js +27 -0
  6. package/dist/server.js.map +1 -0
  7. package/dist/session/browser.js +394 -0
  8. package/dist/session/browser.js.map +1 -0
  9. package/dist/session/buffers.js +43 -0
  10. package/dist/session/buffers.js.map +1 -0
  11. package/dist/session/pause.js +99 -0
  12. package/dist/session/pause.js.map +1 -0
  13. package/dist/session/state.js +93 -0
  14. package/dist/session/state.js.map +1 -0
  15. package/dist/sourcemap/loader.js +138 -0
  16. package/dist/sourcemap/loader.js.map +1 -0
  17. package/dist/sourcemap/normalize.js +59 -0
  18. package/dist/sourcemap/normalize.js.map +1 -0
  19. package/dist/sourcemap/store.js +185 -0
  20. package/dist/sourcemap/store.js.map +1 -0
  21. package/dist/tools/_register.js +30 -0
  22. package/dist/tools/_register.js.map +1 -0
  23. package/dist/tools/breakpoints.js +164 -0
  24. package/dist/tools/breakpoints.js.map +1 -0
  25. package/dist/tools/console.js +48 -0
  26. package/dist/tools/console.js.map +1 -0
  27. package/dist/tools/dom.js +527 -0
  28. package/dist/tools/dom.js.map +1 -0
  29. package/dist/tools/execution.js +89 -0
  30. package/dist/tools/execution.js.map +1 -0
  31. package/dist/tools/inspect.js +178 -0
  32. package/dist/tools/inspect.js.map +1 -0
  33. package/dist/tools/nav.js +136 -0
  34. package/dist/tools/nav.js.map +1 -0
  35. package/dist/tools/network.js +137 -0
  36. package/dist/tools/network.js.map +1 -0
  37. package/dist/tools/session.js +76 -0
  38. package/dist/tools/session.js.map +1 -0
  39. package/dist/tools/source.js +63 -0
  40. package/dist/tools/source.js.map +1 -0
  41. package/dist/util/browser-resolve.js +263 -0
  42. package/dist/util/browser-resolve.js.map +1 -0
  43. package/dist/util/errors.js +12 -0
  44. package/dist/util/errors.js.map +1 -0
  45. package/dist/util/format.js +65 -0
  46. package/dist/util/format.js.map +1 -0
  47. package/dist/util/log.js +34 -0
  48. package/dist/util/log.js.map +1 -0
  49. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/session/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ import { log } from "../util/log.js";
2
+ // Wire up Debugger.scriptParsed to populate the store and lazily load source maps.
3
+ // Returns the registered handler so the caller can later `client.removeListener("Debugger.scriptParsed", handler)`.
4
+ export function attachScriptListener(client, store, sessionId) {
5
+ const handler = (params, eventSessionId) => {
6
+ // Each session sees its own events; gate strictly so root and children
7
+ // don't process each other's. (Strict equality — `if (sessionId && …)`
8
+ // was the original bug: sessionId=undefined made the gate vacuously
9
+ // false, so the root handler ran child events too.)
10
+ if (eventSessionId !== sessionId)
11
+ return;
12
+ if (!params.url) {
13
+ // anonymous inline scripts — skip; nothing to debug by file path
14
+ return;
15
+ }
16
+ store.upsert({
17
+ scriptId: params.scriptId,
18
+ url: params.url,
19
+ sourceMapURL: params.sourceMapURL || undefined,
20
+ startLine: params.startLine,
21
+ startColumn: params.startColumn,
22
+ endLine: params.endLine,
23
+ endColumn: params.endColumn,
24
+ executionContextId: params.executionContextId,
25
+ hash: params.hash,
26
+ isModule: params.isModule,
27
+ ...(sessionId ? { sessionId } : {}),
28
+ });
29
+ if (params.sourceMapURL) {
30
+ void loadSourceMap(client, store, params.scriptId, params.url, params.sourceMapURL, sessionId);
31
+ }
32
+ };
33
+ client.on("Debugger.scriptParsed", handler);
34
+ return handler;
35
+ }
36
+ async function loadSourceMap(client, store, scriptId, scriptUrl, sourceMapURL, sessionId) {
37
+ try {
38
+ let raw;
39
+ let mapUrl;
40
+ if (sourceMapURL.startsWith("data:")) {
41
+ raw = decodeDataUri(sourceMapURL);
42
+ mapUrl = scriptUrl;
43
+ }
44
+ else {
45
+ const resolved = new URL(sourceMapURL, scriptUrl).toString();
46
+ mapUrl = resolved;
47
+ raw = await fetchMap(client, resolved, sessionId);
48
+ }
49
+ store.attachMap(scriptId, sessionId, raw, mapUrl);
50
+ log.debug("source-map loaded", { scriptUrl, mapUrl });
51
+ }
52
+ catch (e) {
53
+ store.setLoadError(scriptId, sessionId, `fetch failed: ${String(e)}`);
54
+ log.warn("source-map fetch failed", { scriptUrl, sourceMapURL, error: String(e) });
55
+ }
56
+ }
57
+ // Decode a data: URI body, supporting the RFC 2397 multi-parameter form
58
+ // (`data:<type>;charset=utf-8;base64,…`) that webpack's `inline-source-map`
59
+ // devtool emits. The previous `[^,;]*` regex rejected anything with extra
60
+ // parameters between the type and `;base64`, so webpack-inlined source maps
61
+ // never loaded and TS-aware tools silently degraded to JS coords.
62
+ export function decodeDataUri(uri) {
63
+ if (!uri.startsWith("data:"))
64
+ throw new Error("Not a data URI");
65
+ const comma = uri.indexOf(",");
66
+ if (comma < 0)
67
+ throw new Error("Malformed data URI (no comma)");
68
+ const meta = uri.slice(5, comma); // between `data:` and `,`
69
+ const payload = uri.slice(comma + 1);
70
+ if (!payload)
71
+ throw new Error("Empty data URI payload");
72
+ const params = meta.split(";");
73
+ const isBase64 = params.includes("base64");
74
+ if (isBase64)
75
+ return Buffer.from(payload, "base64").toString("utf8");
76
+ return decodeURIComponent(payload);
77
+ }
78
+ async function fetchMap(client, url, sessionId) {
79
+ // Prefer using the browser's network stack so we go through the page's
80
+ // origin/CORS context (cookies, auth, dev-server middleware).
81
+ //
82
+ // CDP docs: `Network.loadNetworkResource.frameId` is "Mandatory for frame
83
+ // targets, and should be omitted for worker targets." Without it, the
84
+ // preferred browser-context path fails for page scripts and silently
85
+ // falls back to Node fetch — which works for plain localhost but loses
86
+ // the auth/cookie/origin context we actually want.
87
+ //
88
+ // Strategy: opportunistically resolve the top frame id via Page domain.
89
+ // It succeeds on page/OOPIF sessions, throws on worker sessions where
90
+ // Page is unavailable — exactly the two cases CDP wants us to handle.
91
+ let frameId;
92
+ try {
93
+ const tree = await client.Page.getFrameTree(sessionId);
94
+ frameId = tree.frameTree.frame.id;
95
+ }
96
+ catch {
97
+ // Worker / service-worker session — Page domain unavailable; omit frameId.
98
+ }
99
+ try {
100
+ const { resource } = await client.Network.loadNetworkResource({
101
+ ...(frameId ? { frameId } : {}),
102
+ url,
103
+ // includeCredentials: true — the whole point of the browser-context
104
+ // path is to inherit the page's auth (cookies, sessions, dev-server
105
+ // middleware). false would defeat the intent and bounce
106
+ // session-protected source maps back to the credential-less Node
107
+ // fetch fallback.
108
+ options: { disableCache: false, includeCredentials: true },
109
+ }, sessionId);
110
+ if (!resource?.success || !resource.stream) {
111
+ throw new Error(`loadNetworkResource failed: ${resource?.netError ?? resource?.httpStatusCode}`);
112
+ }
113
+ const first = await client.IO.read({ handle: resource.stream }, sessionId);
114
+ let combined = first.base64Encoded ? Buffer.from(first.data, "base64").toString("utf8") : first.data;
115
+ let eof = first.eof;
116
+ while (!eof) {
117
+ const next = await client.IO.read({ handle: resource.stream }, sessionId);
118
+ combined += next.base64Encoded ? Buffer.from(next.data, "base64").toString("utf8") : next.data;
119
+ eof = next.eof;
120
+ }
121
+ try {
122
+ await client.IO.close({ handle: resource.stream }, sessionId);
123
+ }
124
+ catch {
125
+ /* ignore */
126
+ }
127
+ return combined;
128
+ }
129
+ catch (browserErr) {
130
+ // Fallback: fetch directly from Node — works for localhost dev servers.
131
+ log.debug("loadNetworkResource failed, falling back to Node fetch", { url, error: String(browserErr) });
132
+ const res = await fetch(url);
133
+ if (!res.ok)
134
+ throw new Error(`HTTP ${res.status} fetching ${url}`);
135
+ return await res.text();
136
+ }
137
+ }
138
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/sourcemap/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ // Normalize the messy URLs that bundlers emit into source maps and CDP scripts.
2
+ //
3
+ // Examples we want to fold to "src/foo.ts":
4
+ // webpack:///./src/foo.ts
5
+ // webpack-internal:///./src/foo.ts
6
+ // webpack://app/./src/foo.ts
7
+ // ./src/foo.ts
8
+ // /src/foo.ts
9
+ // file:///C:/proj/src/foo.ts
10
+ //
11
+ // We don't try to resolve to an absolute on-disk path — we only need stable
12
+ // matching keys so a user-supplied "src/foo.ts" can be located.
13
+ const KNOWN_PREFIXES = [
14
+ /^webpack-internal:\/\/\/(?:\.\/)?/,
15
+ /^webpack:\/\/[^/]*\/(?:\.\/)?/,
16
+ /^webpack:\/\/\/(?:\.\/)?/,
17
+ /^rollup:\/\/(?:\.\/)?/,
18
+ /^vite-fs:\/\/(?:\.\/)?/,
19
+ /^source-map:\/\/(?:\.\/)?/,
20
+ ];
21
+ export function normalizeSourcePath(raw) {
22
+ if (!raw)
23
+ return raw;
24
+ let s = raw;
25
+ for (const re of KNOWN_PREFIXES) {
26
+ if (re.test(s)) {
27
+ s = s.replace(re, "");
28
+ break;
29
+ }
30
+ }
31
+ if (s.startsWith("file://")) {
32
+ s = s.slice("file://".length);
33
+ if (/^\/[A-Za-z]:/.test(s))
34
+ s = s.slice(1);
35
+ }
36
+ // strip a single leading slash for matching
37
+ if (s.startsWith("/"))
38
+ s = s.slice(1);
39
+ if (s.startsWith("./"))
40
+ s = s.slice(2);
41
+ return s.replace(/\\/g, "/");
42
+ }
43
+ // Does `candidate` look like the same file as `query`?
44
+ // We accept matches where one is a strict suffix of the other on path segments.
45
+ export function pathMatches(candidate, query) {
46
+ const c = normalizeSourcePath(candidate);
47
+ const q = normalizeSourcePath(query);
48
+ if (c === q)
49
+ return true;
50
+ const cs = c.split("/").filter(Boolean);
51
+ const qs = q.split("/").filter(Boolean);
52
+ if (cs.length === 0 || qs.length === 0)
53
+ return false;
54
+ if (cs.length >= qs.length) {
55
+ return cs.slice(-qs.length).join("/") === qs.join("/");
56
+ }
57
+ return qs.slice(-cs.length).join("/") === cs.join("/");
58
+ }
59
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/sourcemap/normalize.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,4CAA4C;AAC5C,4BAA4B;AAC5B,qCAAqC;AACrC,+BAA+B;AAC/B,iBAAiB;AACjB,gBAAgB;AAChB,+BAA+B;AAC/B,EAAE;AACF,4EAA4E;AAC5E,gEAAgE;AAEhE,MAAM,cAAc,GAAG;IACrB,mCAAmC;IACnC,+BAA+B;IAC/B,0BAA0B;IAC1B,uBAAuB;IACvB,wBAAwB;IACxB,2BAA2B;CAC5B,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,IAAI,CAAC,GAAG,GAAG,CAAC;IACZ,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;QAChC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACf,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACtB,MAAM;QACR,CAAC;IACH,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,4CAA4C;IAC5C,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,uDAAuD;AACvD,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,KAAa;IAC1D,MAAM,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,185 @@
1
+ import { SourceMapConsumer } from "@jridgewell/source-map";
2
+ import { normalizeSourcePath, pathMatches } from "./normalize.js";
3
+ import { log } from "../util/log.js";
4
+ // CDP scriptIds are scoped per Debugger agent (per flat session). Two
5
+ // targets — page + worker, or two iframes — can independently emit
6
+ // scriptId="42". Keying the store on scriptId alone would let the second
7
+ // upsert silently overwrite the first, attach the wrong source map, or
8
+ // resolve paused frames to the wrong script. Compound key is sessionId
9
+ // (or a synthetic root marker) + scriptId.
10
+ const ROOT_KEY = "__root__";
11
+ const keyFor = (scriptId, sessionId) => `${sessionId ?? ROOT_KEY} ${scriptId}`;
12
+ // Indexes scripts the browser has parsed and their (optional) source maps.
13
+ export class ScriptStore {
14
+ byKey = new Map();
15
+ // HMR / soft-reload note: when a script is re-parsed under the same
16
+ // (sessionId, scriptId), Object.assign(existing, info) copies the new
17
+ // metadata fields but does NOT overwrite `consumer`, `sources`, or
18
+ // `loadError` because they aren't in the upsert payload (the input type
19
+ // explicitly Omit<>'s them). A subsequent Debugger.scriptParsed for the
20
+ // *same* scriptId therefore inherits the OLD source-map consumer until
21
+ // attachMap() is called again. This is intentional for soft reloads
22
+ // (the source-map URL is usually the same), but means HMR-changed maps
23
+ // can leak stale mappings until the next session reset() clears them.
24
+ // close_session/switchTarget call ScriptStore.clear() so cross-session
25
+ // contamination is bounded — within a session, downstream callers must
26
+ // re-attachMap() after any reload that may have changed the map.
27
+ upsert(info) {
28
+ const key = keyFor(info.scriptId, info.sessionId);
29
+ const existing = this.byKey.get(key);
30
+ if (existing) {
31
+ Object.assign(existing, info);
32
+ }
33
+ else {
34
+ this.byKey.set(key, { ...info });
35
+ }
36
+ }
37
+ get(scriptId, sessionId) {
38
+ return this.byKey.get(keyFor(scriptId, sessionId));
39
+ }
40
+ all() {
41
+ return Array.from(this.byKey.values());
42
+ }
43
+ remove(scriptId, sessionId) {
44
+ this.byKey.delete(keyFor(scriptId, sessionId));
45
+ }
46
+ clear() {
47
+ for (const s of this.byKey.values())
48
+ s.consumer?.destroy();
49
+ this.byKey.clear();
50
+ }
51
+ // Find scripts whose source map references the given TS file.
52
+ findByOriginalSource(file) {
53
+ const matches = [];
54
+ for (const s of this.byKey.values()) {
55
+ if (!s.sources)
56
+ continue;
57
+ if (s.sources.some((src) => pathMatches(src, file))) {
58
+ matches.push(s);
59
+ }
60
+ }
61
+ return matches;
62
+ }
63
+ attachMap(scriptId, sessionId, raw, mapUrl) {
64
+ const script = this.byKey.get(keyFor(scriptId, sessionId));
65
+ if (!script)
66
+ return null;
67
+ try {
68
+ const consumer = new SourceMapConsumer(raw, mapUrl);
69
+ script.consumer = consumer;
70
+ script.sources = (consumer.sources ?? []).map((s) => normalizeSourcePath(s ?? ""));
71
+ script.loadError = undefined;
72
+ }
73
+ catch (e) {
74
+ script.loadError = `source-map parse failed: ${String(e)}`;
75
+ log.warn("source-map parse failed", { scriptId, sessionId, url: script.url, error: String(e) });
76
+ }
77
+ return script;
78
+ }
79
+ setLoadError(scriptId, sessionId, err) {
80
+ const s = this.byKey.get(keyFor(scriptId, sessionId));
81
+ if (s)
82
+ s.loadError = err;
83
+ }
84
+ }
85
+ // Helpers for converting CDP <-> source-map line numbering.
86
+ // CDP: 0-based line, 0-based column.
87
+ // source-map: 1-based line, 0-based column.
88
+ // Public tool API: 1-based line, 0-based column.
89
+ export function cdpToPublic(loc) {
90
+ return { line: loc.lineNumber + 1, column: loc.columnNumber ?? 0 };
91
+ }
92
+ export function publicToCdp(loc) {
93
+ return { lineNumber: loc.line - 1, columnNumber: loc.column ?? 0 };
94
+ }
95
+ // Translate a CDP-paused frame's location to a public TS location, if a map is available.
96
+ export function mapCdpToOriginal(store, frame, sessionId) {
97
+ const script = store.get(frame.scriptId, sessionId);
98
+ if (!script?.consumer)
99
+ return null;
100
+ const orig = script.consumer.originalPositionFor({
101
+ line: frame.lineNumber + 1, // source-map is 1-based
102
+ column: frame.columnNumber ?? 0,
103
+ });
104
+ if (orig.source == null || orig.line == null)
105
+ return null;
106
+ return {
107
+ file: normalizeSourcePath(orig.source),
108
+ line: orig.line, // already 1-based
109
+ column: orig.column ?? 0,
110
+ };
111
+ }
112
+ // Translate a public TS coord to one or more CDP coords for setBreakpointByUrl.
113
+ //
114
+ // Uses `allGeneratedPositionsFor` (NOT `generatedPositionFor`) because the
115
+ // latter requires an EXACT (line, column) match against the source map's
116
+ // emitted mappings — and esbuild/vite typically emit mappings only at
117
+ // statement starts (e.g., column 2 for an indented `return x;`), not at
118
+ // column 0. Setting a breakpoint at `handlers.ts:12` should land regardless
119
+ // of whether the caller supplied column 0 (the default) or the exact
120
+ // column of the first statement; `allGeneratedPositionsFor` enumerates
121
+ // every generated position for the source line, which is the contract
122
+ // debuggers want for breakpoint resolution. (PR #11 e2e bug — line 12 of
123
+ // the sample app has mappings at columns 2 and 9 but none at column 0.)
124
+ //
125
+ // If the source line has multiple generated positions across distinct
126
+ // generated lines (rare with single-line vite bundles, common after
127
+ // minification splits or with classic webpack), each is emitted as its
128
+ // own GeneratedLocation — Debugger.setBreakpointByUrl ends up binding at
129
+ // each, which is what users intuitively expect.
130
+ export function mapOriginalToGenerated(store, file, line, // 1-based
131
+ column = 0) {
132
+ const out = [];
133
+ for (const script of store.findByOriginalSource(file)) {
134
+ if (!script.consumer)
135
+ continue;
136
+ const sourceKey = pickSourceKey(script, file);
137
+ if (!sourceKey)
138
+ continue;
139
+ // Forward the caller's column. allGeneratedPositionsFor with column=0
140
+ // returns the first mapping on the source line (the line-broad case
141
+ // set_breakpoint uses by default). With a non-zero column it returns
142
+ // the mapping at-or-after that original column — honoring an
143
+ // explicitly-supplied column without forcing exact-match strictness.
144
+ // (Codex/Opus PR #11 round-2: prior version pinned column:0 here and
145
+ // silently ignored the caller's value.)
146
+ const positions = script.consumer.allGeneratedPositionsFor({
147
+ source: sourceKey,
148
+ line, // 1-based in
149
+ column,
150
+ });
151
+ // De-dup by (gen line, gen col) — different originalColumn mappings on
152
+ // the same source line can collapse to the same generated position
153
+ // after minification, but we only need one breakpoint binding per
154
+ // distinct generated location.
155
+ const seen = new Set();
156
+ for (const gen of positions) {
157
+ if (gen.line == null)
158
+ continue;
159
+ const key = `${gen.line}:${gen.column ?? 0}`;
160
+ if (seen.has(key))
161
+ continue;
162
+ seen.add(key);
163
+ out.push({
164
+ scriptId: script.scriptId,
165
+ scriptUrl: script.url,
166
+ ...(script.sessionId ? { sessionId: script.sessionId } : {}),
167
+ lineNumber: gen.line - 1, // back to 0-based for CDP
168
+ columnNumber: gen.column ?? 0,
169
+ });
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+ function pickSourceKey(script, file) {
175
+ if (!script.consumer)
176
+ return null;
177
+ // We want the source as it appears in the map (with whatever prefix it had)
178
+ // so the consumer can look it up.
179
+ for (const raw of script.consumer.sources ?? []) {
180
+ if (raw && pathMatches(raw, file))
181
+ return raw;
182
+ }
183
+ return null;
184
+ }
185
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sourcemap/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { ToolError } from "../util/errors.js";
2
+ import { log } from "../util/log.js";
3
+ import { toolJson, toolText } from "../util/format.js";
4
+ // Wrap a tool handler with consistent error handling so any thrown error
5
+ // becomes a structured `isError: true` result rather than an MCP transport error.
6
+ export function registerJsonTool(server, name, description, inputShape, handler) {
7
+ server.registerTool(name, {
8
+ description,
9
+ ...(inputShape ? { inputSchema: inputShape } : {}),
10
+ }, async (args) => {
11
+ try {
12
+ const result = await handler((args ?? {}));
13
+ if (result === undefined)
14
+ return toolText("ok");
15
+ if (typeof result === "string")
16
+ return toolText(result);
17
+ return toolJson(result);
18
+ }
19
+ catch (e) {
20
+ const code = e instanceof ToolError ? e.code : "internal_error";
21
+ const msg = e instanceof Error ? e.message : String(e);
22
+ log.warn(`tool error ${name}`, { code, msg });
23
+ return {
24
+ isError: true,
25
+ content: [{ type: "text", text: JSON.stringify({ error: code, message: msg }) }],
26
+ };
27
+ }
28
+ });
29
+ }
30
+ //# sourceMappingURL=_register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_register.js","sourceRoot":"","sources":["../../src/tools/_register.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEvD,yEAAyE;AACzE,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAC9B,MAAiB,EACjB,IAAY,EACZ,WAAmB,EACnB,UAA2C,EAC3C,OAAsD;IAEtD,MAAM,CAAC,YAAY,CACjB,IAAI,EACJ;QACE,WAAW;QACX,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,EACD,KAAK,EAAE,IAAS,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAW,CAAC,CAAC;YACrD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,CAAC,YAAY,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;YAChE,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvD,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;aAC1F,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,164 @@
1
+ import { z } from "zod";
2
+ import { requireSession, ROOT_SESSION_KEY } from "../session/state.js";
3
+ import { mapOriginalToGenerated, mapCdpToOriginal } from "../sourcemap/store.js";
4
+ import { ToolError } from "../util/errors.js";
5
+ import { registerJsonTool } from "./_register.js";
6
+ // Look up an existing breakpoint by normalized (file, line, column). Column
7
+ // is always a number here — the caller is responsible for collapsing an
8
+ // omitted or undefined `input.column` to 0 before calling, matching the
9
+ // `input.column ?? 0` shape that mapOriginalToGenerated and list_breakpoints
10
+ // already use. If the three normalizations ever diverge, set_breakpoint's
11
+ // idempotent path silently breaks (see PR #20 review).
12
+ function findBreakpointAt(breakpoints, file, line, column) {
13
+ for (const r of breakpoints.values()) {
14
+ if (r.file === file && r.line === line && (r.column ?? 0) === column)
15
+ return r;
16
+ }
17
+ return undefined;
18
+ }
19
+ function breakpointEnvelope(r, status) {
20
+ return {
21
+ id: r.id,
22
+ resolved_locations: r.resolvedLocations,
23
+ binding_count: r.bindings.length,
24
+ sessions_bound: Array.from(new Set(r.bindings.map((b) => b.sessionId ?? ROOT_SESSION_KEY))),
25
+ status,
26
+ };
27
+ }
28
+ export function registerBreakpointTools(server) {
29
+ registerJsonTool(server, "set_breakpoint", 'Set a breakpoint in TypeScript source. Resolves matching scripts via source maps (including in workers and iframes) and binds in each one\'s session. Returns the resolved JS->TS locations. Idempotent: re-calling with identical (file, line, column, condition, log_message) returns the existing breakpoint id with status: "already-set". Same location with a different condition/log_message returns error: "breakpoint_conflict" — remove the existing breakpoint first.', {
30
+ file: z.string().describe("TS file path or fragment (e.g. src/foo.ts)"),
31
+ line: z.number().int().positive().describe("1-based"),
32
+ column: z.number().int().nonnegative().optional(),
33
+ condition: z.string().optional().describe("Expression — pause only when truthy"),
34
+ log_message: z.string().optional().describe("Logpoint: log instead of pausing"),
35
+ }, async (input) => {
36
+ const s = requireSession();
37
+ // Normalize once at the top so lookup, mapping, and storage cannot
38
+ // drift. column collapses `undefined` and omitted to 0 — matching what
39
+ // mapOriginalToGenerated and list_breakpoints already do. condition /
40
+ // logMessage truthy-normalize so the empty string and undefined match.
41
+ const file = input.file;
42
+ const line = input.line;
43
+ const column = input.column ?? 0;
44
+ const condition = input.condition || undefined;
45
+ const logMessage = input.log_message || undefined;
46
+ const existing = findBreakpointAt(s.breakpoints, file, line, column);
47
+ if (existing) {
48
+ if (existing.condition === condition && existing.logMessage === logMessage) {
49
+ return breakpointEnvelope(existing, "already-set");
50
+ }
51
+ const locStr = `${file}:${line}:${column}`;
52
+ throw new ToolError("breakpoint_conflict", `Breakpoint already exists at ${locStr} (id ${existing.id}) with a different condition or log_message. Remove it first (remove_breakpoint) before setting a new one.`);
53
+ }
54
+ const candidates = mapOriginalToGenerated(s.scripts, file, line, column);
55
+ if (candidates.length === 0) {
56
+ throw new ToolError("no_mapping", `No source-mapped script matches '${file}:${line}'. Try list_scripts to confirm what's loaded.`);
57
+ }
58
+ const id = s.nextBpId();
59
+ const bindings = [];
60
+ const resolved = [];
61
+ const conditionExpr = buildConditionExpression(condition, logMessage);
62
+ for (const c of candidates) {
63
+ // Use the exact `url` field rather than `urlRegex`. CDP's regex is
64
+ // unanchored — `http://localhost/main.js` as a urlRegex also matches
65
+ // `http://localhost/main.js?v=2`, `…?vue&type=template`, etc.
66
+ const params = {
67
+ url: c.scriptUrl,
68
+ lineNumber: c.lineNumber,
69
+ columnNumber: c.columnNumber,
70
+ ...(conditionExpr ? { condition: conditionExpr } : {}),
71
+ };
72
+ const res = await s.client.send("Debugger.setBreakpointByUrl", params, c.sessionId);
73
+ bindings.push({ cdpId: res.breakpointId, ...(c.sessionId ? { sessionId: c.sessionId } : {}) });
74
+ for (const loc of res.locations) {
75
+ const orig = mapCdpToOriginal(s.scripts, loc, c.sessionId);
76
+ if (orig)
77
+ resolved.push(orig);
78
+ else
79
+ resolved.push({ file: c.scriptUrl, line: loc.lineNumber + 1, column: loc.columnNumber ?? 0 });
80
+ }
81
+ }
82
+ const record = {
83
+ id,
84
+ file,
85
+ line,
86
+ column,
87
+ ...(condition ? { condition } : {}),
88
+ ...(logMessage ? { logMessage } : {}),
89
+ resolvedLocations: resolved,
90
+ bindings,
91
+ };
92
+ s.breakpoints.set(id, record);
93
+ return breakpointEnvelope(record, "set");
94
+ });
95
+ registerJsonTool(server, "remove_breakpoint", "Remove a breakpoint by ID (returned from set_breakpoint).", { id: z.string() }, async (input) => {
96
+ const s = requireSession();
97
+ const rec = s.breakpoints.get(input.id);
98
+ if (!rec)
99
+ throw new ToolError("not_found", `No breakpoint with id ${input.id}`);
100
+ for (const b of rec.bindings) {
101
+ try {
102
+ await s.client.send("Debugger.removeBreakpoint", { breakpointId: b.cdpId }, b.sessionId);
103
+ }
104
+ catch {
105
+ /* ignore — session may already be gone */
106
+ }
107
+ }
108
+ s.breakpoints.delete(input.id);
109
+ return "removed";
110
+ });
111
+ registerJsonTool(server, "list_breakpoints", "List all currently active breakpoints.", undefined, async () => {
112
+ const s = requireSession();
113
+ return Array.from(s.breakpoints.values()).map((bp) => ({
114
+ id: bp.id,
115
+ file: bp.file,
116
+ line: bp.line,
117
+ column: bp.column ?? 0,
118
+ condition: bp.condition,
119
+ log_message: bp.logMessage,
120
+ resolved_locations: bp.resolvedLocations,
121
+ binding_count: bp.bindings.length,
122
+ }));
123
+ });
124
+ registerJsonTool(server, "set_pause_on_exceptions", "Configure whether the debugger pauses on exceptions. Applies to the root AND all currently-attached child sessions (workers/iframes/service workers), and is remembered so newly-attached children inherit the setting.", {
125
+ state: z.enum(["none", "uncaught", "all"]),
126
+ }, async (input) => {
127
+ const s = requireSession();
128
+ // Persist so onChildAttached can replay to future attachments.
129
+ s.pauseOnExceptions = input.state;
130
+ // Apply to every currently-attached session. ROOT_SESSION_KEY → undefined
131
+ // for the CDP call; child keys are the literal sessionId.
132
+ const targetSessions = [];
133
+ for (const key of s.sessionHandlers.keys()) {
134
+ targetSessions.push(key === ROOT_SESSION_KEY ? undefined : key);
135
+ }
136
+ if (targetSessions.length === 0)
137
+ targetSessions.push(undefined); // safety net
138
+ const results = await Promise.allSettled(targetSessions.map((sid) => s.client.send("Debugger.setPauseOnExceptions", { state: input.state }, sid)));
139
+ const failures = results
140
+ .map((r, i) => (r.status === "rejected" ? { sid: targetSessions[i] ?? "__root__", error: String(r.reason) } : null))
141
+ .filter((x) => x !== null);
142
+ return {
143
+ state: input.state,
144
+ sessions_applied: targetSessions.length - failures.length,
145
+ failures,
146
+ };
147
+ });
148
+ }
149
+ // Combine an optional `condition` predicate with an optional `logMessage`.
150
+ // Logpoint: emit a console.log and never pause (`false` short-circuits).
151
+ /** @internal exported for unit tests; not part of the MCP tool surface. */
152
+ export function buildConditionExpression(condition, logMessage) {
153
+ if (!condition && !logMessage)
154
+ return undefined;
155
+ if (logMessage) {
156
+ const tmpl = JSON.stringify(logMessage);
157
+ const log = `console.log(${tmpl}.replace(/\\{([^}]+)\\}/g, (m, expr) => { try { return String(eval(expr)); } catch (e) { return "{" + expr + "=?}"; } }))`;
158
+ if (condition)
159
+ return `(${condition}) && (${log}, false)`;
160
+ return `(${log}, false)`;
161
+ }
162
+ return condition;
163
+ }
164
+ //# sourceMappingURL=breakpoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakpoints.js","sourceRoot":"","sources":["../../src/tools/breakpoints.ts"],"names":[],"mappings":"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"}