chrome-cdp-cli 2.0.1 → 2.0.3
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
|
@@ -35,6 +35,7 @@ A command-line tool for browser automation via Chrome DevTools Protocol (CDP). D
|
|
|
35
35
|
- 📊 **Console Monitoring**: Real-time console message capture with filtering and storage
|
|
36
36
|
- 🌐 **Network Monitoring**: Real-time network request/response monitoring with comprehensive filtering
|
|
37
37
|
- 🖱️ **Element Interaction**: Complete native interaction commands (click, hover, fill, drag, press_key, upload_file, wait_for, handle_dialog)
|
|
38
|
+
- 🔄 **Proxy Management**: Restart proxy server to refresh stale console and network logs
|
|
38
39
|
- 🔧 **CLI Interface**: Full command-line interface with argument parsing and routing
|
|
39
40
|
- 🛠️ **IDE Integration**: Install Cursor commands and Claude skills with directory validation and --force option
|
|
40
41
|
- 📦 **Build System**: Complete TypeScript build pipeline with testing framework
|
|
@@ -88,6 +89,7 @@ This tool integrates seamlessly with modern AI-powered development environments.
|
|
|
88
89
|
- 📊 **Monitoring**: Monitor console messages and network requests in real-time
|
|
89
90
|
- 🖱️ **Element Interaction**: Complete native interaction commands (click, hover, fill, drag, press_key, upload_file, wait_for, handle_dialog)
|
|
90
91
|
- 📝 **Form Automation**: Single field and batch form filling with comprehensive options
|
|
92
|
+
- 🔄 **Proxy Management**: Restart proxy server to refresh stale logs
|
|
91
93
|
- 🔧 **Flexible Output**: Support for JSON and human-readable text output formats
|
|
92
94
|
- 🚧 **Eval Workarounds**: Many advanced features available through JavaScript execution
|
|
93
95
|
|
|
@@ -170,8 +172,8 @@ chrome-cdp-cli eval "window.location.href = 'https://example.com'"
|
|
|
170
172
|
# Take a screenshot
|
|
171
173
|
chrome-cdp-cli screenshot --filename screenshot.png
|
|
172
174
|
|
|
173
|
-
# Capture DOM snapshot
|
|
174
|
-
chrome-cdp-cli snapshot --filename dom-snapshot.
|
|
175
|
+
# Capture DOM snapshot (default: text format)
|
|
176
|
+
chrome-cdp-cli snapshot --filename dom-snapshot.txt
|
|
175
177
|
|
|
176
178
|
# Element interactions
|
|
177
179
|
chrome-cdp-cli click "#submit-button"
|
|
@@ -190,8 +192,11 @@ chrome-cdp-cli handle_dialog accept
|
|
|
190
192
|
chrome-cdp-cli fill_form --fields '[{"selector":"#username","value":"john"},{"selector":"#password","value":"secret"}]'
|
|
191
193
|
|
|
192
194
|
# Monitor console and network
|
|
193
|
-
chrome-cdp-cli
|
|
194
|
-
chrome-cdp-cli
|
|
195
|
+
chrome-cdp-cli console --latest
|
|
196
|
+
chrome-cdp-cli network --latest
|
|
197
|
+
|
|
198
|
+
# Restart proxy server when logs are stale
|
|
199
|
+
chrome-cdp-cli restart
|
|
195
200
|
|
|
196
201
|
# Install IDE integrations
|
|
197
202
|
chrome-cdp-cli install_cursor_command
|
|
@@ -262,8 +267,8 @@ chrome-cdp-cli screenshot --filename screenshot.png
|
|
|
262
267
|
# Full page screenshot
|
|
263
268
|
chrome-cdp-cli screenshot --full-page --filename fullpage.png
|
|
264
269
|
|
|
265
|
-
# DOM snapshot with complete layout information
|
|
266
|
-
chrome-cdp-cli snapshot --filename dom-snapshot.
|
|
270
|
+
# DOM snapshot with complete layout information (default: text format)
|
|
271
|
+
chrome-cdp-cli snapshot --filename dom-snapshot.txt
|
|
267
272
|
|
|
268
273
|
# Custom dimensions
|
|
269
274
|
chrome-cdp-cli screenshot --width 1920 --height 1080 --filename custom.png
|
|
@@ -376,13 +381,19 @@ chrome-cdp-cli handle_dialog accept --timeout 10000 # Wait for dialog to appear
|
|
|
376
381
|
#### Console Monitoring
|
|
377
382
|
```bash
|
|
378
383
|
# Get latest console message
|
|
379
|
-
chrome-cdp-cli
|
|
384
|
+
chrome-cdp-cli console --latest
|
|
380
385
|
|
|
381
386
|
# List all console messages
|
|
382
|
-
chrome-cdp-cli
|
|
387
|
+
chrome-cdp-cli console
|
|
383
388
|
|
|
384
389
|
# Filter console messages by type
|
|
385
|
-
chrome-cdp-cli
|
|
390
|
+
chrome-cdp-cli console --types error,warn
|
|
391
|
+
|
|
392
|
+
# Filter by text pattern
|
|
393
|
+
chrome-cdp-cli console --textPattern "error|warning"
|
|
394
|
+
|
|
395
|
+
# Limit number of messages
|
|
396
|
+
chrome-cdp-cli console --maxMessages 10
|
|
386
397
|
```
|
|
387
398
|
|
|
388
399
|
**Note**: Console monitoring only captures messages generated *after* monitoring starts. For historical messages or immediate console operations, use the eval-first approach:
|
|
@@ -400,13 +411,22 @@ See [Console Monitoring Documentation](docs/CONSOLE_MONITORING.md) for detailed
|
|
|
400
411
|
#### Network Monitoring
|
|
401
412
|
```bash
|
|
402
413
|
# Get latest network request
|
|
403
|
-
chrome-cdp-cli
|
|
414
|
+
chrome-cdp-cli network --latest
|
|
404
415
|
|
|
405
416
|
# List all network requests
|
|
406
|
-
chrome-cdp-cli
|
|
417
|
+
chrome-cdp-cli network
|
|
407
418
|
|
|
408
419
|
# Filter network requests by method
|
|
409
|
-
chrome-cdp-cli
|
|
420
|
+
chrome-cdp-cli network --filter '{"methods":["POST"],"statusCodes":[200,201]}'
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### Proxy Management
|
|
424
|
+
```bash
|
|
425
|
+
# Restart proxy server when console or network logs become stale
|
|
426
|
+
chrome-cdp-cli restart
|
|
427
|
+
|
|
428
|
+
# Force restart even if proxy is healthy
|
|
429
|
+
chrome-cdp-cli restart --force
|
|
410
430
|
```
|
|
411
431
|
|
|
412
432
|
#### IDE Integration
|
|
@@ -884,11 +904,14 @@ chrome-cdp-cli eval --file script.js
|
|
|
884
904
|
|
|
885
905
|
# Visual capture
|
|
886
906
|
chrome-cdp-cli screenshot --filename page.png
|
|
887
|
-
chrome-cdp-cli snapshot --filename dom.
|
|
907
|
+
chrome-cdp-cli snapshot --filename dom.txt
|
|
888
908
|
|
|
889
909
|
# Monitoring
|
|
890
|
-
chrome-cdp-cli
|
|
891
|
-
chrome-cdp-cli
|
|
910
|
+
chrome-cdp-cli console --latest
|
|
911
|
+
chrome-cdp-cli network
|
|
912
|
+
|
|
913
|
+
# Proxy management
|
|
914
|
+
chrome-cdp-cli restart
|
|
892
915
|
```
|
|
893
916
|
|
|
894
917
|
For detailed documentation, see the [Form Filling Guide](docs/FORM_FILLING.md).
|
|
@@ -459,6 +459,17 @@ class CommandSchemaRegistry {
|
|
|
459
459
|
description: 'Include text index information',
|
|
460
460
|
type: 'boolean',
|
|
461
461
|
default: false
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
name: 'color',
|
|
465
|
+
description: 'Enable color output (default: auto-detect)',
|
|
466
|
+
type: 'boolean'
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: 'no-color',
|
|
470
|
+
description: 'Disable color output',
|
|
471
|
+
type: 'boolean',
|
|
472
|
+
default: false
|
|
462
473
|
}
|
|
463
474
|
],
|
|
464
475
|
arguments: []
|
package/dist/client/CDPClient.js
CHANGED
|
@@ -141,7 +141,8 @@ class CDPClient {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
async discoverTargets(host, port) {
|
|
144
|
-
const
|
|
144
|
+
const normalizedHost = host === 'localhost' ? '127.0.0.1' : host;
|
|
145
|
+
const response = await (0, node_fetch_1.default)(`http://${normalizedHost}:${port}/json/list`);
|
|
145
146
|
if (!response.ok) {
|
|
146
147
|
throw new Error(`Failed to discover targets: ${response.statusText}`);
|
|
147
148
|
}
|
|
@@ -44,7 +44,8 @@ class ConnectionManager {
|
|
|
44
44
|
this.logger = logger || new logger_1.Logger();
|
|
45
45
|
}
|
|
46
46
|
async discoverTargets(host, port) {
|
|
47
|
-
const
|
|
47
|
+
const normalizedHost = host === 'localhost' ? '127.0.0.1' : host;
|
|
48
|
+
const url = `http://${normalizedHost}:${port}/json/list`;
|
|
48
49
|
try {
|
|
49
50
|
this.logger.debug(`Discovering targets at ${url}`);
|
|
50
51
|
const http = await Promise.resolve().then(() => __importStar(require('http')));
|
|
@@ -6,9 +6,93 @@ const path_1 = require("path");
|
|
|
6
6
|
class TakeSnapshotHandler {
|
|
7
7
|
constructor() {
|
|
8
8
|
this.name = 'snapshot';
|
|
9
|
+
this.colors = {
|
|
10
|
+
reset: '\x1b[0m',
|
|
11
|
+
bright: '\x1b[1m',
|
|
12
|
+
dim: '\x1b[2m',
|
|
13
|
+
red: '\x1b[31m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
blue: '\x1b[34m',
|
|
17
|
+
magenta: '\x1b[35m',
|
|
18
|
+
cyan: '\x1b[36m',
|
|
19
|
+
white: '\x1b[37m',
|
|
20
|
+
gray: '\x1b[90m',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
shouldUseColors(args) {
|
|
24
|
+
if (args.color === false) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (args.color === true) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (process.env.NO_COLOR) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (process.env.FORCE_COLOR === '0') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (process.env.FORCE_COLOR === '1' || process.env.FORCE_COLOR === 'true') {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (args.filename) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return process.stdout.isTTY === true;
|
|
43
|
+
}
|
|
44
|
+
colorize(text, color, useColors) {
|
|
45
|
+
if (!useColors)
|
|
46
|
+
return text;
|
|
47
|
+
return `${color}${text}${this.colors.reset}`;
|
|
48
|
+
}
|
|
49
|
+
colorTag(tagName, useColors) {
|
|
50
|
+
if (['button', 'a', 'input', 'textarea', 'select'].includes(tagName.toLowerCase())) {
|
|
51
|
+
return this.colorize(tagName.toUpperCase(), this.colors.green + this.colors.bright, useColors);
|
|
52
|
+
}
|
|
53
|
+
if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tagName.toLowerCase())) {
|
|
54
|
+
return this.colorize(tagName.toUpperCase(), this.colors.cyan + this.colors.bright, useColors);
|
|
55
|
+
}
|
|
56
|
+
if (tagName.toLowerCase() === 'img') {
|
|
57
|
+
return this.colorize(tagName.toUpperCase(), this.colors.magenta, useColors);
|
|
58
|
+
}
|
|
59
|
+
return this.colorize(tagName.toUpperCase(), this.colors.cyan, useColors);
|
|
60
|
+
}
|
|
61
|
+
colorId(id, useColors) {
|
|
62
|
+
return this.colorize(`#${id}`, this.colors.green, useColors);
|
|
63
|
+
}
|
|
64
|
+
colorClass(className, useColors) {
|
|
65
|
+
return this.colorize(`.${className}`, this.colors.yellow, useColors);
|
|
66
|
+
}
|
|
67
|
+
colorAttribute(name, value, useColors) {
|
|
68
|
+
if (name === 'type') {
|
|
69
|
+
return this.colorize(`[${value}]`, this.colors.magenta, useColors);
|
|
70
|
+
}
|
|
71
|
+
if (name === 'name') {
|
|
72
|
+
return this.colorize(`name="${value}"`, this.colors.magenta, useColors);
|
|
73
|
+
}
|
|
74
|
+
return `[${name}="${value}"]`;
|
|
75
|
+
}
|
|
76
|
+
colorText(text, useColors) {
|
|
77
|
+
return this.colorize(`"${text}"`, this.colors.white, useColors);
|
|
78
|
+
}
|
|
79
|
+
colorUrl(url, useColors) {
|
|
80
|
+
return this.colorize(`"${url}"`, this.colors.blue, useColors);
|
|
81
|
+
}
|
|
82
|
+
colorSpecial(text, useColors) {
|
|
83
|
+
return this.colorize(text, this.colors.yellow, useColors);
|
|
84
|
+
}
|
|
85
|
+
colorTreeSymbol(symbol, useColors) {
|
|
86
|
+
return this.colorize(symbol, this.colors.gray, useColors);
|
|
87
|
+
}
|
|
88
|
+
colorPageTitle(title, useColors) {
|
|
89
|
+
return this.colorize(`PAGE: ${title}`, this.colors.cyan + this.colors.bright, useColors);
|
|
9
90
|
}
|
|
10
91
|
async execute(client, args) {
|
|
11
92
|
const snapshotArgs = args;
|
|
93
|
+
if (snapshotArgs['no-color']) {
|
|
94
|
+
snapshotArgs.color = false;
|
|
95
|
+
}
|
|
12
96
|
try {
|
|
13
97
|
await client.send('DOM.enable');
|
|
14
98
|
await client.send('CSS.enable');
|
|
@@ -89,7 +173,8 @@ class TakeSnapshotHandler {
|
|
|
89
173
|
processedSnapshot = htmlResponse.outerHTML;
|
|
90
174
|
}
|
|
91
175
|
else {
|
|
92
|
-
const
|
|
176
|
+
const useColors = this.shouldUseColors(snapshotArgs);
|
|
177
|
+
const textSnapshot = this.buildTextFromDOMNode(docResponse.root, url, title, useColors);
|
|
93
178
|
processedSnapshot = {
|
|
94
179
|
url,
|
|
95
180
|
title,
|
|
@@ -168,7 +253,8 @@ class TakeSnapshotHandler {
|
|
|
168
253
|
error: 'No documents found'
|
|
169
254
|
};
|
|
170
255
|
}
|
|
171
|
-
const
|
|
256
|
+
const useColors = this.shouldUseColors(args);
|
|
257
|
+
const textSnapshot = this.createTextSnapshot(doc, response.strings, useColors);
|
|
172
258
|
const result = {
|
|
173
259
|
url: doc.documentURL,
|
|
174
260
|
title: doc.title,
|
|
@@ -176,21 +262,21 @@ class TakeSnapshotHandler {
|
|
|
176
262
|
};
|
|
177
263
|
return result;
|
|
178
264
|
}
|
|
179
|
-
createTextSnapshot(doc, strings) {
|
|
265
|
+
createTextSnapshot(doc, strings, useColors = true) {
|
|
180
266
|
const nodes = doc.nodes;
|
|
181
267
|
if (!nodes.nodeName || !nodes.nodeType) {
|
|
182
268
|
return 'Empty document';
|
|
183
269
|
}
|
|
184
270
|
const nodeTree = this.buildNodeTree(doc, strings);
|
|
185
|
-
let output =
|
|
271
|
+
let output = this.colorPageTitle(doc.title || 'Untitled', useColors) + '\n';
|
|
186
272
|
const bodyNode = this.findBodyNode(nodeTree);
|
|
187
273
|
if (bodyNode) {
|
|
188
|
-
output += this.renderNodeAsText(bodyNode, 0);
|
|
274
|
+
output += this.renderNodeAsText(bodyNode, 0, false, [], useColors);
|
|
189
275
|
}
|
|
190
276
|
else {
|
|
191
277
|
for (const node of nodeTree) {
|
|
192
278
|
if (this.shouldIncludeNode(node)) {
|
|
193
|
-
output += this.renderNodeAsText(node, 0);
|
|
279
|
+
output += this.renderNodeAsText(node, 0, false, [], useColors);
|
|
194
280
|
}
|
|
195
281
|
}
|
|
196
282
|
}
|
|
@@ -288,72 +374,78 @@ class TakeSnapshotHandler {
|
|
|
288
374
|
}
|
|
289
375
|
return true;
|
|
290
376
|
}
|
|
291
|
-
renderNodeAsText(node, depth, isLast = false, parentIsLast = []) {
|
|
377
|
+
renderNodeAsText(node, depth, isLast = false, parentIsLast = [], useColors = true) {
|
|
292
378
|
if (!this.shouldIncludeNode(node)) {
|
|
293
379
|
return '';
|
|
294
380
|
}
|
|
295
381
|
let indent = '';
|
|
296
382
|
for (let i = 0; i < parentIsLast.length; i++) {
|
|
297
|
-
|
|
383
|
+
const symbol = parentIsLast[i] ? ' ' : '│ ';
|
|
384
|
+
indent += this.colorTreeSymbol(symbol, useColors);
|
|
298
385
|
}
|
|
299
|
-
const
|
|
386
|
+
const prefixSymbol = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
|
|
387
|
+
const prefix = this.colorTreeSymbol(prefixSymbol, useColors);
|
|
300
388
|
let output = '';
|
|
301
389
|
if (node.nodeType === 3) {
|
|
302
390
|
if (node.textContent) {
|
|
303
391
|
const truncatedText = this.truncateText(node.textContent.trim(), 40);
|
|
304
|
-
output += `${indent}${prefix}
|
|
392
|
+
output += `${indent}${prefix}${this.colorText(truncatedText, useColors)}\n`;
|
|
305
393
|
}
|
|
306
394
|
}
|
|
307
395
|
else if (node.nodeType === 1) {
|
|
308
|
-
const tag = node.nodeName
|
|
396
|
+
const tag = this.colorTag(node.nodeName, useColors);
|
|
309
397
|
let description = tag;
|
|
310
398
|
const attrs = [];
|
|
311
|
-
if (node.attributes.id)
|
|
312
|
-
attrs.push(
|
|
399
|
+
if (node.attributes.id) {
|
|
400
|
+
attrs.push(this.colorId(node.attributes.id, useColors));
|
|
401
|
+
}
|
|
313
402
|
if (node.attributes.class) {
|
|
314
403
|
const classes = node.attributes.class.split(/\s+/).filter((c) => c.trim().length > 0);
|
|
315
404
|
classes.forEach((cls) => {
|
|
316
|
-
attrs.push(
|
|
405
|
+
attrs.push(this.colorClass(cls.trim(), useColors));
|
|
317
406
|
});
|
|
318
407
|
}
|
|
319
|
-
if (node.attributes.type)
|
|
320
|
-
attrs.push(
|
|
321
|
-
|
|
322
|
-
|
|
408
|
+
if (node.attributes.type) {
|
|
409
|
+
attrs.push(this.colorAttribute('type', node.attributes.type, useColors));
|
|
410
|
+
}
|
|
411
|
+
if (node.attributes.name) {
|
|
412
|
+
attrs.push(this.colorAttribute('name', node.attributes.name, useColors));
|
|
413
|
+
}
|
|
323
414
|
if (attrs.length > 0) {
|
|
324
415
|
description += `(${attrs.join(' ')})`;
|
|
325
416
|
}
|
|
326
417
|
if (node.nodeName === 'img' && node.attributes.alt) {
|
|
327
418
|
const altText = this.truncateText(node.attributes.alt, 40);
|
|
328
|
-
description += `:
|
|
419
|
+
description += `: ${this.colorText(altText, useColors)}`;
|
|
329
420
|
}
|
|
330
421
|
else if (node.nodeName === 'a' && node.attributes.href) {
|
|
331
|
-
description += `:
|
|
422
|
+
description += `: ${this.colorUrl(node.attributes.href, useColors)}`;
|
|
332
423
|
}
|
|
333
424
|
else if (['input', 'textarea'].includes(node.nodeName)) {
|
|
334
425
|
if (node.attributes.placeholder) {
|
|
335
426
|
const placeholderText = this.truncateText(node.attributes.placeholder, 40);
|
|
336
|
-
description += `:
|
|
427
|
+
description += `: ${this.colorText(placeholderText, useColors)}`;
|
|
337
428
|
}
|
|
338
429
|
else if (node.inputValue) {
|
|
339
430
|
const inputText = this.truncateText(node.inputValue, 40);
|
|
340
|
-
description += `:
|
|
431
|
+
description += `: ${this.colorText(inputText, useColors)}`;
|
|
341
432
|
}
|
|
342
433
|
else if (node.nodeName === 'textarea') {
|
|
343
434
|
const textContent = this.extractTextContent(node);
|
|
344
435
|
if (textContent) {
|
|
345
436
|
const truncatedText = this.truncateText(textContent, 40);
|
|
346
|
-
description += `:
|
|
437
|
+
description += `: ${this.colorText(truncatedText, useColors)}`;
|
|
347
438
|
}
|
|
348
439
|
}
|
|
349
|
-
if (node.checked)
|
|
350
|
-
description += '
|
|
440
|
+
if (node.checked) {
|
|
441
|
+
description += ` ${this.colorSpecial('[checked]', useColors)}`;
|
|
442
|
+
}
|
|
351
443
|
}
|
|
352
444
|
else if (node.nodeName === 'button' || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.nodeName)) {
|
|
353
445
|
const textContent = this.extractTextContent(node);
|
|
354
446
|
if (textContent) {
|
|
355
447
|
const truncatedText = this.truncateText(textContent, 40);
|
|
356
|
-
description += `:
|
|
448
|
+
description += `: ${this.colorText(truncatedText, useColors)}`;
|
|
357
449
|
}
|
|
358
450
|
}
|
|
359
451
|
output += `${indent}${prefix}${description}\n`;
|
|
@@ -365,7 +457,8 @@ class TakeSnapshotHandler {
|
|
|
365
457
|
const textContent = this.extractTextContent(node);
|
|
366
458
|
if (textContent && textContent.trim().length > 0) {
|
|
367
459
|
const truncatedText = this.truncateText(textContent.trim(), 40);
|
|
368
|
-
|
|
460
|
+
const treeSymbol = this.colorTreeSymbol('│ └── ', useColors);
|
|
461
|
+
output += `${indent}${treeSymbol}${this.colorText(truncatedText, useColors)}\n`;
|
|
369
462
|
return output;
|
|
370
463
|
}
|
|
371
464
|
return output;
|
|
@@ -375,7 +468,7 @@ class TakeSnapshotHandler {
|
|
|
375
468
|
for (let i = 0; i < meaningfulChildren.length; i++) {
|
|
376
469
|
const child = meaningfulChildren[i];
|
|
377
470
|
const childIsLast = i === meaningfulChildren.length - 1;
|
|
378
|
-
output += this.renderNodeAsText(child, depth + 1, childIsLast, newParentIsLast);
|
|
471
|
+
output += this.renderNodeAsText(child, depth + 1, childIsLast, newParentIsLast, useColors);
|
|
379
472
|
}
|
|
380
473
|
}
|
|
381
474
|
}
|
|
@@ -401,17 +494,17 @@ class TakeSnapshotHandler {
|
|
|
401
494
|
return text;
|
|
402
495
|
return text.substring(0, maxLength) + '...';
|
|
403
496
|
}
|
|
404
|
-
buildTextFromDOMNode(root, _url, title) {
|
|
405
|
-
let output =
|
|
497
|
+
buildTextFromDOMNode(root, _url, title, useColors = true) {
|
|
498
|
+
let output = this.colorPageTitle(title || 'Untitled', useColors) + '\n';
|
|
406
499
|
const bodyNode = this.findBodyInDOMTree(root);
|
|
407
500
|
if (bodyNode) {
|
|
408
|
-
output += this.renderDOMNodeAsText(bodyNode, 0);
|
|
501
|
+
output += this.renderDOMNodeAsText(bodyNode, 0, false, [], useColors);
|
|
409
502
|
}
|
|
410
503
|
else {
|
|
411
504
|
if (root.children) {
|
|
412
505
|
for (const child of root.children) {
|
|
413
506
|
if (this.shouldIncludeDOMNode(child)) {
|
|
414
|
-
output += this.renderDOMNodeAsText(child, 0);
|
|
507
|
+
output += this.renderDOMNodeAsText(child, 0, false, [], useColors);
|
|
415
508
|
}
|
|
416
509
|
}
|
|
417
510
|
}
|
|
@@ -448,25 +541,28 @@ class TakeSnapshotHandler {
|
|
|
448
541
|
}
|
|
449
542
|
return true;
|
|
450
543
|
}
|
|
451
|
-
renderDOMNodeAsText(node, depth, isLast = false, parentIsLast = []) {
|
|
544
|
+
renderDOMNodeAsText(node, depth, isLast = false, parentIsLast = [], useColors = true) {
|
|
452
545
|
if (!this.shouldIncludeDOMNode(node)) {
|
|
453
546
|
return '';
|
|
454
547
|
}
|
|
455
548
|
let indent = '';
|
|
456
549
|
for (let i = 0; i < parentIsLast.length; i++) {
|
|
457
|
-
|
|
550
|
+
const symbol = parentIsLast[i] ? ' ' : '│ ';
|
|
551
|
+
indent += this.colorTreeSymbol(symbol, useColors);
|
|
458
552
|
}
|
|
459
|
-
const
|
|
553
|
+
const prefixSymbol = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
|
|
554
|
+
const prefix = this.colorTreeSymbol(prefixSymbol, useColors);
|
|
460
555
|
let output = '';
|
|
461
556
|
if (node.nodeType === 3) {
|
|
462
557
|
const text = (node.nodeValue || '').trim();
|
|
463
558
|
if (text) {
|
|
464
559
|
const truncatedText = this.truncateText(text, 40);
|
|
465
|
-
output += `${indent}${prefix}
|
|
560
|
+
output += `${indent}${prefix}${this.colorText(truncatedText, useColors)}\n`;
|
|
466
561
|
}
|
|
467
562
|
}
|
|
468
563
|
else if (node.nodeType === 1) {
|
|
469
|
-
const
|
|
564
|
+
const nodeName = (node.nodeName || '').toLowerCase();
|
|
565
|
+
const tag = this.colorTag(nodeName, useColors);
|
|
470
566
|
let description = tag;
|
|
471
567
|
const attrs = [];
|
|
472
568
|
if (node.attributes) {
|
|
@@ -474,36 +570,38 @@ class TakeSnapshotHandler {
|
|
|
474
570
|
const name = node.attributes[i];
|
|
475
571
|
const value = node.attributes[i + 1];
|
|
476
572
|
if (['id', 'class', 'type', 'name', 'href', 'src', 'alt', 'placeholder', 'value', 'title'].includes(name)) {
|
|
477
|
-
if (name === 'id')
|
|
478
|
-
attrs.push(
|
|
573
|
+
if (name === 'id') {
|
|
574
|
+
attrs.push(this.colorId(value, useColors));
|
|
575
|
+
}
|
|
479
576
|
else if (name === 'class') {
|
|
480
577
|
const classes = value.split(/\s+/).filter((c) => c.trim().length > 0);
|
|
481
578
|
classes.forEach((cls) => {
|
|
482
|
-
attrs.push(
|
|
579
|
+
attrs.push(this.colorClass(cls.trim(), useColors));
|
|
483
580
|
});
|
|
484
581
|
}
|
|
485
|
-
else if (name === 'type')
|
|
486
|
-
attrs.push(
|
|
487
|
-
|
|
488
|
-
|
|
582
|
+
else if (name === 'type') {
|
|
583
|
+
attrs.push(this.colorAttribute('type', value, useColors));
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
attrs.push(this.colorAttribute(name, value, useColors));
|
|
587
|
+
}
|
|
489
588
|
}
|
|
490
589
|
}
|
|
491
590
|
}
|
|
492
591
|
if (attrs.length > 0) {
|
|
493
592
|
description += `(${attrs.join(' ')})`;
|
|
494
593
|
}
|
|
495
|
-
const nodeName = (node.nodeName || '').toLowerCase();
|
|
496
594
|
if (nodeName === 'img' && node.attributes) {
|
|
497
595
|
const altIndex = node.attributes.indexOf('alt');
|
|
498
596
|
if (altIndex >= 0 && altIndex + 1 < node.attributes.length) {
|
|
499
597
|
const altText = this.truncateText(node.attributes[altIndex + 1], 40);
|
|
500
|
-
description += `:
|
|
598
|
+
description += `: ${this.colorText(altText, useColors)}`;
|
|
501
599
|
}
|
|
502
600
|
}
|
|
503
601
|
else if (nodeName === 'a' && node.attributes) {
|
|
504
602
|
const hrefIndex = node.attributes.indexOf('href');
|
|
505
603
|
if (hrefIndex >= 0 && hrefIndex + 1 < node.attributes.length) {
|
|
506
|
-
description += `:
|
|
604
|
+
description += `: ${this.colorUrl(node.attributes[hrefIndex + 1], useColors)}`;
|
|
507
605
|
}
|
|
508
606
|
}
|
|
509
607
|
else if (['input', 'textarea'].includes(nodeName)) {
|
|
@@ -511,14 +609,14 @@ class TakeSnapshotHandler {
|
|
|
511
609
|
const placeholderIndex = node.attributes.indexOf('placeholder');
|
|
512
610
|
if (placeholderIndex >= 0 && placeholderIndex + 1 < node.attributes.length) {
|
|
513
611
|
const placeholderText = this.truncateText(node.attributes[placeholderIndex + 1], 40);
|
|
514
|
-
description += `:
|
|
612
|
+
description += `: ${this.colorText(placeholderText, useColors)}`;
|
|
515
613
|
}
|
|
516
614
|
}
|
|
517
615
|
if (nodeName === 'textarea') {
|
|
518
616
|
const textContent = this.extractTextFromDOMNode(node);
|
|
519
617
|
if (textContent) {
|
|
520
618
|
const truncatedText = this.truncateText(textContent, 40);
|
|
521
|
-
description += `:
|
|
619
|
+
description += `: ${this.colorText(truncatedText, useColors)}`;
|
|
522
620
|
}
|
|
523
621
|
}
|
|
524
622
|
}
|
|
@@ -526,7 +624,7 @@ class TakeSnapshotHandler {
|
|
|
526
624
|
const textContent = this.extractTextFromDOMNode(node);
|
|
527
625
|
if (textContent) {
|
|
528
626
|
const truncatedText = this.truncateText(textContent, 40);
|
|
529
|
-
description += `:
|
|
627
|
+
description += `: ${this.colorText(truncatedText, useColors)}`;
|
|
530
628
|
}
|
|
531
629
|
}
|
|
532
630
|
output += `${indent}${prefix}${description}\n`;
|
|
@@ -539,7 +637,8 @@ class TakeSnapshotHandler {
|
|
|
539
637
|
const textContent = this.extractTextFromDOMNode(node);
|
|
540
638
|
if (textContent && textContent.trim().length > 0) {
|
|
541
639
|
const truncatedText = this.truncateText(textContent.trim(), 40);
|
|
542
|
-
|
|
640
|
+
const treeSymbol = this.colorTreeSymbol('│ └── ', useColors);
|
|
641
|
+
output += `${indent}${treeSymbol}${this.colorText(truncatedText, useColors)}\n`;
|
|
543
642
|
return output;
|
|
544
643
|
}
|
|
545
644
|
return output;
|
|
@@ -549,7 +648,7 @@ class TakeSnapshotHandler {
|
|
|
549
648
|
for (let i = 0; i < meaningfulChildren.length; i++) {
|
|
550
649
|
const child = meaningfulChildren[i];
|
|
551
650
|
const childIsLast = i === meaningfulChildren.length - 1;
|
|
552
|
-
output += this.renderDOMNodeAsText(child, depth + 1, childIsLast, newParentIsLast);
|
|
651
|
+
output += this.renderDOMNodeAsText(child, depth + 1, childIsLast, newParentIsLast, useColors);
|
|
553
652
|
}
|
|
554
653
|
}
|
|
555
654
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-cdp-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
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",
|