chrome-cdp-cli 1.7.5 ā 1.7.7
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
CHANGED
|
@@ -1,41 +1,16 @@
|
|
|
1
1
|
# Chrome DevTools CLI
|
|
2
2
|
|
|
3
|
+
A command-line tool for browser automation via Chrome DevTools Protocol (CDP). Designed for developers who need reliable, scriptable browser control with both dedicated commands and flexible JavaScript execution.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
## š¤ Why This Tool Exists
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
**The honest story:** I started using `chrome-devtools-mcp` like everyone else. It worked great... until it didn't. One day it just stopped working - Cursor showed 26 tools available, everything looked normal, but every single tool call threw errors. Classic black box problem: you can't debug what you can't see inside.
|
|
7
8
|
|
|
8
|
-
**
|
|
9
|
+
**The MCP reality check:** Model Context Protocol sounded promising, but let's be real - it's not exactly taking the world by storm. Meanwhile, Anthropic introduced the SKILL concept, which actually makes sense for how LLMs work. And what pairs perfectly with Skills? Good old-fashioned command-line tools. They're debuggable, efficient, and you can actually see what's happening when things go wrong.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
**The pragmatic solution:** Instead of wrestling with mysterious MCP failures, why not build a CLI that just works? One that you can debug, extend, and actually understand. Plus, when your AI assistant needs to automate a browser, it can just write the command and execute it - no black boxes, no mysterious failures, just straightforward automation.
|
|
11
12
|
|
|
12
|
-
**The
|
|
13
|
-
|
|
14
|
-
1. **š§ LLMs Excel at JavaScript**: Large Language Models are exceptionally good at writing JavaScript code. They can generate complex automation scripts, handle async operations, and adapt to different scenarios - all in JavaScript.
|
|
15
|
-
|
|
16
|
-
2. **ā” Rapid Script Validation**: LLMs can write a script, test it immediately with `eval`, see the results, and refine it in seconds. This iterative loop is where LLMs shine.
|
|
17
|
-
|
|
18
|
-
3. **š Maximum Flexibility**: Instead of waiting for specific commands to be implemented, LLMs can accomplish any browser task through JavaScript execution. Need to click an element? `document.querySelector('#btn').click()`. Need to wait for content? `await new Promise(...)`. Need complex data extraction? Just write the JavaScript.
|
|
19
|
-
|
|
20
|
-
4. **šÆ Perfect for AI Workflows**: When you ask Claude or Cursor to automate a browser task, they can write the JavaScript directly - no need to learn complex CLI syntax or wait for feature implementations.
|
|
21
|
-
|
|
22
|
-
### IDE Integration for LLM Workflows
|
|
23
|
-
|
|
24
|
-
**Built-in support for AI development environments:**
|
|
25
|
-
|
|
26
|
-
- **š„ļø Cursor Commands**: Install with `install-cursor-command` - brings browser automation directly into Cursor's command palette
|
|
27
|
-
- **š¤ Claude Skills**: Install with `install-claude-skill` - enables Claude to use browser automation in conversations
|
|
28
|
-
- **ā” Seamless Integration**: AI assistants can generate automation scripts and execute them instantly through these integrations
|
|
29
|
-
|
|
30
|
-
**Why this matters:** When LLMs are integrated into your IDE, they can write browser automation scripts as part of your development workflow. The eval-first approach means they can accomplish any task without waiting for specific command implementations.
|
|
31
|
-
|
|
32
|
-
### The LLM Advantage
|
|
33
|
-
|
|
34
|
-
- **š§ Natural Language ā JavaScript**: Ask an LLM "click the submit button" ā it generates `document.querySelector('#submit').click()`
|
|
35
|
-
- **ā” Instant Testing**: Write, execute, see results, refine - all in seconds
|
|
36
|
-
- **š Iterative Refinement**: LLMs can adjust scripts based on results immediately
|
|
37
|
-
- **š Context-Aware**: AI understands your project and can write automation scripts that fit your specific needs
|
|
38
|
-
- **šÆ No Learning Curve**: LLMs already know JavaScript - no need to learn CLI-specific syntax
|
|
13
|
+
**The result:** A tool that's both powerful enough for complex automation and simple enough that you (and your AI assistant) can actually use it without pulling your hair out.
|
|
39
14
|
|
|
40
15
|
## Implementation Status
|
|
41
16
|
|
|
@@ -51,39 +26,39 @@ A command-line tool designed specifically for Large Language Models (LLMs) and A
|
|
|
51
26
|
- š ļø **IDE Integration**: Install Cursor commands and Claude skills with directory validation and --force option
|
|
52
27
|
- š¦ **Build System**: Complete TypeScript build pipeline with testing framework
|
|
53
28
|
|
|
54
|
-
### š§
|
|
29
|
+
### š§ Available via JavaScript Execution
|
|
55
30
|
|
|
56
|
-
|
|
31
|
+
For maximum flexibility, many advanced features are available through the `eval` command. This approach is particularly powerful for AI assistants and complex automation scenarios:
|
|
57
32
|
|
|
58
33
|
- š **Page Navigation**: `eval "window.location.href = 'https://example.com'"`
|
|
59
34
|
- š **Performance Data**: `eval "performance.now()"` or `eval "performance.getEntriesByType('navigation')"`
|
|
60
35
|
- š± **User Agent**: `eval "navigator.userAgent"`
|
|
61
36
|
- š **Network Requests**: `eval "fetch('/api').then(r => r.json())"`
|
|
62
37
|
|
|
63
|
-
**Why
|
|
38
|
+
**Why JavaScript execution is powerful:**
|
|
64
39
|
|
|
65
|
-
1. **
|
|
66
|
-
2. **Rapid
|
|
67
|
-
3. **
|
|
68
|
-
4. **
|
|
69
|
-
5. **Maximum flexibility**:
|
|
40
|
+
1. **Universal capability**: Any browser API, any complexity level, any scenario
|
|
41
|
+
2. **Rapid prototyping**: Write ā Execute ā See Results ā Refine
|
|
42
|
+
3. **AI-friendly**: Perfect for AI assistants that excel at JavaScript
|
|
43
|
+
4. **No waiting**: Accomplish tasks immediately without waiting for feature implementations
|
|
44
|
+
5. **Maximum flexibility**: Handle edge cases and custom scenarios easily
|
|
70
45
|
|
|
71
|
-
**This
|
|
46
|
+
**This provides both dedicated commands for common tasks and unlimited flexibility through JavaScript execution.**
|
|
72
47
|
|
|
73
|
-
### šÆ IDE Integration - Built for
|
|
48
|
+
### šÆ IDE Integration - Built for Modern Development
|
|
74
49
|
|
|
75
50
|
**Why we support Cursor Commands & Claude Skills:**
|
|
76
51
|
|
|
77
|
-
This tool
|
|
52
|
+
This tool integrates seamlessly with modern AI-powered development environments. The IDE integrations (`install-cursor-command` and `install-claude-skill`) bring browser automation directly into your workflow:
|
|
78
53
|
|
|
79
|
-
- **š Seamless
|
|
80
|
-
- **š§
|
|
81
|
-
- **ā” Instant
|
|
82
|
-
- **š Context-Aware
|
|
83
|
-
- **šÆ Natural Language ā Automation**: Ask "click the submit button" ā AI generates
|
|
54
|
+
- **š Seamless Workflow**: AI assistants can write and execute browser automation scripts directly in your IDE
|
|
55
|
+
- **š§ Natural Integration**: JavaScript execution means AI can accomplish any browser task
|
|
56
|
+
- **ā” Instant Execution**: Write scripts ā execute via commands ā see results ā refine in real-time
|
|
57
|
+
- **š Context-Aware**: AI understands your project context and generates relevant automation
|
|
58
|
+
- **šÆ Natural Language ā Automation**: Ask "click the submit button" ā AI generates and executes the solution
|
|
84
59
|
- **š¤ Perfect for AI Assistants**: Claude and Cursor can use browser automation as part of their toolset
|
|
85
60
|
|
|
86
|
-
**The integration exists because
|
|
61
|
+
**The integration exists because modern development is AI-assisted - these tools work together to enable efficient browser automation.**
|
|
87
62
|
|
|
88
63
|
### ā³ Not Yet Implemented
|
|
89
64
|
|
|
@@ -144,19 +119,29 @@ npm link
|
|
|
144
119
|
Before using the CLI, start Chrome with remote debugging enabled:
|
|
145
120
|
|
|
146
121
|
```bash
|
|
147
|
-
# Default port (9222)
|
|
148
|
-
chrome --remote-debugging-port=9222
|
|
122
|
+
# Default port (9222) - IMPORTANT: Include --user-data-dir to avoid conflicts
|
|
123
|
+
chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile
|
|
149
124
|
|
|
150
125
|
# Custom port
|
|
151
|
-
chrome --remote-debugging-port=9223
|
|
126
|
+
chrome --remote-debugging-port=9223 --user-data-dir=/tmp/chrome-debug-profile
|
|
152
127
|
|
|
153
128
|
# Headless mode
|
|
154
|
-
chrome --headless --remote-debugging-port=9222
|
|
129
|
+
chrome --headless --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile
|
|
155
130
|
|
|
156
131
|
# With additional flags for automation
|
|
157
|
-
chrome --remote-debugging-port=9222 --no-first-run --no-default-browser-check
|
|
132
|
+
chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile --no-first-run --no-default-browser-check
|
|
133
|
+
|
|
134
|
+
# macOS example with full path and logging
|
|
135
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/Users/$USER/chrome-profile-debug > /tmp/chrome.log 2>&1 &
|
|
158
136
|
```
|
|
159
137
|
|
|
138
|
+
**Important Notes:**
|
|
139
|
+
- **Always use `--user-data-dir`**: This creates a separate Chrome profile for debugging and prevents conflicts with your regular Chrome instance
|
|
140
|
+
- **Choose a dedicated directory**: Use a path like `/tmp/chrome-debug-profile` or `/Users/$USER/chrome-profile-debug`
|
|
141
|
+
- **Avoid profile conflicts**: Without `--user-data-dir`, Chrome may fail to open the debugging port if another instance is running
|
|
142
|
+
|
|
143
|
+
For more details, see the [Chrome Remote Debugging documentation](https://developer.chrome.com/blog/remote-debugging-port).
|
|
144
|
+
|
|
160
145
|
## Quick Start
|
|
161
146
|
|
|
162
147
|
```bash
|
|
@@ -437,7 +422,7 @@ chrome-cdp-cli install_cursor_command --force
|
|
|
437
422
|
chrome-cdp-cli install_claude_skill --force
|
|
438
423
|
```
|
|
439
424
|
|
|
440
|
-
### š§ Available via
|
|
425
|
+
### š§ Available via JavaScript Execution
|
|
441
426
|
|
|
442
427
|
#### Page Management
|
|
443
428
|
```bash
|
|
@@ -464,7 +449,7 @@ chrome-cdp-cli click "#button"
|
|
|
464
449
|
chrome-cdp-cli hover ".menu-item"
|
|
465
450
|
chrome-cdp-cli fill "#email" "user@example.com"
|
|
466
451
|
|
|
467
|
-
# Via
|
|
452
|
+
# Via JavaScript execution (flexible for complex scenarios)
|
|
468
453
|
chrome-cdp-cli eval "document.querySelector('#button').click()"
|
|
469
454
|
chrome-cdp-cli eval "document.querySelector('.menu-item').dispatchEvent(new MouseEvent('mouseover'))"
|
|
470
455
|
chrome-cdp-cli eval "document.querySelector('#email').value = 'user@example.com'"
|
|
@@ -492,7 +477,7 @@ chrome-cdp-cli fill_form --fields '[
|
|
|
492
477
|
chrome-cdp-cli fill "#name" "John Doe"
|
|
493
478
|
chrome-cdp-cli fill "#email" "john@example.com"
|
|
494
479
|
|
|
495
|
-
# Via
|
|
480
|
+
# Via JavaScript execution (for complex form operations)
|
|
496
481
|
chrome-cdp-cli eval "
|
|
497
482
|
document.querySelector('#name').value = 'John Doe';
|
|
498
483
|
document.querySelector('#email').value = 'john@example.com';
|
|
@@ -505,7 +490,7 @@ chrome-cdp-cli eval "document.querySelector('#myform').submit()"
|
|
|
505
490
|
# Select dropdown option (native)
|
|
506
491
|
chrome-cdp-cli fill "#dropdown" "option1"
|
|
507
492
|
|
|
508
|
-
# Select dropdown option (via
|
|
493
|
+
# Select dropdown option (via JavaScript execution)
|
|
509
494
|
chrome-cdp-cli eval "document.querySelector('#dropdown').value = 'option1'"
|
|
510
495
|
|
|
511
496
|
# Check checkbox
|
|
@@ -690,25 +675,25 @@ new Promise(resolve => {
|
|
|
690
675
|
- Quiet and verbose modes
|
|
691
676
|
- Custom output templates
|
|
692
677
|
|
|
693
|
-
### Why
|
|
678
|
+
### Why JavaScript Execution? (Built for Modern Development)
|
|
694
679
|
|
|
695
|
-
**This is not a workaround - it's
|
|
680
|
+
**This is not a workaround - it's a core design philosophy optimized for modern development workflows:**
|
|
696
681
|
|
|
697
|
-
1. **š§
|
|
682
|
+
1. **š§ Universal Language**: JavaScript is the language of the web. Developers and AI assistants alike excel at writing JavaScript for browser automation.
|
|
698
683
|
|
|
699
|
-
2. **ā” Rapid
|
|
684
|
+
2. **ā” Rapid Prototyping**: The perfect workflow: Write JavaScript ā Execute ā See Results ā Refine. This iterative loop is ideal for both human developers and AI assistants.
|
|
700
685
|
|
|
701
686
|
3. **š Maximum Flexibility**: Any browser task, any complexity, any scenario - all through JavaScript. No waiting for specific command implementations.
|
|
702
687
|
|
|
703
|
-
4. **š¤ AI-Native Workflow**: When you ask Claude or Cursor to automate something, they write JavaScript - exactly what `eval` executes.
|
|
688
|
+
4. **š¤ AI-Native Workflow**: When you ask Claude or Cursor to automate something, they naturally write JavaScript - exactly what the `eval` command executes.
|
|
704
689
|
|
|
705
690
|
5. **š Natural Language ā Automation**: "Click the submit button" ā AI generates `document.querySelector('#submit').click()` ā Executes instantly.
|
|
706
691
|
|
|
707
692
|
6. **šÆ Context-Aware**: AI understands your project and can write automation scripts that fit your specific needs.
|
|
708
693
|
|
|
709
|
-
7. **ā” Instant Iteration**:
|
|
694
|
+
7. **ā” Instant Iteration**: Both developers and AI can adjust scripts based on results immediately - no need to wait for feature releases.
|
|
710
695
|
|
|
711
|
-
**This tool
|
|
696
|
+
**This tool bridges the gap between dedicated commands for common tasks and unlimited flexibility through JavaScript execution, making it perfect for both traditional development and AI-assisted workflows.**
|
|
712
697
|
|
|
713
698
|
## Form Filling & Element Interaction
|
|
714
699
|
|
|
@@ -1044,18 +1029,26 @@ console.log(result);
|
|
|
1044
1029
|
### Common Issues
|
|
1045
1030
|
|
|
1046
1031
|
1. **Connection Refused**
|
|
1047
|
-
- Ensure Chrome is running with `--remote-debugging-port=9222`
|
|
1032
|
+
- Ensure Chrome is running with `--remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug`
|
|
1033
|
+
- **Always include `--user-data-dir`** to avoid profile conflicts
|
|
1048
1034
|
- Check if the port is correct and not blocked by firewall
|
|
1035
|
+
- Verify no other Chrome instances are using the same debugging port
|
|
1036
|
+
|
|
1037
|
+
2. **Chrome Won't Start Debugging Port**
|
|
1038
|
+
- **Most common cause**: Missing `--user-data-dir` parameter
|
|
1039
|
+
- **Solution**: Use a dedicated profile directory: `--user-data-dir=/tmp/chrome-debug-profile`
|
|
1040
|
+
- **Why needed**: Prevents conflicts with existing Chrome instances
|
|
1041
|
+
- See [Chrome Remote Debugging documentation](https://developer.chrome.com/blog/remote-debugging-port) for details
|
|
1049
1042
|
|
|
1050
|
-
|
|
1043
|
+
3. **Command Timeout**
|
|
1051
1044
|
- Increase timeout with `--timeout` option
|
|
1052
1045
|
- Check if the page is responsive
|
|
1053
1046
|
|
|
1054
|
-
|
|
1047
|
+
4. **Element Not Found**
|
|
1055
1048
|
- Verify CSS selectors are correct
|
|
1056
1049
|
- Use `wait_for` command to wait for dynamic elements
|
|
1057
1050
|
|
|
1058
|
-
|
|
1051
|
+
5. **Permission Denied**
|
|
1059
1052
|
- Ensure Chrome has necessary permissions
|
|
1060
1053
|
- Check file system permissions for screenshot output
|
|
1061
1054
|
|
|
@@ -1077,31 +1070,6 @@ npm run package
|
|
|
1077
1070
|
npm run prepublishOnly
|
|
1078
1071
|
```
|
|
1079
1072
|
|
|
1080
|
-
## Publishing to npm
|
|
1081
|
-
|
|
1082
|
-
To make this tool available via `npx`, you need to publish it to npm:
|
|
1083
|
-
|
|
1084
|
-
```bash
|
|
1085
|
-
# 1. Login to npm (one time setup)
|
|
1086
|
-
npm login
|
|
1087
|
-
|
|
1088
|
-
# 2. Publish the package
|
|
1089
|
-
npm publish
|
|
1090
|
-
|
|
1091
|
-
# 3. Users can then use it with npx
|
|
1092
|
-
npx chrome-cdp-cli eval "document.title"
|
|
1093
|
-
```
|
|
1094
|
-
|
|
1095
|
-
**Note**: The package name `chrome-cdp-cli` uses a clean, descriptive approach. This approach:
|
|
1096
|
-
|
|
1097
|
-
- ā
**Professional naming** that clearly indicates Chrome DevTools Protocol CLI
|
|
1098
|
-
- ā
**Works with npx**: `npx chrome-cdp-cli eval "document.title"`
|
|
1099
|
-
- ā
**Simple installation**: `npm install -g chrome-cdp-cli`
|
|
1100
|
-
- ā
**Short and memorable** compared to longer alternatives
|
|
1101
|
-
|
|
1102
|
-
Alternative naming examples:
|
|
1103
|
-
1. **Scoped name**: `@nickxiao42/chrome-devtools-cli`
|
|
1104
|
-
2. **Longer descriptive**: `chrome-automation-cli`
|
|
1105
1073
|
|
|
1106
1074
|
## Contributing
|
|
1107
1075
|
|
|
@@ -35,28 +35,45 @@ class CLIApplication {
|
|
|
35
35
|
this.cli.registerHandler(new handlers_1.WaitForHandler());
|
|
36
36
|
this.cli.registerHandler(new handlers_1.HandleDialogHandler());
|
|
37
37
|
}
|
|
38
|
+
configureDebugMode(debug) {
|
|
39
|
+
const registry = this.cli.getRegistry();
|
|
40
|
+
const handlerNames = registry.getCommandNames();
|
|
41
|
+
for (const handlerName of handlerNames) {
|
|
42
|
+
const handler = registry.get(handlerName);
|
|
43
|
+
if (handler && typeof handler.setDebug === 'function') {
|
|
44
|
+
handler.setDebug(debug);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
38
48
|
async run(argv) {
|
|
39
49
|
try {
|
|
40
|
-
console.log('[DEBUG] CLIApplication.run called with argv:', argv);
|
|
41
50
|
const command = this.cli.parseArgs(argv);
|
|
42
|
-
|
|
51
|
+
if (command.config.debug) {
|
|
52
|
+
this.logger.setLevel(3);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.logger.setLevel(2);
|
|
56
|
+
}
|
|
57
|
+
this.configureDebugMode(command.config.debug);
|
|
58
|
+
this.logger.debug('CLIApplication.run called with argv:', argv);
|
|
59
|
+
this.logger.debug('Parsed command:', command);
|
|
43
60
|
if (command.config.verbose) {
|
|
44
61
|
this.proxyManager.setLogging(true);
|
|
45
62
|
}
|
|
46
|
-
|
|
63
|
+
this.logger.debug('Ensuring proxy is ready...');
|
|
47
64
|
await this.ensureProxyReady();
|
|
48
65
|
if (this.needsConnection(command.name)) {
|
|
49
|
-
|
|
66
|
+
this.logger.debug('Command needs connection, ensuring connection...');
|
|
50
67
|
await this.ensureConnection(command);
|
|
51
68
|
}
|
|
52
|
-
|
|
69
|
+
this.logger.debug('Executing command via CLI interface...');
|
|
53
70
|
const result = await this.cli.execute(command);
|
|
54
|
-
|
|
71
|
+
this.logger.debug('Command execution result:', result);
|
|
55
72
|
this.outputResult(result, command);
|
|
56
73
|
return result.exitCode || (result.success ? CommandRouter_1.ExitCode.SUCCESS : CommandRouter_1.ExitCode.GENERAL_ERROR);
|
|
57
74
|
}
|
|
58
75
|
catch (error) {
|
|
59
|
-
|
|
76
|
+
this.logger.debug('Error in CLIApplication.run:', error);
|
|
60
77
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
61
78
|
console.error(`Error: ${errorMessage}`);
|
|
62
79
|
return CommandRouter_1.ExitCode.GENERAL_ERROR;
|
package/dist/cli/CLIInterface.js
CHANGED
|
@@ -61,6 +61,7 @@ class CLIInterface {
|
|
|
61
61
|
.option('-v, --verbose', 'Enable verbose logging', CLIInterface_1.DEFAULT_CLI_CONFIG.verbose)
|
|
62
62
|
.option('-q, --quiet', 'Enable quiet mode', CLIInterface_1.DEFAULT_CLI_CONFIG.quiet)
|
|
63
63
|
.option('-t, --timeout <timeout>', 'Command timeout in milliseconds', (value) => parseInt(value, 10), CLIInterface_1.DEFAULT_CLI_CONFIG.timeout)
|
|
64
|
+
.option('-d, --debug', 'Enable debug logging', CLIInterface_1.DEFAULT_CLI_CONFIG.debug)
|
|
64
65
|
.option('-c, --config <config>', 'Configuration file path');
|
|
65
66
|
}
|
|
66
67
|
parseArgs(argv) {
|
|
@@ -77,7 +78,12 @@ class CLIInterface {
|
|
|
77
78
|
const arg = args[i];
|
|
78
79
|
if (arg.startsWith('--')) {
|
|
79
80
|
const optionName = arg.substring(2);
|
|
80
|
-
|
|
81
|
+
const booleanFlags = ['verbose', 'quiet', 'debug'];
|
|
82
|
+
if (booleanFlags.includes(optionName)) {
|
|
83
|
+
options[optionName] = true;
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
else if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
81
87
|
options[optionName] = args[i + 1];
|
|
82
88
|
i += 2;
|
|
83
89
|
}
|
|
@@ -88,7 +94,12 @@ class CLIInterface {
|
|
|
88
94
|
}
|
|
89
95
|
else if (arg.startsWith('-') && arg.length > 1) {
|
|
90
96
|
const shortOption = arg.substring(1);
|
|
91
|
-
|
|
97
|
+
const booleanShortFlags = ['v', 'q', 'd'];
|
|
98
|
+
if (booleanShortFlags.includes(shortOption)) {
|
|
99
|
+
options[shortOption] = true;
|
|
100
|
+
i++;
|
|
101
|
+
}
|
|
102
|
+
else if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
92
103
|
options[shortOption] = args[i + 1];
|
|
93
104
|
i += 2;
|
|
94
105
|
}
|
|
@@ -114,6 +125,8 @@ class CLIInterface {
|
|
|
114
125
|
options.quiet = true;
|
|
115
126
|
if (options.t)
|
|
116
127
|
options.timeout = parseInt(options.t, 10);
|
|
128
|
+
if (options.d)
|
|
129
|
+
options.debug = true;
|
|
117
130
|
if (options.c)
|
|
118
131
|
options.config = options.c;
|
|
119
132
|
if (options.port && typeof options.port === 'string') {
|
|
@@ -163,7 +176,8 @@ class CLIInterface {
|
|
|
163
176
|
outputFormat: cliOptions.format || fileConfig.outputFormat || CLIInterface_1.DEFAULT_CLI_CONFIG.outputFormat,
|
|
164
177
|
verbose: cliOptions.verbose || fileConfig.verbose || CLIInterface_1.DEFAULT_CLI_CONFIG.verbose,
|
|
165
178
|
quiet: cliOptions.quiet || fileConfig.quiet || CLIInterface_1.DEFAULT_CLI_CONFIG.quiet,
|
|
166
|
-
timeout: cliOptions.timeout || fileConfig.timeout || CLIInterface_1.DEFAULT_CLI_CONFIG.timeout
|
|
179
|
+
timeout: cliOptions.timeout || fileConfig.timeout || CLIInterface_1.DEFAULT_CLI_CONFIG.timeout,
|
|
180
|
+
debug: cliOptions.debug || fileConfig.debug || CLIInterface_1.DEFAULT_CLI_CONFIG.debug
|
|
167
181
|
};
|
|
168
182
|
}
|
|
169
183
|
loadConfigFile(configPath) {
|
|
@@ -199,6 +213,9 @@ class CLIInterface {
|
|
|
199
213
|
if (config.timeout !== undefined && (typeof config.timeout !== 'number' || config.timeout < 1)) {
|
|
200
214
|
throw new Error('Configuration "timeout" must be a positive number');
|
|
201
215
|
}
|
|
216
|
+
if (config.debug !== undefined && typeof config.debug !== 'boolean') {
|
|
217
|
+
throw new Error('Configuration "debug" must be a boolean');
|
|
218
|
+
}
|
|
202
219
|
}
|
|
203
220
|
extractCommandArgs(command, args, options) {
|
|
204
221
|
const commandArgs = {};
|
|
@@ -169,18 +169,24 @@ class CommandRouter {
|
|
|
169
169
|
}
|
|
170
170
|
async executeWithTimeout(handler, command) {
|
|
171
171
|
const timeout = command.config.timeout;
|
|
172
|
-
|
|
172
|
+
if (command.config.debug) {
|
|
173
|
+
this.logger.setLevel(3);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.logger.setLevel(2);
|
|
177
|
+
}
|
|
178
|
+
this.logger.debug(`CommandRouter.executeWithTimeout called for command: ${command.name}, timeout: ${timeout}ms`);
|
|
173
179
|
const timeoutPromise = new Promise((_, reject) => {
|
|
174
180
|
setTimeout(() => {
|
|
175
|
-
|
|
181
|
+
this.logger.debug(`Command timeout reached for: ${command.name} after ${timeout}ms`);
|
|
176
182
|
reject(new Error(`Command timeout after ${timeout}ms`));
|
|
177
183
|
}, timeout);
|
|
178
184
|
});
|
|
179
|
-
|
|
185
|
+
this.logger.debug(`Starting handler execution for: ${command.name}`);
|
|
180
186
|
const executionPromise = handler.execute(this.client, command.args);
|
|
181
187
|
try {
|
|
182
188
|
const result = await Promise.race([executionPromise, timeoutPromise]);
|
|
183
|
-
|
|
189
|
+
this.logger.debug(`Command completed successfully for: ${command.name}`);
|
|
184
190
|
if (!result || typeof result !== 'object') {
|
|
185
191
|
return {
|
|
186
192
|
success: false,
|
|
@@ -194,7 +200,7 @@ class CommandRouter {
|
|
|
194
200
|
return result;
|
|
195
201
|
}
|
|
196
202
|
catch (error) {
|
|
197
|
-
|
|
203
|
+
this.logger.debug(`Command execution error for: ${command.name}:`, error);
|
|
198
204
|
if (error instanceof Error && error.message.includes('timeout')) {
|
|
199
205
|
return {
|
|
200
206
|
success: false,
|
|
@@ -218,6 +224,7 @@ Global Options:
|
|
|
218
224
|
-v, --verbose Enable verbose logging
|
|
219
225
|
-q, --quiet Enable quiet mode
|
|
220
226
|
-t, --timeout <ms> Command timeout in milliseconds (default: 30000)
|
|
227
|
+
-d, --debug Enable debug logging
|
|
221
228
|
-c, --config <path> Configuration file path
|
|
222
229
|
-V, --version Show version number
|
|
223
230
|
|
|
@@ -5,16 +5,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.EvaluateScriptHandler = void 0;
|
|
7
7
|
const ProxyClient_1 = require("../client/ProxyClient");
|
|
8
|
+
const logger_1 = require("../utils/logger");
|
|
8
9
|
const fs_1 = require("fs");
|
|
9
10
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
10
11
|
class EvaluateScriptHandler {
|
|
11
|
-
constructor(useProxy = false) {
|
|
12
|
+
constructor(useProxy = false, debug = false) {
|
|
12
13
|
this.name = 'eval';
|
|
13
14
|
this.proxyClient = new ProxyClient_1.ProxyClient();
|
|
14
15
|
this.useProxy = useProxy;
|
|
16
|
+
this.logger = new logger_1.Logger();
|
|
17
|
+
if (debug) {
|
|
18
|
+
this.logger.setLevel(3);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this.logger.setLevel(2);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
setDebug(debug) {
|
|
25
|
+
if (debug) {
|
|
26
|
+
this.logger.setLevel(3);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.logger.setLevel(2);
|
|
30
|
+
}
|
|
15
31
|
}
|
|
16
32
|
async execute(client, args) {
|
|
17
|
-
|
|
33
|
+
this.logger.debug('EvaluateScriptHandler.execute called with args:', args);
|
|
18
34
|
const scriptArgs = args;
|
|
19
35
|
if (!scriptArgs.expression && !scriptArgs.file) {
|
|
20
36
|
return {
|
|
@@ -28,17 +44,17 @@ class EvaluateScriptHandler {
|
|
|
28
44
|
error: 'Cannot specify both "expression" and "file" arguments'
|
|
29
45
|
};
|
|
30
46
|
}
|
|
31
|
-
|
|
47
|
+
this.logger.debug('Arguments validated, useProxy:', this.useProxy);
|
|
32
48
|
try {
|
|
33
49
|
if (this.useProxy) {
|
|
34
|
-
|
|
50
|
+
this.logger.debug('Checking proxy availability...');
|
|
35
51
|
const proxyAvailable = await this.proxyClient.isProxyAvailable();
|
|
36
|
-
|
|
52
|
+
this.logger.debug('Proxy available:', proxyAvailable);
|
|
37
53
|
if (proxyAvailable) {
|
|
38
54
|
console.log('[INFO] Using proxy connection for script evaluation');
|
|
39
|
-
|
|
55
|
+
this.logger.debug('About to call executeWithProxy...');
|
|
40
56
|
const result = await this.executeWithProxy(scriptArgs);
|
|
41
|
-
|
|
57
|
+
this.logger.debug('executeWithProxy returned:', result);
|
|
42
58
|
return result;
|
|
43
59
|
}
|
|
44
60
|
else {
|
|
@@ -49,12 +65,12 @@ class EvaluateScriptHandler {
|
|
|
49
65
|
catch (error) {
|
|
50
66
|
console.warn('[WARN] Proxy execution failed, falling back to direct CDP:', error instanceof Error ? error.message : error);
|
|
51
67
|
}
|
|
52
|
-
|
|
68
|
+
this.logger.debug('Falling back to direct CDP');
|
|
53
69
|
return await this.executeWithDirectCDP(client, scriptArgs);
|
|
54
70
|
}
|
|
55
71
|
async executeWithProxy(scriptArgs) {
|
|
56
72
|
try {
|
|
57
|
-
|
|
73
|
+
this.logger.debug('Starting executeWithProxy');
|
|
58
74
|
let expression;
|
|
59
75
|
if (scriptArgs.file) {
|
|
60
76
|
expression = await this.readScriptFile(scriptArgs.file);
|
|
@@ -62,10 +78,10 @@ class EvaluateScriptHandler {
|
|
|
62
78
|
else {
|
|
63
79
|
expression = scriptArgs.expression;
|
|
64
80
|
}
|
|
65
|
-
|
|
66
|
-
|
|
81
|
+
this.logger.debug('Expression to execute:', expression.substring(0, 100));
|
|
82
|
+
this.logger.debug('Creating new proxy connection...');
|
|
67
83
|
const connectionId = await this.proxyClient.connect('localhost', 9222);
|
|
68
|
-
|
|
84
|
+
this.logger.debug(`Created new proxy connection: ${connectionId}`);
|
|
69
85
|
try {
|
|
70
86
|
const result = await this.executeScriptThroughHTTP(connectionId, expression, scriptArgs);
|
|
71
87
|
return {
|
|
@@ -78,7 +94,7 @@ class EvaluateScriptHandler {
|
|
|
78
94
|
}
|
|
79
95
|
}
|
|
80
96
|
catch (error) {
|
|
81
|
-
|
|
97
|
+
this.logger.debug('Error in executeWithProxy:', error);
|
|
82
98
|
return {
|
|
83
99
|
success: false,
|
|
84
100
|
error: error instanceof Error ? error.message : String(error)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-cdp-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7",
|
|
4
4
|
"description": "Browser automation CLI via Chrome DevTools Protocol. Designed for developers and AI assistants - combines dedicated commands for common tasks with flexible JavaScript execution for complex scenarios. Features: element interaction, screenshots, DOM snapshots, console/network monitoring. Built-in IDE integration for Cursor and Claude.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"prepublishOnly": "npm run test:ci && npm run build:prod",
|
|
36
36
|
"prepack": "npm run build:prod",
|
|
37
37
|
"verify": "npm run lint && npm run test:ci && npm run build:prod",
|
|
38
|
-
"postinstall": "node -e \"console.log('\\nš chrome-cdp-cli installed successfully!\\n\\nš Quick Start:\\n 1. Start Chrome with debugging: chrome --remote-debugging-port=9222\\n 2. Try: chrome-cdp-cli eval \\\"document.title\\\"\\n 3. Get help: chrome-cdp-cli --help\\n\\nš More info: https://github.com/nicoster/chrome-devtools-cli\\n')\""
|
|
38
|
+
"postinstall": "node -e \"console.log('\\nš chrome-cdp-cli installed successfully!\\n\\nš Quick Start:\\n 1. Start Chrome with debugging: chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug\\n 2. Try: chrome-cdp-cli eval \\\"document.title\\\"\\n 3. Get help: chrome-cdp-cli --help\\n\\nš More info: https://github.com/nicoster/chrome-devtools-cli\\n')\""
|
|
39
39
|
},
|
|
40
40
|
"keywords": [
|
|
41
41
|
"chrome",
|