chrome-cdp-cli 2.0.4 → 2.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/dist/cli/ArgumentParser.js +172 -91
- package/dist/cli/CLIApplication.js +181 -57
- package/dist/cli/CommandRouter.js +98 -74
- package/dist/cli/CommandSchemaRegistry.js +506 -398
- package/dist/cli/EnhancedCLIInterface.js +2 -1
- package/dist/cli/HelpSystem.js +286 -256
- package/dist/handlers/ClickHandler.js +91 -27
- package/dist/handlers/InstallClaudeSkillHandler.js +220 -220
- package/dist/handlers/InstallCursorCommandHandler.js +60 -60
- package/dist/handlers/ListConsoleMessagesHandler.js +126 -178
- package/dist/handlers/ListNetworkRequestsHandler.js +128 -108
- package/dist/handlers/RestartProxyHandler.js +4 -4
- package/dist/handlers/TakeScreenshotHandler.js +70 -59
- package/dist/handlers/TakeSnapshotHandler.js +223 -165
- package/dist/handlers/index.js +0 -1
- package/dist/monitors/ConsoleMonitor.js +29 -0
- package/dist/monitors/NetworkMonitor.js +43 -19
- package/dist/proxy/server/CDPProxyServer.js +5 -1
- package/dist/proxy/server/CommandExecutionService.js +1 -1
- package/dist/proxy/server/ProxyAPIServer.js +11 -6
- package/package.json +3 -2
|
@@ -30,8 +30,10 @@ class CommandRouter {
|
|
|
30
30
|
if (!this.client) {
|
|
31
31
|
return {
|
|
32
32
|
success: false,
|
|
33
|
-
error:
|
|
34
|
-
|
|
33
|
+
error: "Not connected to Chrome.\n" +
|
|
34
|
+
"Launch Chrome with: google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug\n" +
|
|
35
|
+
"From Chrome 136, --user-data-dir is required. See: https://developer.chrome.com/blog/remote-debugging-port",
|
|
36
|
+
exitCode: ExitCode.CONNECTION_ERROR,
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
const handler = this.registry.get(command.name);
|
|
@@ -39,14 +41,14 @@ class CommandRouter {
|
|
|
39
41
|
return {
|
|
40
42
|
success: false,
|
|
41
43
|
error: `Unknown command: ${command.name}. Use "help" to see available commands.`,
|
|
42
|
-
exitCode: ExitCode.INVALID_COMMAND
|
|
44
|
+
exitCode: ExitCode.INVALID_COMMAND,
|
|
43
45
|
};
|
|
44
46
|
}
|
|
45
47
|
if (handler.validateArgs && !handler.validateArgs(command.args)) {
|
|
46
48
|
return {
|
|
47
49
|
success: false,
|
|
48
50
|
error: `Invalid arguments for command "${command.name}". Use "help ${command.name}" for usage information.`,
|
|
49
|
-
exitCode: ExitCode.VALIDATION_ERROR
|
|
51
|
+
exitCode: ExitCode.VALIDATION_ERROR,
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
if (command.config.verbose) {
|
|
@@ -66,36 +68,36 @@ class CommandRouter {
|
|
|
66
68
|
return {
|
|
67
69
|
success: false,
|
|
68
70
|
error: errorMessage,
|
|
69
|
-
exitCode: this.getExitCodeForError(error)
|
|
71
|
+
exitCode: this.getExitCodeForError(error),
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
isSpecialCommand(commandName) {
|
|
74
76
|
const specialCommands = [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
"help",
|
|
78
|
+
"connect",
|
|
79
|
+
"disconnect",
|
|
80
|
+
"install_cursor_command",
|
|
81
|
+
"install_claude_skill",
|
|
80
82
|
];
|
|
81
83
|
return specialCommands.includes(commandName);
|
|
82
84
|
}
|
|
83
85
|
async executeSpecialCommand(command) {
|
|
84
86
|
switch (command.name) {
|
|
85
|
-
case
|
|
87
|
+
case "help":
|
|
86
88
|
return this.executeHelpCommand(command);
|
|
87
|
-
case
|
|
89
|
+
case "connect":
|
|
88
90
|
return this.executeConnectCommand(command);
|
|
89
|
-
case
|
|
91
|
+
case "disconnect":
|
|
90
92
|
return this.executeDisconnectCommand();
|
|
91
|
-
case
|
|
92
|
-
case
|
|
93
|
+
case "install_cursor_command":
|
|
94
|
+
case "install_claude_skill": {
|
|
93
95
|
const handler = this.registry.get(command.name);
|
|
94
96
|
if (!handler) {
|
|
95
97
|
return {
|
|
96
98
|
success: false,
|
|
97
99
|
error: `Handler not found for command: ${command.name}`,
|
|
98
|
-
exitCode: ExitCode.INVALID_COMMAND
|
|
100
|
+
exitCode: ExitCode.INVALID_COMMAND,
|
|
99
101
|
};
|
|
100
102
|
}
|
|
101
103
|
return await handler.execute(null, command.args);
|
|
@@ -104,26 +106,28 @@ class CommandRouter {
|
|
|
104
106
|
return {
|
|
105
107
|
success: false,
|
|
106
108
|
error: `Unknown special command: ${command.name}`,
|
|
107
|
-
exitCode: ExitCode.INVALID_COMMAND
|
|
109
|
+
exitCode: ExitCode.INVALID_COMMAND,
|
|
108
110
|
};
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
executeHelpCommand(command) {
|
|
112
114
|
const commandName = command.args.command;
|
|
113
115
|
if (commandName) {
|
|
114
|
-
const normalizedCommandName = commandName.replace(/-/g,
|
|
116
|
+
const normalizedCommandName = commandName.replace(/-/g, "_");
|
|
115
117
|
const handler = this.registry.get(normalizedCommandName);
|
|
116
118
|
if (!handler) {
|
|
117
119
|
return {
|
|
118
120
|
success: false,
|
|
119
121
|
error: `Unknown command: ${commandName}`,
|
|
120
|
-
exitCode: ExitCode.INVALID_COMMAND
|
|
122
|
+
exitCode: ExitCode.INVALID_COMMAND,
|
|
121
123
|
};
|
|
122
124
|
}
|
|
123
|
-
const helpText = handler.getHelp
|
|
125
|
+
const helpText = handler.getHelp
|
|
126
|
+
? handler.getHelp()
|
|
127
|
+
: `No help available for command: ${commandName}`;
|
|
124
128
|
return {
|
|
125
129
|
success: true,
|
|
126
|
-
data: helpText
|
|
130
|
+
data: helpText,
|
|
127
131
|
};
|
|
128
132
|
}
|
|
129
133
|
else {
|
|
@@ -131,7 +135,7 @@ class CommandRouter {
|
|
|
131
135
|
const helpText = this.generateGeneralHelp(commands);
|
|
132
136
|
return {
|
|
133
137
|
success: true,
|
|
134
|
-
data: helpText
|
|
138
|
+
data: helpText,
|
|
135
139
|
};
|
|
136
140
|
}
|
|
137
141
|
}
|
|
@@ -139,14 +143,14 @@ class CommandRouter {
|
|
|
139
143
|
try {
|
|
140
144
|
return {
|
|
141
145
|
success: true,
|
|
142
|
-
data: `Connected to Chrome at ${command.config.host}:${command.config.port}
|
|
146
|
+
data: `Connected to Chrome at ${command.config.host}:${command.config.port}`,
|
|
143
147
|
};
|
|
144
148
|
}
|
|
145
149
|
catch (error) {
|
|
146
150
|
return {
|
|
147
151
|
success: false,
|
|
148
152
|
error: `Failed to connect: ${error instanceof Error ? error.message : String(error)}`,
|
|
149
|
-
exitCode: ExitCode.CONNECTION_ERROR
|
|
153
|
+
exitCode: ExitCode.CONNECTION_ERROR,
|
|
150
154
|
};
|
|
151
155
|
}
|
|
152
156
|
}
|
|
@@ -158,14 +162,14 @@ class CommandRouter {
|
|
|
158
162
|
}
|
|
159
163
|
return {
|
|
160
164
|
success: true,
|
|
161
|
-
data:
|
|
165
|
+
data: "Disconnected from Chrome",
|
|
162
166
|
};
|
|
163
167
|
}
|
|
164
168
|
catch (error) {
|
|
165
169
|
return {
|
|
166
170
|
success: false,
|
|
167
171
|
error: `Failed to disconnect: ${error instanceof Error ? error.message : String(error)}`,
|
|
168
|
-
exitCode: ExitCode.CONNECTION_ERROR
|
|
172
|
+
exitCode: ExitCode.CONNECTION_ERROR,
|
|
169
173
|
};
|
|
170
174
|
}
|
|
171
175
|
}
|
|
@@ -178,22 +182,41 @@ class CommandRouter {
|
|
|
178
182
|
this.logger.setLevel(2);
|
|
179
183
|
}
|
|
180
184
|
this.logger.debug(`CommandRouter.executeWithTimeout called for command: ${command.name}, timeout: ${timeout}ms`);
|
|
185
|
+
this.logger.debug(`Starting handler execution for: ${command.name}`);
|
|
186
|
+
const executionPromise = handler.execute(this.client, command.args);
|
|
187
|
+
const longRunningCommands = ["log", "console", "network"];
|
|
188
|
+
const isLongRunning = longRunningCommands.includes(command.name) ||
|
|
189
|
+
command.args?.follow ||
|
|
190
|
+
command.args?.f;
|
|
191
|
+
if (isLongRunning) {
|
|
192
|
+
this.logger.debug(`Command ${command.name} is long-running, skipping timeout`);
|
|
193
|
+
try {
|
|
194
|
+
const result = await executionPromise;
|
|
195
|
+
if (result?.isLongRunning) {
|
|
196
|
+
return new Promise(() => {
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
this.logger.debug(`Command execution error for: ${command.name}:`, error);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
181
206
|
const timeoutPromise = new Promise((_, reject) => {
|
|
182
207
|
setTimeout(() => {
|
|
183
208
|
this.logger.debug(`Command timeout reached for: ${command.name} after ${timeout}ms`);
|
|
184
209
|
reject(new Error(`Command timeout after ${timeout}ms`));
|
|
185
210
|
}, timeout);
|
|
186
211
|
});
|
|
187
|
-
this.logger.debug(`Starting handler execution for: ${command.name}`);
|
|
188
|
-
const executionPromise = handler.execute(this.client, command.args);
|
|
189
212
|
try {
|
|
190
213
|
const result = await Promise.race([executionPromise, timeoutPromise]);
|
|
191
214
|
this.logger.debug(`Command completed successfully for: ${command.name}`);
|
|
192
|
-
if (!result || typeof result !==
|
|
215
|
+
if (!result || typeof result !== "object") {
|
|
193
216
|
return {
|
|
194
217
|
success: false,
|
|
195
|
-
error:
|
|
196
|
-
exitCode: ExitCode.GENERAL_ERROR
|
|
218
|
+
error: "Invalid command result format",
|
|
219
|
+
exitCode: ExitCode.GENERAL_ERROR,
|
|
197
220
|
};
|
|
198
221
|
}
|
|
199
222
|
if (result.success && !result.exitCode) {
|
|
@@ -203,11 +226,11 @@ class CommandRouter {
|
|
|
203
226
|
}
|
|
204
227
|
catch (error) {
|
|
205
228
|
this.logger.debug(`Command execution error for: ${command.name}:`, error);
|
|
206
|
-
if (error instanceof Error && error.message.includes(
|
|
229
|
+
if (error instanceof Error && error.message.includes("timeout")) {
|
|
207
230
|
return {
|
|
208
231
|
success: false,
|
|
209
232
|
error: error.message,
|
|
210
|
-
exitCode: ExitCode.TIMEOUT_ERROR
|
|
233
|
+
exitCode: ExitCode.TIMEOUT_ERROR,
|
|
211
234
|
};
|
|
212
235
|
}
|
|
213
236
|
throw error;
|
|
@@ -215,9 +238,9 @@ class CommandRouter {
|
|
|
215
238
|
}
|
|
216
239
|
generateGeneralHelp(commands) {
|
|
217
240
|
return `
|
|
218
|
-
|
|
241
|
+
CDP - Chrome DevTools Protocol CLI
|
|
219
242
|
|
|
220
|
-
Usage:
|
|
243
|
+
Usage: cdp [options] <command> [command-options]
|
|
221
244
|
|
|
222
245
|
Global Options:
|
|
223
246
|
-h, --host <host> Chrome host address (default: localhost)
|
|
@@ -231,64 +254,65 @@ Global Options:
|
|
|
231
254
|
-V, --version Show version number
|
|
232
255
|
|
|
233
256
|
Available Commands:
|
|
234
|
-
${commands.map(cmd => ` ${cmd.padEnd(20)} - ${this.getCommandDescription(cmd)}`).join(
|
|
257
|
+
${commands.map((cmd) => ` ${cmd.padEnd(20)} - ${this.getCommandDescription(cmd)}`).join("\n")}
|
|
235
258
|
|
|
236
259
|
Examples:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
260
|
+
cdp eval "document.title"
|
|
261
|
+
cdp eval --file script.js
|
|
262
|
+
cdp screenshot --filename page.png
|
|
263
|
+
cdp snapshot --filename dom.html
|
|
264
|
+
cdp log -f
|
|
265
|
+
cdp network --urlPattern "/api"
|
|
266
|
+
cdp help <command>
|
|
242
267
|
|
|
243
268
|
For more information about a specific command, use:
|
|
244
|
-
|
|
269
|
+
cdp help <command>
|
|
245
270
|
`;
|
|
246
271
|
}
|
|
247
272
|
getCommandDescription(commandName) {
|
|
248
273
|
const descriptions = {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
'help': 'Show help information'
|
|
274
|
+
connect: "Connect to Chrome instance",
|
|
275
|
+
disconnect: "Disconnect from Chrome instance",
|
|
276
|
+
navigate: "Navigate to URL",
|
|
277
|
+
"new-page": "Create new page/tab",
|
|
278
|
+
"close-page": "Close current or specified page",
|
|
279
|
+
"list-pages": "List all open pages",
|
|
280
|
+
"select-page": "Select/focus page",
|
|
281
|
+
"resize-page": "Resize browser viewport",
|
|
282
|
+
eval: "Execute JavaScript code",
|
|
283
|
+
click: "Click element",
|
|
284
|
+
fill: "Fill form field",
|
|
285
|
+
fill_form: "Fill multiple form fields in batch",
|
|
286
|
+
hover: "Hover over element",
|
|
287
|
+
drag: "Perform drag and drop operations",
|
|
288
|
+
press_key: "Simulate keyboard input with modifiers",
|
|
289
|
+
upload_file: "Upload files to file input elements",
|
|
290
|
+
wait_for: "Wait for elements to appear or meet conditions",
|
|
291
|
+
handle_dialog: "Handle browser dialogs (alert, confirm, prompt)",
|
|
292
|
+
screenshot: "Capture page screenshot",
|
|
293
|
+
snapshot: "Capture DOM snapshot with structure and styles",
|
|
294
|
+
log: "Follow console messages in real-time",
|
|
295
|
+
console: "Follow console messages (alias for log)",
|
|
296
|
+
network: "Follow network requests in real-time",
|
|
297
|
+
install_cursor_command: "Install Cursor IDE commands for Chrome automation",
|
|
298
|
+
install_claude_skill: "Install Claude Code skill for Chrome automation",
|
|
299
|
+
help: "Show help information",
|
|
276
300
|
};
|
|
277
|
-
return descriptions[commandName] ||
|
|
301
|
+
return descriptions[commandName] || "No description available";
|
|
278
302
|
}
|
|
279
303
|
getExitCodeForError(error) {
|
|
280
304
|
if (error instanceof Error) {
|
|
281
305
|
const message = error.message.toLowerCase();
|
|
282
|
-
if (message.includes(
|
|
306
|
+
if (message.includes("timeout")) {
|
|
283
307
|
return ExitCode.TIMEOUT_ERROR;
|
|
284
308
|
}
|
|
285
|
-
if (message.includes(
|
|
309
|
+
if (message.includes("connection") || message.includes("connect")) {
|
|
286
310
|
return ExitCode.CONNECTION_ERROR;
|
|
287
311
|
}
|
|
288
|
-
if (message.includes(
|
|
312
|
+
if (message.includes("file") || message.includes("path")) {
|
|
289
313
|
return ExitCode.FILE_ERROR;
|
|
290
314
|
}
|
|
291
|
-
if (message.includes(
|
|
315
|
+
if (message.includes("invalid") || message.includes("validation")) {
|
|
292
316
|
return ExitCode.VALIDATION_ERROR;
|
|
293
317
|
}
|
|
294
318
|
}
|