chrome-devtools-axi 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/dist/bin/chrome-devtools-axi.d.ts +2 -0
- package/dist/bin/chrome-devtools-axi.js +4 -0
- package/dist/bin/chrome-devtools-axi.js.map +1 -0
- package/dist/src/bridge.d.ts +13 -0
- package/dist/src/bridge.js +109 -0
- package/dist/src/bridge.js.map +1 -0
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +287 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.d.ts +21 -0
- package/dist/src/client.js +204 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/snapshot.d.ts +13 -0
- package/dist/src/snapshot.js +32 -0
- package/dist/src/snapshot.js.map +1 -0
- package/dist/src/suggestions.d.ts +6 -0
- package/dist/src/suggestions.js +49 -0
- package/dist/src/suggestions.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kun Chen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chrome-devtools-axi.js","sourceRoot":"","sources":["../../bin/chrome-devtools-axi.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Persistent MCP bridge server for chrome-devtools-axi.
|
|
4
|
+
*
|
|
5
|
+
* Spawns chrome-devtools-mcp as a child process and maintains a single
|
|
6
|
+
* persistent MCP session. Exposes a simple HTTP API:
|
|
7
|
+
* POST /call { name, args } → { result }
|
|
8
|
+
* GET /tools → [{ name, description }]
|
|
9
|
+
* GET /health → { status: "ok" }
|
|
10
|
+
*
|
|
11
|
+
* Writes a PID file to ~/.chrome-devtools-axi/bridge.pid on startup.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Persistent MCP bridge server for chrome-devtools-axi.
|
|
4
|
+
*
|
|
5
|
+
* Spawns chrome-devtools-mcp as a child process and maintains a single
|
|
6
|
+
* persistent MCP session. Exposes a simple HTTP API:
|
|
7
|
+
* POST /call { name, args } → { result }
|
|
8
|
+
* GET /tools → [{ name, description }]
|
|
9
|
+
* GET /health → { status: "ok" }
|
|
10
|
+
*
|
|
11
|
+
* Writes a PID file to ~/.chrome-devtools-axi/bridge.pid on startup.
|
|
12
|
+
*/
|
|
13
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
14
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
15
|
+
import { createServer } from "node:http";
|
|
16
|
+
import { mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
const PORT = parseInt(process.env.CHROME_DEVTOOLS_AXI_PORT ?? "9224", 10);
|
|
20
|
+
const STATE_DIR = join(homedir(), ".chrome-devtools-axi");
|
|
21
|
+
const PID_FILE = join(STATE_DIR, "bridge.pid");
|
|
22
|
+
function writePidFile(port) {
|
|
23
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
24
|
+
writeFileSync(PID_FILE, JSON.stringify({ pid: process.pid, port }));
|
|
25
|
+
}
|
|
26
|
+
function removePidFile() {
|
|
27
|
+
try {
|
|
28
|
+
unlinkSync(PID_FILE);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Already gone — fine
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function main() {
|
|
35
|
+
// Connect to chrome-devtools-mcp via stdio
|
|
36
|
+
const transport = new StdioClientTransport({
|
|
37
|
+
command: "npx",
|
|
38
|
+
args: ["-y", "chrome-devtools-mcp@latest", "--headless", "--isolated"],
|
|
39
|
+
});
|
|
40
|
+
const client = new Client({ name: "chrome-devtools-axi-bridge", version: "1.0.0" });
|
|
41
|
+
await client.connect(transport);
|
|
42
|
+
console.error(`[chrome-devtools-axi] Connected to chrome-devtools-mcp`);
|
|
43
|
+
const server = createServer(async (req, res) => {
|
|
44
|
+
res.setHeader("Content-Type", "application/json");
|
|
45
|
+
if (req.method === "GET" && req.url === "/health") {
|
|
46
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (req.method === "GET" && req.url === "/tools") {
|
|
50
|
+
try {
|
|
51
|
+
const result = await client.listTools();
|
|
52
|
+
const tools = result.tools.map((t) => ({
|
|
53
|
+
name: t.name,
|
|
54
|
+
description: t.description,
|
|
55
|
+
}));
|
|
56
|
+
res.end(JSON.stringify(tools));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
res.statusCode = 500;
|
|
60
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (req.method === "POST" && req.url === "/call") {
|
|
65
|
+
let body = "";
|
|
66
|
+
for await (const chunk of req)
|
|
67
|
+
body += chunk;
|
|
68
|
+
try {
|
|
69
|
+
const { name, args } = JSON.parse(body);
|
|
70
|
+
const result = await client.callTool({ name, arguments: args ?? {} });
|
|
71
|
+
const parts = [];
|
|
72
|
+
for (const block of result.content) {
|
|
73
|
+
if (block.type === "text" && block.text)
|
|
74
|
+
parts.push(block.text);
|
|
75
|
+
}
|
|
76
|
+
res.end(JSON.stringify({ result: parts.join("\n") }));
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
res.statusCode = 500;
|
|
80
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
res.statusCode = 404;
|
|
85
|
+
res.end(JSON.stringify({ error: "not found" }));
|
|
86
|
+
});
|
|
87
|
+
server.listen(PORT, "127.0.0.1", () => {
|
|
88
|
+
writePidFile(PORT);
|
|
89
|
+
console.error(`[chrome-devtools-axi] Listening on http://127.0.0.1:${PORT}`);
|
|
90
|
+
// Signal readiness to parent
|
|
91
|
+
console.log("READY");
|
|
92
|
+
});
|
|
93
|
+
// Graceful shutdown
|
|
94
|
+
const shutdown = async () => {
|
|
95
|
+
removePidFile();
|
|
96
|
+
server.close();
|
|
97
|
+
await client.close();
|
|
98
|
+
await transport.close();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
};
|
|
101
|
+
process.on("SIGTERM", shutdown);
|
|
102
|
+
process.on("SIGINT", shutdown);
|
|
103
|
+
}
|
|
104
|
+
main().catch((err) => {
|
|
105
|
+
console.error(`[chrome-devtools-axi] Fatal: ${err}`);
|
|
106
|
+
removePidFile();
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(argv: string[]): Promise<void>;
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { encode } from "@toon-format/toon";
|
|
2
|
+
import { CdpError, callTool, ensureBridge, stopBridge } from "./client.js";
|
|
3
|
+
import { countRefs, extractTitle } from "./snapshot.js";
|
|
4
|
+
import { getSuggestions } from "./suggestions.js";
|
|
5
|
+
const HELP = `usage: chrome-devtools-axi <command> [args]
|
|
6
|
+
commands[12]:
|
|
7
|
+
open <url>, snapshot, click @<uid>, fill @<uid> <text>, type <text>,
|
|
8
|
+
press <key>, scroll <dir>, back, wait <ms|text>, eval <js>, start, stop
|
|
9
|
+
`;
|
|
10
|
+
function renderHelp(lines) {
|
|
11
|
+
if (lines.length === 0)
|
|
12
|
+
return "";
|
|
13
|
+
const indented = lines.map((l) => ` ${l}`).join("\n");
|
|
14
|
+
return `help[${lines.length}]:\n${indented}`;
|
|
15
|
+
}
|
|
16
|
+
function renderError(message, code, suggestions = []) {
|
|
17
|
+
const blocks = [encode({ error: message, code })];
|
|
18
|
+
if (suggestions.length > 0) {
|
|
19
|
+
blocks.push(renderHelp(suggestions));
|
|
20
|
+
}
|
|
21
|
+
return blocks.join("\n");
|
|
22
|
+
}
|
|
23
|
+
function renderOutput(blocks) {
|
|
24
|
+
return blocks.filter(Boolean).join("\n");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse snapshot from an includeSnapshot response.
|
|
28
|
+
* The response contains a "## Latest page snapshot" section.
|
|
29
|
+
*/
|
|
30
|
+
function parseSnapshotFromResponse(response) {
|
|
31
|
+
const marker = "## Latest page snapshot";
|
|
32
|
+
const idx = response.indexOf(marker);
|
|
33
|
+
if (idx === -1)
|
|
34
|
+
return null;
|
|
35
|
+
const after = response.slice(idx + marker.length);
|
|
36
|
+
// The snapshot follows after the header line, possibly with a blank line
|
|
37
|
+
const trimmed = after.replace(/^\s*\n/, "");
|
|
38
|
+
// Snapshot ends at the next ## heading or end of text
|
|
39
|
+
const nextHeading = trimmed.indexOf("\n## ");
|
|
40
|
+
return nextHeading === -1 ? trimmed.trimEnd() : trimmed.slice(0, nextHeading).trimEnd();
|
|
41
|
+
}
|
|
42
|
+
/** Format page metadata (TOON) + raw snapshot + suggestions. */
|
|
43
|
+
function formatPageOutput(snapshot, command, url) {
|
|
44
|
+
const title = extractTitle(snapshot);
|
|
45
|
+
const refs = countRefs(snapshot);
|
|
46
|
+
const blocks = [];
|
|
47
|
+
// Page metadata as TOON
|
|
48
|
+
const page = {};
|
|
49
|
+
if (title)
|
|
50
|
+
page.title = title;
|
|
51
|
+
if (url)
|
|
52
|
+
page.url = url;
|
|
53
|
+
page.refs = refs;
|
|
54
|
+
blocks.push(encode({ page }));
|
|
55
|
+
// Raw snapshot (not TOON-encoded — already token-efficient tree format)
|
|
56
|
+
blocks.push(`snapshot:\n${snapshot.trimEnd()}`);
|
|
57
|
+
// Contextual suggestions
|
|
58
|
+
const suggestions = getSuggestions({ command, url, snapshot });
|
|
59
|
+
if (suggestions.length > 0) {
|
|
60
|
+
blocks.push(renderHelp(suggestions));
|
|
61
|
+
}
|
|
62
|
+
return renderOutput(blocks);
|
|
63
|
+
}
|
|
64
|
+
/** Strip the `## Latest page snapshot` header that chrome-devtools-mcp prepends. */
|
|
65
|
+
function stripSnapshotHeader(text) {
|
|
66
|
+
return text.replace(/^##\s+Latest page snapshot\s*\n/, "");
|
|
67
|
+
}
|
|
68
|
+
/** Strip leading @ from uid ref. */
|
|
69
|
+
function parseUid(arg) {
|
|
70
|
+
return arg.startsWith("@") ? arg.slice(1) : arg;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Call a tool with includeSnapshot:true and extract the snapshot.
|
|
74
|
+
* Falls back to a separate take_snapshot() if parsing fails.
|
|
75
|
+
*/
|
|
76
|
+
async function callWithSnapshot(name, args) {
|
|
77
|
+
const result = await callTool(name, { ...args, includeSnapshot: true });
|
|
78
|
+
const snapshot = parseSnapshotFromResponse(result);
|
|
79
|
+
if (snapshot && snapshot.length > 0)
|
|
80
|
+
return stripSnapshotHeader(snapshot);
|
|
81
|
+
// Fallback: take snapshot separately
|
|
82
|
+
return stripSnapshotHeader(await callTool("take_snapshot"));
|
|
83
|
+
}
|
|
84
|
+
const SCROLL_FUNCTIONS = {
|
|
85
|
+
up: "window.scrollBy(0, -500)",
|
|
86
|
+
down: "window.scrollBy(0, 500)",
|
|
87
|
+
top: "window.scrollTo(0, 0)",
|
|
88
|
+
bottom: "window.scrollTo(0, document.body.scrollHeight)",
|
|
89
|
+
};
|
|
90
|
+
async function handleOpen(args) {
|
|
91
|
+
const url = args[0];
|
|
92
|
+
if (!url) {
|
|
93
|
+
throw new CdpError("Missing URL", "VALIDATION_ERROR", [
|
|
94
|
+
"Run `chrome-devtools-axi open https://example.com` to navigate to a page",
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
await callTool("navigate_page", { type: "url", url });
|
|
98
|
+
const snapshot = stripSnapshotHeader(await callTool("take_snapshot"));
|
|
99
|
+
return formatPageOutput(snapshot, "open", url);
|
|
100
|
+
}
|
|
101
|
+
async function handleSnapshot() {
|
|
102
|
+
const snapshot = stripSnapshotHeader(await callTool("take_snapshot"));
|
|
103
|
+
return formatPageOutput(snapshot, "snapshot");
|
|
104
|
+
}
|
|
105
|
+
async function handleClick(args) {
|
|
106
|
+
const uid = args[0];
|
|
107
|
+
if (!uid) {
|
|
108
|
+
throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
|
|
109
|
+
"Run `chrome-devtools-axi click @<uid>` — get uid from snapshot",
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
112
|
+
const snapshot = await callWithSnapshot("click", { uid: parseUid(uid) });
|
|
113
|
+
return formatPageOutput(snapshot, "click");
|
|
114
|
+
}
|
|
115
|
+
async function handleFill(args) {
|
|
116
|
+
const uid = args[0];
|
|
117
|
+
const value = args.slice(1).join(" ");
|
|
118
|
+
if (!uid) {
|
|
119
|
+
throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
|
|
120
|
+
'Run `chrome-devtools-axi fill @<uid> "text"` — get uid from snapshot',
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
if (!value) {
|
|
124
|
+
throw new CdpError("Missing fill text", "VALIDATION_ERROR", [
|
|
125
|
+
'Run `chrome-devtools-axi fill @<uid> "text"` to fill the field',
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
const snapshot = await callWithSnapshot("fill", { uid: parseUid(uid), value });
|
|
129
|
+
return formatPageOutput(snapshot, "fill");
|
|
130
|
+
}
|
|
131
|
+
async function handlePress(args) {
|
|
132
|
+
const key = args[0];
|
|
133
|
+
if (!key) {
|
|
134
|
+
throw new CdpError("Missing key name", "VALIDATION_ERROR", [
|
|
135
|
+
"Run `chrome-devtools-axi press Enter` to press a key",
|
|
136
|
+
]);
|
|
137
|
+
}
|
|
138
|
+
const snapshot = await callWithSnapshot("press_key", { key });
|
|
139
|
+
return formatPageOutput(snapshot, "press");
|
|
140
|
+
}
|
|
141
|
+
async function handleType(args) {
|
|
142
|
+
const text = args.join(" ");
|
|
143
|
+
if (!text) {
|
|
144
|
+
throw new CdpError("Missing text", "VALIDATION_ERROR", [
|
|
145
|
+
'Run `chrome-devtools-axi type "hello"` to type text',
|
|
146
|
+
]);
|
|
147
|
+
}
|
|
148
|
+
await callTool("type_text", { text });
|
|
149
|
+
const snapshot = stripSnapshotHeader(await callTool("take_snapshot"));
|
|
150
|
+
return formatPageOutput(snapshot, "type");
|
|
151
|
+
}
|
|
152
|
+
async function handleScroll(args) {
|
|
153
|
+
const dir = (args[0] ?? "down").toLowerCase();
|
|
154
|
+
const fn = SCROLL_FUNCTIONS[dir];
|
|
155
|
+
if (!fn) {
|
|
156
|
+
throw new CdpError(`Unknown scroll direction: ${dir}`, "VALIDATION_ERROR", [
|
|
157
|
+
"Run `chrome-devtools-axi scroll down` — directions: up, down, top, bottom",
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
await callTool("evaluate_script", { function: fn });
|
|
161
|
+
const snapshot = stripSnapshotHeader(await callTool("take_snapshot"));
|
|
162
|
+
return formatPageOutput(snapshot, "scroll");
|
|
163
|
+
}
|
|
164
|
+
async function handleBack() {
|
|
165
|
+
await callTool("navigate_page", { type: "back" });
|
|
166
|
+
const snapshot = stripSnapshotHeader(await callTool("take_snapshot"));
|
|
167
|
+
return formatPageOutput(snapshot, "back");
|
|
168
|
+
}
|
|
169
|
+
async function handleWait(args) {
|
|
170
|
+
const target = args[0];
|
|
171
|
+
if (!target) {
|
|
172
|
+
throw new CdpError("Missing wait target (milliseconds or text)", "VALIDATION_ERROR", [
|
|
173
|
+
"Run `chrome-devtools-axi wait 2000` to wait 2 seconds",
|
|
174
|
+
'Run `chrome-devtools-axi wait "Submit"` to wait for text to appear',
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
const isNumeric = /^\d+$/.test(target);
|
|
178
|
+
if (isNumeric) {
|
|
179
|
+
await callTool("evaluate_script", {
|
|
180
|
+
function: `new Promise(r => setTimeout(r, ${target}))`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
await callTool("wait_for", { text: [target] });
|
|
185
|
+
}
|
|
186
|
+
const blocks = [];
|
|
187
|
+
blocks.push(encode({ waited: target }));
|
|
188
|
+
const suggestions = getSuggestions({ command: "wait" });
|
|
189
|
+
if (suggestions.length > 0)
|
|
190
|
+
blocks.push(renderHelp(suggestions));
|
|
191
|
+
return renderOutput(blocks);
|
|
192
|
+
}
|
|
193
|
+
async function handleEval(args) {
|
|
194
|
+
const js = args.join(" ");
|
|
195
|
+
if (!js) {
|
|
196
|
+
throw new CdpError("Missing JavaScript expression", "VALIDATION_ERROR", [
|
|
197
|
+
'Run `chrome-devtools-axi eval "document.title"` to evaluate JavaScript',
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
const output = await callTool("evaluate_script", { function: js });
|
|
201
|
+
const blocks = [];
|
|
202
|
+
blocks.push(encode({ result: output.trim() }));
|
|
203
|
+
const suggestions = getSuggestions({ command: "eval" });
|
|
204
|
+
if (suggestions.length > 0)
|
|
205
|
+
blocks.push(renderHelp(suggestions));
|
|
206
|
+
return renderOutput(blocks);
|
|
207
|
+
}
|
|
208
|
+
async function handleStart() {
|
|
209
|
+
const port = await ensureBridge();
|
|
210
|
+
return encode({ status: "ready", port });
|
|
211
|
+
}
|
|
212
|
+
async function handleStop() {
|
|
213
|
+
await stopBridge();
|
|
214
|
+
return encode({ status: "stopped" });
|
|
215
|
+
}
|
|
216
|
+
export async function main(argv) {
|
|
217
|
+
const args = [...argv];
|
|
218
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
219
|
+
process.stdout.write(HELP);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const command = args[0] ?? "";
|
|
223
|
+
const commandArgs = args.slice(1);
|
|
224
|
+
try {
|
|
225
|
+
let output;
|
|
226
|
+
switch (command) {
|
|
227
|
+
case "open":
|
|
228
|
+
output = await handleOpen(commandArgs);
|
|
229
|
+
break;
|
|
230
|
+
case "snapshot":
|
|
231
|
+
output = await handleSnapshot();
|
|
232
|
+
break;
|
|
233
|
+
case "click":
|
|
234
|
+
output = await handleClick(commandArgs);
|
|
235
|
+
break;
|
|
236
|
+
case "fill":
|
|
237
|
+
output = await handleFill(commandArgs);
|
|
238
|
+
break;
|
|
239
|
+
case "type":
|
|
240
|
+
output = await handleType(commandArgs);
|
|
241
|
+
break;
|
|
242
|
+
case "press":
|
|
243
|
+
output = await handlePress(commandArgs);
|
|
244
|
+
break;
|
|
245
|
+
case "scroll":
|
|
246
|
+
output = await handleScroll(commandArgs);
|
|
247
|
+
break;
|
|
248
|
+
case "back":
|
|
249
|
+
output = await handleBack();
|
|
250
|
+
break;
|
|
251
|
+
case "wait":
|
|
252
|
+
output = await handleWait(commandArgs);
|
|
253
|
+
break;
|
|
254
|
+
case "eval":
|
|
255
|
+
output = await handleEval(commandArgs);
|
|
256
|
+
break;
|
|
257
|
+
case "start":
|
|
258
|
+
output = await handleStart();
|
|
259
|
+
break;
|
|
260
|
+
case "stop":
|
|
261
|
+
output = await handleStop();
|
|
262
|
+
break;
|
|
263
|
+
case "":
|
|
264
|
+
// No command = show current page state
|
|
265
|
+
output = await handleSnapshot();
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
process.stdout.write(renderError(`Unknown command: ${command}`, "UNKNOWN", [
|
|
269
|
+
"Run `chrome-devtools-axi --help` to see available commands",
|
|
270
|
+
]) + "\n");
|
|
271
|
+
process.exitCode = 1;
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
process.stdout.write(output + "\n");
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
if (err instanceof CdpError) {
|
|
278
|
+
process.stdout.write(renderError(err.message, err.code, err.suggestions) + "\n");
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
282
|
+
process.stdout.write(renderError(message, "UNKNOWN") + "\n");
|
|
283
|
+
}
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the chrome-devtools-axi bridge + bridge lifecycle management.
|
|
3
|
+
*/
|
|
4
|
+
export type ErrorCode = "BRIDGE_NOT_READY" | "REF_NOT_FOUND" | "TIMEOUT" | "BROWSER_ERROR" | "VALIDATION_ERROR" | "UNKNOWN";
|
|
5
|
+
export declare class CdpError extends Error {
|
|
6
|
+
readonly code: ErrorCode;
|
|
7
|
+
readonly suggestions: string[];
|
|
8
|
+
constructor(message: string, code: ErrorCode, suggestions?: string[]);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Ensure the bridge is running, starting it if needed. Returns the port.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ensureBridge(): Promise<number>;
|
|
14
|
+
/**
|
|
15
|
+
* Call an MCP tool via the bridge. Returns the text result.
|
|
16
|
+
*/
|
|
17
|
+
export declare function callTool(name: string, args?: Record<string, unknown>): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Stop the bridge process.
|
|
20
|
+
*/
|
|
21
|
+
export declare function stopBridge(): Promise<void>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the chrome-devtools-axi bridge + bridge lifecycle management.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
6
|
+
import { join, resolve } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { request } from "node:http";
|
|
9
|
+
const STATE_DIR = join(homedir(), ".chrome-devtools-axi");
|
|
10
|
+
const PID_FILE = join(STATE_DIR, "bridge.pid");
|
|
11
|
+
const DEFAULT_PORT = 9224;
|
|
12
|
+
export class CdpError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
suggestions;
|
|
15
|
+
constructor(message, code, suggestions = []) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.suggestions = suggestions;
|
|
19
|
+
this.name = "CdpError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function readPidFile() {
|
|
23
|
+
try {
|
|
24
|
+
if (!existsSync(PID_FILE))
|
|
25
|
+
return null;
|
|
26
|
+
const data = JSON.parse(readFileSync(PID_FILE, "utf-8"));
|
|
27
|
+
if (typeof data.pid === "number" && typeof data.port === "number") {
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isProcessAlive(pid) {
|
|
37
|
+
try {
|
|
38
|
+
process.kill(pid, 0);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function httpGet(port, path, timeoutMs = 2000) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const req = request({ hostname: "127.0.0.1", port, path, method: "GET", timeout: timeoutMs }, (res) => {
|
|
48
|
+
let data = "";
|
|
49
|
+
res.on("data", (chunk) => (data += chunk));
|
|
50
|
+
res.on("end", () => resolve(data));
|
|
51
|
+
});
|
|
52
|
+
req.on("error", reject);
|
|
53
|
+
req.on("timeout", () => {
|
|
54
|
+
req.destroy();
|
|
55
|
+
reject(new Error("timeout"));
|
|
56
|
+
});
|
|
57
|
+
req.end();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function httpPost(port, path, body, timeoutMs = 120_000) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const payload = JSON.stringify(body);
|
|
63
|
+
const req = request({
|
|
64
|
+
hostname: "127.0.0.1",
|
|
65
|
+
port,
|
|
66
|
+
path,
|
|
67
|
+
method: "POST",
|
|
68
|
+
timeout: timeoutMs,
|
|
69
|
+
headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload) },
|
|
70
|
+
}, (res) => {
|
|
71
|
+
let data = "";
|
|
72
|
+
res.on("data", (chunk) => (data += chunk));
|
|
73
|
+
res.on("end", () => {
|
|
74
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
75
|
+
reject(new Error(data));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
resolve(data);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
req.on("error", reject);
|
|
83
|
+
req.on("timeout", () => {
|
|
84
|
+
req.destroy();
|
|
85
|
+
reject(new Error("timeout"));
|
|
86
|
+
});
|
|
87
|
+
req.write(payload);
|
|
88
|
+
req.end();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function checkBridgeHealth(port) {
|
|
92
|
+
try {
|
|
93
|
+
const resp = await httpGet(port, "/health");
|
|
94
|
+
const data = JSON.parse(resp);
|
|
95
|
+
return data.status === "ok";
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function sleep(ms) {
|
|
102
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Ensure the bridge is running, starting it if needed. Returns the port.
|
|
106
|
+
*/
|
|
107
|
+
export async function ensureBridge() {
|
|
108
|
+
const port = parseInt(process.env.CHROME_DEVTOOLS_AXI_PORT ?? String(DEFAULT_PORT), 10);
|
|
109
|
+
// Check existing bridge via PID file
|
|
110
|
+
const pidInfo = readPidFile();
|
|
111
|
+
if (pidInfo && isProcessAlive(pidInfo.pid)) {
|
|
112
|
+
if (await checkBridgeHealth(pidInfo.port)) {
|
|
113
|
+
return pidInfo.port;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Start a new bridge
|
|
117
|
+
console.error("[chrome-devtools-axi] Starting browser...");
|
|
118
|
+
const bridgeScript = resolve(import.meta.dirname, "bridge.js");
|
|
119
|
+
// Try .ts first (dev mode), fall back to .js (built)
|
|
120
|
+
const script = existsSync(bridgeScript.replace(/\.js$/, ".ts"))
|
|
121
|
+
? bridgeScript.replace(/\.js$/, ".ts")
|
|
122
|
+
: bridgeScript;
|
|
123
|
+
const runner = script.endsWith(".ts") ? "tsx" : "node";
|
|
124
|
+
const child = spawn(runner === "tsx" ? "npx" : "node", runner === "tsx" ? ["tsx", script] : [script], {
|
|
125
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
126
|
+
env: { ...process.env, CHROME_DEVTOOLS_AXI_PORT: String(port) },
|
|
127
|
+
detached: true,
|
|
128
|
+
});
|
|
129
|
+
child.unref();
|
|
130
|
+
// Detach stdin so parent can exit
|
|
131
|
+
child.stdin?.end();
|
|
132
|
+
// Poll for health (max 30s — Chrome launch can be slow)
|
|
133
|
+
const deadline = Date.now() + 30_000;
|
|
134
|
+
while (Date.now() < deadline) {
|
|
135
|
+
if (await checkBridgeHealth(port)) {
|
|
136
|
+
return port;
|
|
137
|
+
}
|
|
138
|
+
await sleep(500);
|
|
139
|
+
}
|
|
140
|
+
throw new CdpError("Bridge failed to start within 30s", "BRIDGE_NOT_READY", ["Check that chrome-devtools-mcp is installed: npx chrome-devtools-mcp@latest --help"]);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Call an MCP tool via the bridge. Returns the text result.
|
|
144
|
+
*/
|
|
145
|
+
export async function callTool(name, args = {}) {
|
|
146
|
+
const port = await ensureBridge();
|
|
147
|
+
try {
|
|
148
|
+
const resp = await httpPost(port, "/call", { name, args });
|
|
149
|
+
const data = JSON.parse(resp);
|
|
150
|
+
if (data.error) {
|
|
151
|
+
throw new Error(data.error);
|
|
152
|
+
}
|
|
153
|
+
return data.result ?? "";
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
157
|
+
throw mapError(message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function mapError(message) {
|
|
161
|
+
if (message.includes("ECONNREFUSED") || message.includes("ECONNRESET")) {
|
|
162
|
+
return new CdpError("Bridge is not running", "BRIDGE_NOT_READY", [
|
|
163
|
+
"Run `chrome-devtools-axi open <url>` — the bridge starts automatically",
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
if ((message.includes("uid") || message.includes("element")) &&
|
|
167
|
+
(message.includes("not found") || message.includes("invalid"))) {
|
|
168
|
+
return new CdpError(message, "REF_NOT_FOUND", [
|
|
169
|
+
"Run `chrome-devtools-axi snapshot` to see available elements and their @uid refs",
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
173
|
+
return new CdpError(message, "TIMEOUT", [
|
|
174
|
+
"Run `chrome-devtools-axi snapshot` to see current page state",
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
// Try to parse JSON error
|
|
178
|
+
try {
|
|
179
|
+
const parsed = JSON.parse(message);
|
|
180
|
+
if (parsed.error) {
|
|
181
|
+
return new CdpError(parsed.error, "BROWSER_ERROR", [
|
|
182
|
+
"Run `chrome-devtools-axi snapshot` to see current page state",
|
|
183
|
+
]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Not JSON
|
|
188
|
+
}
|
|
189
|
+
return new CdpError(message, "UNKNOWN");
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Stop the bridge process.
|
|
193
|
+
*/
|
|
194
|
+
export async function stopBridge() {
|
|
195
|
+
const pidInfo = readPidFile();
|
|
196
|
+
if (!pidInfo) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (isProcessAlive(pidInfo.pid)) {
|
|
200
|
+
process.kill(pidInfo.pid, "SIGTERM");
|
|
201
|
+
}
|
|
202
|
+
// PID file is cleaned up by the bridge on shutdown
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAC;AAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAC/C,MAAM,YAAY,GAAG,IAAI,CAAC;AAU1B,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IACA;IAHlB,YACE,OAAe,EACC,IAAe,EACf,cAAwB,EAAE;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAW;QACf,gBAAW,GAAX,WAAW,CAAe;QAG1C,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAOD,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClE,OAAO,IAAe,CAAC;QACzB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,IAAY,EAAE,SAAS,GAAG,IAAI;IAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,OAAO,CACjB,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EACxE,CAAC,GAAG,EAAE,EAAE;YACN,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC,CACF,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxB,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACrB,GAAG,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY,EAAE,IAAa,EAAE,SAAS,GAAG,OAAO;IAC9E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,OAAO,CACjB;YACE,QAAQ,EAAE,WAAW;YACrB,IAAI;YACJ,IAAI;YACJ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;SAC9F,EACD,CAAC,GAAG,EAAE,EAAE;YACN,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;oBAC5C,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CACF,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxB,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACrB,GAAG,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,MAAM,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAExF,qCAAqC;IACrC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,IAAI,MAAM,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,OAAO,OAAO,CAAC,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAE3D,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC/D,qDAAqD;IACrD,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC;QACtC,CAAC,CAAC,YAAY,CAAC;IACjB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAEvD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;QACpG,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;QAClC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,wBAAwB,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;QAC/D,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,kCAAkC;IAClC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;IAEnB,wDAAwD;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;IACrC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,MAAM,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,QAAQ,CAChB,mCAAmC,EACnC,kBAAkB,EAClB,CAAC,oFAAoF,CAAC,CACvF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,OAAgC,EAAE;IAC7E,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,QAAQ,CAAC,uBAAuB,EAAE,kBAAkB,EAAE;YAC/D,wEAAwE;SACzE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACnE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE;YAC5C,kFAAkF;SACnF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE;YACtC,8DAA8D;SAC/D,CAAC,CAAC;IACL,CAAC;IACD,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,eAAe,EAAE;gBACjD,8DAA8D;aAC/D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,WAAW;IACb,CAAC;IACD,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IACD,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IACD,mDAAmD;AACrD,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface RefInfo {
|
|
2
|
+
ref: string;
|
|
3
|
+
label: string;
|
|
4
|
+
type: string;
|
|
5
|
+
}
|
|
6
|
+
/** Count interactive refs (uid=...) in snapshot text. */
|
|
7
|
+
export declare function countRefs(snapshot: string): number;
|
|
8
|
+
/** Extract ref IDs with labels and types from snapshot text. */
|
|
9
|
+
export declare function extractRefs(snapshot: string): RefInfo[];
|
|
10
|
+
/** Extract page title from snapshot (RootWebArea or first heading). */
|
|
11
|
+
export declare function extractTitle(snapshot: string): string;
|
|
12
|
+
/** Check if a ref type is an input/form field. */
|
|
13
|
+
export declare function isInputType(type: string): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Count interactive refs (uid=...) in snapshot text. */
|
|
2
|
+
export function countRefs(snapshot) {
|
|
3
|
+
const matches = snapshot.match(/\buid=\S+/g);
|
|
4
|
+
return matches ? matches.length : 0;
|
|
5
|
+
}
|
|
6
|
+
/** Extract ref IDs with labels and types from snapshot text. */
|
|
7
|
+
export function extractRefs(snapshot) {
|
|
8
|
+
const refs = [];
|
|
9
|
+
for (const line of snapshot.split("\n")) {
|
|
10
|
+
const m = line.match(/\buid=(\S+)\s+(\w+)\s+"([^"]*)"/);
|
|
11
|
+
if (!m)
|
|
12
|
+
continue;
|
|
13
|
+
refs.push({ ref: m[1], type: m[2], label: m[3] });
|
|
14
|
+
}
|
|
15
|
+
return refs;
|
|
16
|
+
}
|
|
17
|
+
/** Extract page title from snapshot (RootWebArea or first heading). */
|
|
18
|
+
export function extractTitle(snapshot) {
|
|
19
|
+
const rootMatch = snapshot.match(/RootWebArea\s+"([^"]+)"/);
|
|
20
|
+
if (rootMatch)
|
|
21
|
+
return rootMatch[1];
|
|
22
|
+
const headingMatch = snapshot.match(/\bheading\s+"([^"]+)"/);
|
|
23
|
+
if (headingMatch)
|
|
24
|
+
return headingMatch[1];
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
const INPUT_TYPES = ["textbox", "searchbox", "input", "combobox", "textarea"];
|
|
28
|
+
/** Check if a ref type is an input/form field. */
|
|
29
|
+
export function isInputType(type) {
|
|
30
|
+
return INPUT_TYPES.includes(type);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/snapshot.ts"],"names":[],"mappings":"AAMA,yDAAyD;AACzD,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACxD,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5D,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC7D,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;IACzC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE9E,kDAAkD;AAClD,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { extractRefs, isInputType } from "./snapshot.js";
|
|
2
|
+
export function getSuggestions(ctx) {
|
|
3
|
+
// Commands without auto-snapshot — suggest viewing page state
|
|
4
|
+
if (ctx.command === "wait" || ctx.command === "eval") {
|
|
5
|
+
return ["Run `chrome-devtools-axi snapshot` to see current page state"];
|
|
6
|
+
}
|
|
7
|
+
const refs = ctx.snapshot ? extractRefs(ctx.snapshot) : [];
|
|
8
|
+
const links = refs.filter((r) => r.type === "link");
|
|
9
|
+
const buttons = refs.filter((r) => r.type === "button");
|
|
10
|
+
const inputs = refs.filter((r) => isInputType(r.type));
|
|
11
|
+
const lines = [];
|
|
12
|
+
// After filling a field, suggest submitting
|
|
13
|
+
if (ctx.command === "fill") {
|
|
14
|
+
const submitBtn = buttons.find((r) => /submit|search|go|send|login|sign|ok/i.test(r.label));
|
|
15
|
+
if (submitBtn) {
|
|
16
|
+
lines.push(`Run \`chrome-devtools-axi click @${submitBtn.ref}\` to click "${submitBtn.label}"`);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
lines.push("Run `chrome-devtools-axi press Enter` to submit the form");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Suggest filling inputs (unless we just filled one)
|
|
23
|
+
if (inputs.length > 0 && ctx.command !== "fill") {
|
|
24
|
+
const inp = inputs[0];
|
|
25
|
+
const label = inp.label ? `the "${inp.label}" field` : "the input field";
|
|
26
|
+
lines.push(`Run \`chrome-devtools-axi fill @${inp.ref} "text"\` to fill ${label}`);
|
|
27
|
+
}
|
|
28
|
+
// Suggest clicking buttons
|
|
29
|
+
if (buttons.length > 0 && lines.length < 2) {
|
|
30
|
+
const btn = ctx.command === "fill"
|
|
31
|
+
? buttons.find((r) => !/submit|search|go|send|login|sign|ok/i.test(r.label)) ?? buttons[0]
|
|
32
|
+
: buttons[0];
|
|
33
|
+
if (btn && !lines.some((l) => l.includes(`@${btn.ref}`))) {
|
|
34
|
+
const label = btn.label ? `"${btn.label}" ` : "";
|
|
35
|
+
lines.push(`Run \`chrome-devtools-axi click @${btn.ref}\` to click the ${label}button`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Suggest clicking links
|
|
39
|
+
if (links.length > 0 && lines.length < 2) {
|
|
40
|
+
const link = links[0];
|
|
41
|
+
lines.push(`Run \`chrome-devtools-axi click @${link.ref}\` to click the "${link.label}" link`);
|
|
42
|
+
}
|
|
43
|
+
// Suggest scrolling if page has many elements
|
|
44
|
+
if (refs.length > 5 && lines.length < 3) {
|
|
45
|
+
lines.push("Run `chrome-devtools-axi scroll down` to scroll down");
|
|
46
|
+
}
|
|
47
|
+
return lines.slice(0, 3);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=suggestions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestions.js","sourceRoot":"","sources":["../../src/suggestions.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chrome-devtools-axi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AXI-compliant chrome-devtools-mcp wrapper — combined operations, TOON output, contextual suggestions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/kunchenguid/chrome-devtools-axi.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"chrome",
|
|
12
|
+
"devtools",
|
|
13
|
+
"browser",
|
|
14
|
+
"cli",
|
|
15
|
+
"agent",
|
|
16
|
+
"axi",
|
|
17
|
+
"toon",
|
|
18
|
+
"mcp"
|
|
19
|
+
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"chrome-devtools-axi": "./dist/bin/chrome-devtools-axi.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"dev": "tsx bin/chrome-devtools-axi.ts",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"prepublishOnly": "npm run build"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=20"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
44
|
+
"@toon-format/toon": "^2.1.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"tsx": "^4.0.0",
|
|
49
|
+
"typescript": "^5.7.0",
|
|
50
|
+
"vitest": "^3.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|