cdp-mcp 0.2.1 → 0.4.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 +28 -303
- package/bin.js +23 -0
- package/contract.d.ts +1 -0
- package/contract.js +2 -0
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/package.json +31 -73
- package/dist/contract.d.ts +0 -11
- package/dist/contract.js +0 -11
- package/dist/contract.js.map +0 -1
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -402
- package/dist/index.js.map +0 -1
- package/dist/locator.d.ts +0 -108
- package/dist/locator.js +0 -176
- package/dist/locator.js.map +0 -1
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -41
- package/dist/server.js.map +0 -1
- package/dist/session/browser.d.ts +0 -29
- package/dist/session/browser.js +0 -409
- package/dist/session/browser.js.map +0 -1
- package/dist/session/buffers.d.ts +0 -48
- package/dist/session/buffers.js +0 -43
- package/dist/session/buffers.js.map +0 -1
- package/dist/session/pause.d.ts +0 -21
- package/dist/session/pause.js +0 -99
- package/dist/session/pause.js.map +0 -1
- package/dist/session/state.d.ts +0 -53
- package/dist/session/state.js +0 -93
- package/dist/session/state.js.map +0 -1
- package/dist/sourcemap/loader.d.ts +0 -4
- package/dist/sourcemap/loader.js +0 -138
- package/dist/sourcemap/loader.js.map +0 -1
- package/dist/sourcemap/normalize.d.ts +0 -2
- package/dist/sourcemap/normalize.js +0 -59
- package/dist/sourcemap/normalize.js.map +0 -1
- package/dist/sourcemap/store.d.ts +0 -57
- package/dist/sourcemap/store.js +0 -185
- package/dist/sourcemap/store.js.map +0 -1
- package/dist/tools/_locator_runtime.d.ts +0 -31
- package/dist/tools/_locator_runtime.js +0 -243
- package/dist/tools/_locator_runtime.js.map +0 -1
- package/dist/tools/_register.d.ts +0 -2
- package/dist/tools/_register.js +0 -30
- package/dist/tools/_register.js.map +0 -1
- package/dist/tools/breakpoints.d.ts +0 -4
- package/dist/tools/breakpoints.js +0 -164
- package/dist/tools/breakpoints.js.map +0 -1
- package/dist/tools/console.d.ts +0 -2
- package/dist/tools/console.js +0 -48
- package/dist/tools/console.js.map +0 -1
- package/dist/tools/dom.d.ts +0 -2
- package/dist/tools/dom.js +0 -309
- package/dist/tools/dom.js.map +0 -1
- package/dist/tools/execution.d.ts +0 -29
- package/dist/tools/execution.js +0 -89
- package/dist/tools/execution.js.map +0 -1
- package/dist/tools/forms.d.ts +0 -8
- package/dist/tools/forms.js +0 -256
- package/dist/tools/forms.js.map +0 -1
- package/dist/tools/inspect.d.ts +0 -2
- package/dist/tools/inspect.js +0 -178
- package/dist/tools/inspect.js.map +0 -1
- package/dist/tools/nav.d.ts +0 -2
- package/dist/tools/nav.js +0 -136
- package/dist/tools/nav.js.map +0 -1
- package/dist/tools/network.d.ts +0 -2
- package/dist/tools/network.js +0 -137
- package/dist/tools/network.js.map +0 -1
- package/dist/tools/session.d.ts +0 -2
- package/dist/tools/session.js +0 -76
- package/dist/tools/session.js.map +0 -1
- package/dist/tools/source.d.ts +0 -2
- package/dist/tools/source.js +0 -63
- package/dist/tools/source.js.map +0 -1
- package/dist/tools/storage.d.ts +0 -2
- package/dist/tools/storage.js +0 -296
- package/dist/tools/storage.js.map +0 -1
- package/dist/util/browser-resolve.d.ts +0 -19
- package/dist/util/browser-resolve.js +0 -263
- package/dist/util/browser-resolve.js.map +0 -1
- package/dist/util/errors.d.ts +0 -7
- package/dist/util/errors.js +0 -12
- package/dist/util/errors.js.map +0 -1
- package/dist/util/format.d.ts +0 -20
- package/dist/util/format.js +0 -65
- package/dist/util/format.js.map +0 -1
- package/dist/util/log.d.ts +0 -6
- package/dist/util/log.js +0 -34
- package/dist/util/log.js.map +0 -1
- package/docs/chromium-sandboxing.md +0 -197
- package/docs/known-chromium-gaps.md +0 -138
- package/docs/launchd-service.md +0 -217
- package/docs/local-l3-e2e-setup.md +0 -199
- package/docs/systemd-service.md +0 -233
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { SourceMapConsumer } from "@jridgewell/source-map";
|
|
2
|
-
import type { Protocol } from "devtools-protocol";
|
|
3
|
-
export interface ScriptInfo {
|
|
4
|
-
scriptId: string;
|
|
5
|
-
url: string;
|
|
6
|
-
sourceMapURL?: string;
|
|
7
|
-
startLine: number;
|
|
8
|
-
startColumn: number;
|
|
9
|
-
endLine: number;
|
|
10
|
-
endColumn: number;
|
|
11
|
-
executionContextId: number;
|
|
12
|
-
hash: string;
|
|
13
|
-
isModule?: boolean;
|
|
14
|
-
sessionId?: string;
|
|
15
|
-
consumer?: SourceMapConsumer;
|
|
16
|
-
sources?: string[];
|
|
17
|
-
loadError?: string;
|
|
18
|
-
}
|
|
19
|
-
export declare class ScriptStore {
|
|
20
|
-
private byKey;
|
|
21
|
-
upsert(info: Omit<ScriptInfo, "consumer" | "sources" | "loadError">): void;
|
|
22
|
-
get(scriptId: string, sessionId?: string): ScriptInfo | undefined;
|
|
23
|
-
all(): ScriptInfo[];
|
|
24
|
-
remove(scriptId: string, sessionId?: string): void;
|
|
25
|
-
clear(): void;
|
|
26
|
-
findByOriginalSource(file: string): ScriptInfo[];
|
|
27
|
-
attachMap(scriptId: string, sessionId: string | undefined, raw: string, mapUrl?: string): ScriptInfo | null;
|
|
28
|
-
setLoadError(scriptId: string, sessionId: string | undefined, err: string): void;
|
|
29
|
-
}
|
|
30
|
-
export declare function cdpToPublic(loc: {
|
|
31
|
-
lineNumber: number;
|
|
32
|
-
columnNumber?: number;
|
|
33
|
-
}): {
|
|
34
|
-
line: number;
|
|
35
|
-
column: number;
|
|
36
|
-
};
|
|
37
|
-
export declare function publicToCdp(loc: {
|
|
38
|
-
line: number;
|
|
39
|
-
column?: number;
|
|
40
|
-
}): {
|
|
41
|
-
lineNumber: number;
|
|
42
|
-
columnNumber: number;
|
|
43
|
-
};
|
|
44
|
-
export declare function mapCdpToOriginal(store: ScriptStore, frame: Pick<Protocol.Debugger.CallFrame["location"], "scriptId" | "lineNumber" | "columnNumber">, sessionId: string | undefined): {
|
|
45
|
-
file: string;
|
|
46
|
-
line: number;
|
|
47
|
-
column: number;
|
|
48
|
-
} | null;
|
|
49
|
-
export interface GeneratedLocation {
|
|
50
|
-
scriptId: string;
|
|
51
|
-
scriptUrl: string;
|
|
52
|
-
sessionId?: string;
|
|
53
|
-
lineNumber: number;
|
|
54
|
-
columnNumber: number;
|
|
55
|
-
}
|
|
56
|
-
export declare function mapOriginalToGenerated(store: ScriptStore, file: string, line: number, // 1-based
|
|
57
|
-
column?: number): GeneratedLocation[];
|
package/dist/sourcemap/store.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sourcemap/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type LocatorSpec } from "../locator.js";
|
|
2
|
-
/**
|
|
3
|
-
* Normalize a LocatorSpec for tool use, surfacing failures as the repo's
|
|
4
|
-
* structured `ToolError` (historically `missing_arg`) instead of the contract's
|
|
5
|
-
* plain `LocatorError`.
|
|
6
|
-
*/
|
|
7
|
-
export declare function normalizeLocator(input: LocatorSpec): LocatorSpec;
|
|
8
|
-
/**
|
|
9
|
-
* In-page helper library: text/visibility utilities, the accessibility
|
|
10
|
-
* heuristics (`implicitRole`, `accessibleName`, `cssPath`), `elementInfo`, and
|
|
11
|
-
* `findElements(spec)`. Inject this into a `Runtime.evaluate` expression before
|
|
12
|
-
* `locatorReadScript()` or `mutationHelpersScript()`.
|
|
13
|
-
*/
|
|
14
|
-
export declare function locatorHelpersScript(): string;
|
|
15
|
-
/**
|
|
16
|
-
* The read-only `locate(spec, options)` entry. Compose after
|
|
17
|
-
* `locatorHelpersScript()`; returns `{ ok, error?, found, count, visible_count, matches }`.
|
|
18
|
-
*/
|
|
19
|
-
export declare function locatorReadScript(): string;
|
|
20
|
-
/**
|
|
21
|
-
* Mutation helpers for the form-driving tools. Compose after
|
|
22
|
-
* `locatorHelpersScript()`:
|
|
23
|
-
* - `resolveOne(spec)` → `{ ok, el?, count, visible_count, error?, code? }`,
|
|
24
|
-
* preferring visible matches (the same visible-first bias `locate` reports)
|
|
25
|
-
* and picking the first match. On failure `code` distinguishes an
|
|
26
|
-
* invalid/unsupported locator (`invalid_locator`, mirroring locate/wait_for)
|
|
27
|
-
* from a valid locator that matched nothing (`not_found`).
|
|
28
|
-
* - `fireEvents(el, types)` → dispatch bubbling events (e.g. `input`/`change`)
|
|
29
|
-
* so app frameworks observe a programmatic mutation.
|
|
30
|
-
*/
|
|
31
|
-
export declare function mutationHelpersScript(): string;
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared, tools-side locator plumbing.
|
|
3
|
-
*
|
|
4
|
-
* The canonical LocatorSpec contract lives in `../locator.ts` (zod-only, public).
|
|
5
|
-
* This module adds the parts that are specific to running locators *inside the
|
|
6
|
-
* page* and to the cdp-mcp tool error envelope:
|
|
7
|
-
* - `normalizeLocator` — the contract normalizer, re-wrapping `LocatorError`
|
|
8
|
-
* as the repo's structured `ToolError` (preserving its error code).
|
|
9
|
-
* - `locatorHelpersScript()` — the in-page helper library (accessibility
|
|
10
|
-
* heuristics, visibility, `findElements`, `elementInfo`).
|
|
11
|
-
* - `locatorReadScript()` — the read-only `locate(spec, options)` entry.
|
|
12
|
-
* - `mutationHelpersScript()` — `resolveOne(spec)` + `fireEvents(el, types)`,
|
|
13
|
-
* used by the form-driving tools to resolve and mutate an element with the
|
|
14
|
-
* exact same matching semantics as `locate`.
|
|
15
|
-
*
|
|
16
|
-
* Both `dom.ts` (read) and the form-driving tools (drive) compose these so a
|
|
17
|
-
* locator behaves identically whether it is queried or acted upon.
|
|
18
|
-
*/
|
|
19
|
-
import { ToolError } from "../util/errors.js";
|
|
20
|
-
import { normalizeLocator as normalizeLocatorContract, LocatorError, } from "../locator.js";
|
|
21
|
-
/**
|
|
22
|
-
* Normalize a LocatorSpec for tool use, surfacing failures as the repo's
|
|
23
|
-
* structured `ToolError` (historically `missing_arg`) instead of the contract's
|
|
24
|
-
* plain `LocatorError`.
|
|
25
|
-
*/
|
|
26
|
-
export function normalizeLocator(input) {
|
|
27
|
-
try {
|
|
28
|
-
return normalizeLocatorContract(input);
|
|
29
|
-
}
|
|
30
|
-
catch (e) {
|
|
31
|
-
if (e instanceof LocatorError)
|
|
32
|
-
throw new ToolError(e.code, e.message);
|
|
33
|
-
throw e;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* In-page helper library: text/visibility utilities, the accessibility
|
|
38
|
-
* heuristics (`implicitRole`, `accessibleName`, `cssPath`), `elementInfo`, and
|
|
39
|
-
* `findElements(spec)`. Inject this into a `Runtime.evaluate` expression before
|
|
40
|
-
* `locatorReadScript()` or `mutationHelpersScript()`.
|
|
41
|
-
*/
|
|
42
|
-
export function locatorHelpersScript() {
|
|
43
|
-
return String.raw `
|
|
44
|
-
const compact = (value) => (value || "").replace(/\s+/g, " ").trim();
|
|
45
|
-
const lower = (value) => compact(value).toLowerCase();
|
|
46
|
-
const cssEscape = (value) => globalThis.CSS?.escape ? globalThis.CSS.escape(value) : String(value).replace(/["\\]/g, "\\$&");
|
|
47
|
-
const matchesText = (actual, expected, exact) => {
|
|
48
|
-
if (expected == null || expected === "") return true;
|
|
49
|
-
const a = lower(actual);
|
|
50
|
-
const e = lower(expected);
|
|
51
|
-
return exact ? a === e : a.includes(e);
|
|
52
|
-
};
|
|
53
|
-
const textOf = (el) => compact(el.innerText || el.textContent || "");
|
|
54
|
-
const isVisible = (el) => {
|
|
55
|
-
if (!el.isConnected) return false;
|
|
56
|
-
const style = getComputedStyle(el);
|
|
57
|
-
if (style.visibility === "hidden" || style.display === "none" || Number(style.opacity) === 0) return false;
|
|
58
|
-
const rect = el.getBoundingClientRect();
|
|
59
|
-
return rect.width > 0 && rect.height > 0;
|
|
60
|
-
};
|
|
61
|
-
const labelText = (el) => {
|
|
62
|
-
if ("labels" in el && el.labels && el.labels.length > 0) {
|
|
63
|
-
return compact(Array.from(el.labels).map((label) => label.innerText || label.textContent || "").join(" "));
|
|
64
|
-
}
|
|
65
|
-
return "";
|
|
66
|
-
};
|
|
67
|
-
const accessibleName = (el) => {
|
|
68
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
69
|
-
if (ariaLabel) return compact(ariaLabel);
|
|
70
|
-
const labelledBy = el.getAttribute("aria-labelledby");
|
|
71
|
-
if (labelledBy) {
|
|
72
|
-
const text = labelledBy
|
|
73
|
-
.split(/\s+/)
|
|
74
|
-
.map((id) => document.getElementById(id)?.innerText || document.getElementById(id)?.textContent || "")
|
|
75
|
-
.join(" ");
|
|
76
|
-
if (compact(text)) return compact(text);
|
|
77
|
-
}
|
|
78
|
-
const label = labelText(el);
|
|
79
|
-
if (label) return label;
|
|
80
|
-
if (el instanceof HTMLInputElement && ["button", "submit", "reset"].includes(el.type)) return compact(el.value);
|
|
81
|
-
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) return compact(el.placeholder || el.value || "");
|
|
82
|
-
if (el instanceof HTMLImageElement) return compact(el.alt || "");
|
|
83
|
-
return textOf(el);
|
|
84
|
-
};
|
|
85
|
-
const implicitRole = (el) => {
|
|
86
|
-
const explicit = el.getAttribute("role");
|
|
87
|
-
if (explicit) return lower(explicit.split(/\s+/)[0]);
|
|
88
|
-
const tag = el.tagName.toLowerCase();
|
|
89
|
-
if (tag === "button") return "button";
|
|
90
|
-
if (tag === "a" && el.hasAttribute("href")) return "link";
|
|
91
|
-
if (/^h[1-6]$/.test(tag)) return "heading";
|
|
92
|
-
if (tag === "textarea") return "textbox";
|
|
93
|
-
if (tag === "select") return el.multiple ? "listbox" : "combobox";
|
|
94
|
-
if (tag === "img") return "img";
|
|
95
|
-
if (el.isContentEditable) return "textbox";
|
|
96
|
-
if (tag === "input") {
|
|
97
|
-
const type = lower(el.getAttribute("type") || "text");
|
|
98
|
-
if (["button", "submit", "reset"].includes(type)) return "button";
|
|
99
|
-
if (type === "checkbox") return "checkbox";
|
|
100
|
-
if (type === "radio") return "radio";
|
|
101
|
-
if (type === "range") return "slider";
|
|
102
|
-
if (["email", "password", "search", "tel", "text", "url", ""].includes(type)) return "textbox";
|
|
103
|
-
if (type === "number") return "spinbutton";
|
|
104
|
-
}
|
|
105
|
-
return "";
|
|
106
|
-
};
|
|
107
|
-
const cssPath = (el) => {
|
|
108
|
-
if (el.id) return "#" + cssEscape(el.id);
|
|
109
|
-
const testId = el.getAttribute("data-testid") || el.getAttribute("data-test-id") || el.getAttribute("data-test");
|
|
110
|
-
if (testId) return "[" + (el.hasAttribute("data-testid") ? "data-testid" : el.hasAttribute("data-test-id") ? "data-test-id" : "data-test") + "=\"" + cssEscape(testId) + "\"]";
|
|
111
|
-
const parts = [];
|
|
112
|
-
let node = el;
|
|
113
|
-
while (node && node.nodeType === Node.ELEMENT_NODE && parts.length < 5) {
|
|
114
|
-
const tag = node.tagName.toLowerCase();
|
|
115
|
-
const name = node.getAttribute("name");
|
|
116
|
-
if (name) {
|
|
117
|
-
parts.unshift(tag + "[name=\"" + cssEscape(name) + "\"]");
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
const siblings = Array.from(node.parentElement?.children || []).filter((child) => child.tagName === node.tagName);
|
|
121
|
-
const index = siblings.indexOf(node) + 1;
|
|
122
|
-
parts.unshift(siblings.length > 1 ? tag + ":nth-of-type(" + index + ")" : tag);
|
|
123
|
-
node = node.parentElement;
|
|
124
|
-
}
|
|
125
|
-
return parts.join(" > ");
|
|
126
|
-
};
|
|
127
|
-
const elementInfo = (el) => {
|
|
128
|
-
const rect = el.getBoundingClientRect();
|
|
129
|
-
const info = {
|
|
130
|
-
selector: cssPath(el),
|
|
131
|
-
tag: el.tagName.toLowerCase(),
|
|
132
|
-
role: implicitRole(el) || undefined,
|
|
133
|
-
name: accessibleName(el) || undefined,
|
|
134
|
-
text: textOf(el).slice(0, 300),
|
|
135
|
-
visible: isVisible(el),
|
|
136
|
-
disabled: "disabled" in el ? !!el.disabled : undefined,
|
|
137
|
-
value: "value" in el ? el.value : undefined,
|
|
138
|
-
checked: "checked" in el ? !!el.checked : undefined,
|
|
139
|
-
bbox: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
140
|
-
};
|
|
141
|
-
return Object.fromEntries(Object.entries(info).filter(([, value]) => value !== undefined && value !== ""));
|
|
142
|
-
};
|
|
143
|
-
const queryAll = (selector) => {
|
|
144
|
-
try {
|
|
145
|
-
return { ok: true, elements: Array.from(document.querySelectorAll(selector)) };
|
|
146
|
-
} catch (error) {
|
|
147
|
-
return { ok: false, error: "Invalid CSS selector " + selector + ": " + error.message };
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
const leafTextMatches = (el, expected, exact) => {
|
|
151
|
-
if (!matchesText(textOf(el), expected, exact)) return false;
|
|
152
|
-
return !Array.from(el.children).some((child) => matchesText(textOf(child), expected, exact));
|
|
153
|
-
};
|
|
154
|
-
const findElements = (spec) => {
|
|
155
|
-
const by = spec.by || (spec.selector || spec.css ? "css" : "");
|
|
156
|
-
const exact = !!spec.exact;
|
|
157
|
-
if (by === "css") return queryAll(spec.selector || spec.css);
|
|
158
|
-
if (by === "text") {
|
|
159
|
-
return { ok: true, elements: Array.from(document.querySelectorAll("body *")).filter((el) => leafTextMatches(el, spec.text || spec.name, exact)) };
|
|
160
|
-
}
|
|
161
|
-
if (by === "role") {
|
|
162
|
-
return { ok: true, elements: Array.from(document.querySelectorAll("body *")).filter((el) => implicitRole(el) === lower(spec.role) && matchesText(accessibleName(el), spec.name, exact)) };
|
|
163
|
-
}
|
|
164
|
-
if (by === "test_id" || by === "testId") {
|
|
165
|
-
const wanted = spec.test_id || spec.testId || spec.name;
|
|
166
|
-
const candidates = Array.from(document.querySelectorAll("[data-testid], [data-test-id], [data-test]"));
|
|
167
|
-
return { ok: true, elements: candidates.filter((el) => [el.getAttribute("data-testid"), el.getAttribute("data-test-id"), el.getAttribute("data-test")].some((value) => matchesText(value, wanted, true))) };
|
|
168
|
-
}
|
|
169
|
-
if (by === "label") {
|
|
170
|
-
const wanted = spec.label || spec.name;
|
|
171
|
-
const controls = [];
|
|
172
|
-
for (const label of Array.from(document.querySelectorAll("label"))) {
|
|
173
|
-
if (!matchesText(textOf(label), wanted, exact)) continue;
|
|
174
|
-
const control = label.control || label.querySelector("input, textarea, select, button");
|
|
175
|
-
if (control) controls.push(control);
|
|
176
|
-
}
|
|
177
|
-
return { ok: true, elements: controls };
|
|
178
|
-
}
|
|
179
|
-
if (by === "placeholder") {
|
|
180
|
-
const wanted = spec.placeholder || spec.name;
|
|
181
|
-
return { ok: true, elements: Array.from(document.querySelectorAll("[placeholder]")).filter((el) => matchesText(el.getAttribute("placeholder"), wanted, exact)) };
|
|
182
|
-
}
|
|
183
|
-
if (by === "name") {
|
|
184
|
-
return { ok: true, elements: Array.from(document.querySelectorAll("[name]")).filter((el) => matchesText(el.getAttribute("name"), spec.name, true)) };
|
|
185
|
-
}
|
|
186
|
-
return { ok: false, error: "Unsupported locator strategy: " + by };
|
|
187
|
-
};
|
|
188
|
-
`;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* The read-only `locate(spec, options)` entry. Compose after
|
|
192
|
-
* `locatorHelpersScript()`; returns `{ ok, error?, found, count, visible_count, matches }`.
|
|
193
|
-
*/
|
|
194
|
-
export function locatorReadScript() {
|
|
195
|
-
return String.raw `
|
|
196
|
-
const locate = (spec, options) => {
|
|
197
|
-
const found = findElements(spec);
|
|
198
|
-
if (!found.ok) return { ok: false, error: found.error, found: false, count: 0, visible_count: 0, matches: [] };
|
|
199
|
-
const all = found.elements;
|
|
200
|
-
const visible = all.filter(isVisible);
|
|
201
|
-
const returned = (options.includeHidden ? all : visible).slice(0, options.limit || 20).map(elementInfo);
|
|
202
|
-
return {
|
|
203
|
-
ok: true,
|
|
204
|
-
found: returned.length > 0,
|
|
205
|
-
count: all.length,
|
|
206
|
-
visible_count: visible.length,
|
|
207
|
-
matches: returned,
|
|
208
|
-
};
|
|
209
|
-
};
|
|
210
|
-
`;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Mutation helpers for the form-driving tools. Compose after
|
|
214
|
-
* `locatorHelpersScript()`:
|
|
215
|
-
* - `resolveOne(spec)` → `{ ok, el?, count, visible_count, error?, code? }`,
|
|
216
|
-
* preferring visible matches (the same visible-first bias `locate` reports)
|
|
217
|
-
* and picking the first match. On failure `code` distinguishes an
|
|
218
|
-
* invalid/unsupported locator (`invalid_locator`, mirroring locate/wait_for)
|
|
219
|
-
* from a valid locator that matched nothing (`not_found`).
|
|
220
|
-
* - `fireEvents(el, types)` → dispatch bubbling events (e.g. `input`/`change`)
|
|
221
|
-
* so app frameworks observe a programmatic mutation.
|
|
222
|
-
*/
|
|
223
|
-
export function mutationHelpersScript() {
|
|
224
|
-
return String.raw `
|
|
225
|
-
const resolveOne = (spec) => {
|
|
226
|
-
const found = findElements(spec);
|
|
227
|
-
// findElements only returns !ok for an invalid/unsupported locator (bad CSS
|
|
228
|
-
// selector or unknown strategy) — the same condition locate/wait_for report
|
|
229
|
-
// as invalid_locator. A valid locator that simply matches nothing is the
|
|
230
|
-
// distinct not_found case below.
|
|
231
|
-
if (!found.ok) return { ok: false, error: found.error, code: "invalid_locator" };
|
|
232
|
-
const all = found.elements;
|
|
233
|
-
const visible = all.filter(isVisible);
|
|
234
|
-
const pick = visible.length ? visible : all;
|
|
235
|
-
if (pick.length === 0) return { ok: false, error: "no element matches locator", code: "not_found" };
|
|
236
|
-
return { ok: true, el: pick[0], count: all.length, visible_count: visible.length };
|
|
237
|
-
};
|
|
238
|
-
const fireEvents = (el, types) => {
|
|
239
|
-
for (const t of types) el.dispatchEvent(new Event(t, { bubbles: true }));
|
|
240
|
-
};
|
|
241
|
-
`;
|
|
242
|
-
}
|
|
243
|
-
//# sourceMappingURL=_locator_runtime.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"_locator_runtime.js","sourceRoot":"","sources":["../../src/tools/_locator_runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,gBAAgB,IAAI,wBAAwB,EAC5C,YAAY,GAEb,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,IAAI,CAAC;QACH,OAAO,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,YAAY;YAAE,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QACtE,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiJhB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;GAehB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;GAiBhB,CAAC;AACJ,CAAC"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
export declare function registerJsonTool<TInput extends Record<string, any>>(server: McpServer, name: string, description: string, inputShape: Record<string, any> | undefined, handler: (input: TInput) => Promise<unknown> | unknown): void;
|
package/dist/tools/_register.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
export declare function registerBreakpointTools(server: McpServer): void;
|
|
3
|
-
/** @internal exported for unit tests; not part of the MCP tool surface. */
|
|
4
|
-
export declare function buildConditionExpression(condition?: string, logMessage?: string): string | undefined;
|