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.json
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 get_console_message
194
- chrome-cdp-cli get_network_request
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.json
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 get_console_message
384
+ chrome-cdp-cli console --latest
380
385
 
381
386
  # List all console messages
382
- chrome-cdp-cli list_console_messages
387
+ chrome-cdp-cli console
383
388
 
384
389
  # Filter console messages by type
385
- chrome-cdp-cli list_console_messages --filter '{"types":["error","warn"]}'
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 get_network_request
414
+ chrome-cdp-cli network --latest
404
415
 
405
416
  # List all network requests
406
- chrome-cdp-cli list_network_requests
417
+ chrome-cdp-cli network
407
418
 
408
419
  # Filter network requests by method
409
- chrome-cdp-cli list_network_requests --filter '{"methods":["POST"],"statusCodes":[200,201]}'
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.json
907
+ chrome-cdp-cli snapshot --filename dom.txt
888
908
 
889
909
  # Monitoring
890
- chrome-cdp-cli get_console_message
891
- chrome-cdp-cli list_network_requests
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: []
@@ -141,7 +141,8 @@ class CDPClient {
141
141
  }
142
142
  }
143
143
  async discoverTargets(host, port) {
144
- const response = await (0, node_fetch_1.default)(`http://${host}:${port}/json/list`);
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 url = `http://${host}:${port}/json/list`;
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 textSnapshot = this.buildTextFromDOMNode(docResponse.root, url, title);
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 textSnapshot = this.createTextSnapshot(doc, response.strings);
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 = `PAGE: ${doc.title || 'Untitled'}\n`;
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
- indent += parentIsLast[i] ? ' ' : '│ ';
383
+ const symbol = parentIsLast[i] ? ' ' : '│ ';
384
+ indent += this.colorTreeSymbol(symbol, useColors);
298
385
  }
299
- const prefix = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
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}"${truncatedText}"\n`;
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.toUpperCase();
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(`#${node.attributes.id}`);
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(`.${cls.trim()}`);
405
+ attrs.push(this.colorClass(cls.trim(), useColors));
317
406
  });
318
407
  }
319
- if (node.attributes.type)
320
- attrs.push(`[${node.attributes.type}]`);
321
- if (node.attributes.name)
322
- attrs.push(`name="${node.attributes.name}"`);
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 += `: "${altText}"`;
419
+ description += `: ${this.colorText(altText, useColors)}`;
329
420
  }
330
421
  else if (node.nodeName === 'a' && node.attributes.href) {
331
- description += `: "${node.attributes.href}"`;
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 += `: "${placeholderText}"`;
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 += `: "${inputText}"`;
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 += `: "${truncatedText}"`;
437
+ description += `: ${this.colorText(truncatedText, useColors)}`;
347
438
  }
348
439
  }
349
- if (node.checked)
350
- description += ' [checked]';
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 += `: "${truncatedText}"`;
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
- output += `${indent}│ └── "${truncatedText}"\n`;
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 = `PAGE: ${title || 'Untitled'}\n`;
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
- indent += parentIsLast[i] ? ' ' : '│ ';
550
+ const symbol = parentIsLast[i] ? ' ' : '│ ';
551
+ indent += this.colorTreeSymbol(symbol, useColors);
458
552
  }
459
- const prefix = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
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}"${truncatedText}"\n`;
560
+ output += `${indent}${prefix}${this.colorText(truncatedText, useColors)}\n`;
466
561
  }
467
562
  }
468
563
  else if (node.nodeType === 1) {
469
- const tag = (node.nodeName || '').toUpperCase();
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(`#${value}`);
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(`.${cls.trim()}`);
579
+ attrs.push(this.colorClass(cls.trim(), useColors));
483
580
  });
484
581
  }
485
- else if (name === 'type')
486
- attrs.push(`[${value}]`);
487
- else
488
- attrs.push(`${name}="${value}"`);
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 += `: "${altText}"`;
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 += `: "${node.attributes[hrefIndex + 1]}"`;
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 += `: "${placeholderText}"`;
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 += `: "${truncatedText}"`;
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 += `: "${truncatedText}"`;
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
- output += `${indent}│ └── "${truncatedText}"\n`;
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.1",
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",