cdp-skill 1.0.19 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-skill",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "Browser automation skill using Chrome DevTools Protocol for Claude Code and AI agents",
5
5
  "type": "module",
6
6
  "main": "scripts/index.js",
@@ -96,8 +96,14 @@ export async function executeEval(pageController, params) {
96
96
  reject(new Error(`Eval timed out after ${evalTimeout}ms`));
97
97
  }, evalTimeout);
98
98
  });
99
- result = await Promise.race([evalPromise, timeoutPromise]);
100
- clearTimeout(evalTimeoutId);
99
+ try {
100
+ result = await Promise.race([evalPromise, timeoutPromise]);
101
+ } catch (err) {
102
+ evalPromise.catch(() => {}); // suppress dangling rejection if timeout won
103
+ throw err;
104
+ } finally {
105
+ clearTimeout(evalTimeoutId);
106
+ }
101
107
  } else {
102
108
  result = await evalPromise;
103
109
  }
@@ -119,7 +119,7 @@ export async function executeGetDom(pageController, params) {
119
119
  const expression = selector
120
120
  ? `(function() {
121
121
  const el = document.querySelector(${JSON.stringify(selector)});
122
- if (!el) return { error: 'Element not found: ${selector}' };
122
+ if (!el) return { error: 'Element not found: ' + ${JSON.stringify(selector)} };
123
123
  return {
124
124
  html: ${outer} ? el.outerHTML : el.innerHTML,
125
125
  tagName: el.tagName.toLowerCase(),
@@ -228,10 +228,11 @@ export async function executeGetBox(ariaSnapshot, params) {
228
228
  * @returns {Promise<Object>} Result with filled element info
229
229
  */
230
230
 
231
- export async function executeRefAt(session, params) {
231
+ export async function executeRefAt(pageController, params) {
232
+ const session = pageController.session;
232
233
  const { x, y } = params;
233
234
 
234
- const result = await session.send('Runtime.evaluate', {
235
+ const evalArgs = {
235
236
  expression: `(function() {
236
237
  const x = ${x};
237
238
  const y = ${y};
@@ -352,7 +353,10 @@ export async function executeRefAt(session, params) {
352
353
  };
353
354
  })()`,
354
355
  returnByValue: true
355
- });
356
+ };
357
+ const contextId = pageController.getFrameContext();
358
+ if (contextId) evalArgs.contextId = contextId;
359
+ const result = await session.send('Runtime.evaluate', evalArgs);
356
360
 
357
361
  if (result.exceptionDetails) {
358
362
  throw new Error(`refAt error: ${result.exceptionDetails.text}`);
@@ -370,8 +374,9 @@ export async function executeRefAt(session, params) {
370
374
  * Execute an elementsAt step - get refs for elements at multiple coordinates
371
375
  */
372
376
 
373
- export async function executeElementsAt(session, coords) {
374
- const result = await session.send('Runtime.evaluate', {
377
+ export async function executeElementsAt(pageController, coords) {
378
+ const session = pageController.session;
379
+ const evalArgs = {
375
380
  expression: `(function() {
376
381
  const coords = ${JSON.stringify(coords)};
377
382
 
@@ -499,7 +504,10 @@ export async function executeElementsAt(session, coords) {
499
504
  return { elements: results, count: results.filter(r => !r.error).length };
500
505
  })()`,
501
506
  returnByValue: true
502
- });
507
+ };
508
+ const contextId = pageController.getFrameContext();
509
+ if (contextId) evalArgs.contextId = contextId;
510
+ const result = await session.send('Runtime.evaluate', evalArgs);
503
511
 
504
512
  if (result.exceptionDetails) {
505
513
  throw new Error(`elementsAt error: ${result.exceptionDetails.text}`);
@@ -512,10 +520,11 @@ export async function executeElementsAt(session, coords) {
512
520
  * Execute an elementsNear step - get refs for all elements near a coordinate
513
521
  */
514
522
 
515
- export async function executeElementsNear(session, params) {
523
+ export async function executeElementsNear(pageController, params) {
524
+ const session = pageController.session;
516
525
  const { x, y, radius = 50, limit = 20 } = params;
517
526
 
518
- const result = await session.send('Runtime.evaluate', {
527
+ const evalArgs = {
519
528
  expression: `(function() {
520
529
  const centerX = ${x};
521
530
  const centerY = ${y};
@@ -665,7 +674,10 @@ export async function executeElementsNear(session, params) {
665
674
  };
666
675
  })()`,
667
676
  returnByValue: true
668
- });
677
+ };
678
+ const contextId = pageController.getFrameContext();
679
+ if (contextId) evalArgs.contextId = contextId;
680
+ const result = await session.send('Runtime.evaluate', evalArgs);
669
681
 
670
682
  if (result.exceptionDetails) {
671
683
  throw new Error(`elementsNear error: ${result.exceptionDetails.text}`);
@@ -829,10 +841,7 @@ export async function executeQueryAll(elementLocator, params) {
829
841
  const results = {};
830
842
 
831
843
  for (const [name, selectorOrConfig] of Object.entries(params)) {
832
- // Support both string selectors and query config objects
833
- const queryParams = typeof selectorOrConfig === 'string'
834
- ? selectorOrConfig
835
- : selectorOrConfig;
844
+ const queryParams = selectorOrConfig;
836
845
 
837
846
  try {
838
847
  results[name] = await executeQuery(elementLocator, queryParams);
@@ -457,13 +457,13 @@ export async function executeStep(deps, step, options = {}) {
457
457
  const eaParams = step.elementsAt;
458
458
  if (Array.isArray(eaParams)) {
459
459
  // Batch mode (array of coordinates)
460
- stepResult.output = await executeElementsAt(pageController.session, eaParams);
460
+ stepResult.output = await executeElementsAt(pageController, eaParams);
461
461
  } else if (eaParams && typeof eaParams === 'object' && eaParams.radius !== undefined) {
462
462
  // Nearby mode (has radius)
463
- stepResult.output = await executeElementsNear(pageController.session, eaParams);
463
+ stepResult.output = await executeElementsNear(pageController, eaParams);
464
464
  } else {
465
465
  // Single point mode (was refAt)
466
- stepResult.output = await executeRefAt(pageController.session, eaParams);
466
+ stepResult.output = await executeRefAt(pageController, eaParams);
467
467
  }
468
468
  } else if (step.pageFunction !== undefined) {
469
469
  stepResult.action = 'pageFunction';
@@ -576,7 +576,10 @@ export async function executeStep(deps, step, options = {}) {
576
576
 
577
577
  if (isOptional) {
578
578
  stepResult.status = 'skipped';
579
- stepResult.error = `${error.message} (timeout: ${stepTimeout}ms)`;
579
+ const isTimeout = error.code === 'TIMEOUT' || error.name === 'TimeoutError' || error.message?.includes('timed out');
580
+ stepResult.error = isTimeout
581
+ ? `${error.message} (timeout: ${stepTimeout}ms)`
582
+ : error.message;
580
583
  } else {
581
584
  stepResult.status = 'error';
582
585
  stepResult.error = error.message;
@@ -501,8 +501,8 @@ describe('executeGetBox', () => {
501
501
 
502
502
  describe('executeRefAt', () => {
503
503
  it('should get element ref at coordinates', async () => {
504
- const session = createMockPageController({ refAt: true }).session;
505
- const result = await executeRefAt(session, { x: 100, y: 200 });
504
+ const pageController = createMockPageController({ refAt: true });
505
+ const result = await executeRefAt(pageController, { x: 100, y: 200 });
506
506
 
507
507
  assert.strictEqual(result.ref, 'f0s1e1');
508
508
  assert.strictEqual(result.tag, 'BUTTON');
@@ -511,8 +511,8 @@ describe('executeRefAt', () => {
511
511
  });
512
512
 
513
513
  it('should return element info with box', async () => {
514
- const session = createMockPageController({ refAt: true }).session;
515
- const result = await executeRefAt(session, { x: 100, y: 200 });
514
+ const pageController = createMockPageController({ refAt: true });
515
+ const result = await executeRefAt(pageController, { x: 100, y: 200 });
516
516
 
517
517
  assert.ok(result.box);
518
518
  assert.strictEqual(result.box.x, 100);
@@ -522,17 +522,17 @@ describe('executeRefAt', () => {
522
522
  });
523
523
 
524
524
  it('should throw if no element at coordinates', async () => {
525
- const session = createMockPageController({ refAtNoElement: true }).session;
525
+ const pageController = createMockPageController({ refAtNoElement: true });
526
526
  await assert.rejects(
527
- async () => executeRefAt(session, { x: 999, y: 999 }),
527
+ async () => executeRefAt(pageController, { x: 999, y: 999 }),
528
528
  /No element at coordinates/
529
529
  );
530
530
  });
531
531
 
532
532
  it('should throw on evaluation error', async () => {
533
- const session = createMockPageController({ evalError: true }).session;
533
+ const pageController = createMockPageController({ evalError: true });
534
534
  await assert.rejects(
535
- async () => executeRefAt(session, { x: 100, y: 100 }),
535
+ async () => executeRefAt(pageController, { x: 100, y: 100 }),
536
536
  /Evaluation error/
537
537
  );
538
538
  });
@@ -544,12 +544,12 @@ describe('executeRefAt', () => {
544
544
 
545
545
  describe('executeElementsAt', () => {
546
546
  it('should get elements at multiple coordinates', async () => {
547
- const session = createMockPageController({ elementsAt: true }).session;
547
+ const pageController = createMockPageController({ elementsAt: true });
548
548
  const coords = [
549
549
  { x: 100, y: 100 },
550
550
  { x: 200, y: 200 }
551
551
  ];
552
- const result = await executeElementsAt(session, coords);
552
+ const result = await executeElementsAt(pageController, coords);
553
553
 
554
554
  assert.ok(result.results);
555
555
  assert.strictEqual(result.results.length, 2);
@@ -558,16 +558,16 @@ describe('executeElementsAt', () => {
558
558
  });
559
559
 
560
560
  it('should handle empty coordinates array', async () => {
561
- const session = createMockPageController({ elementsAt: true }).session;
562
- const result = await executeElementsAt(session, []);
561
+ const pageController = createMockPageController({ elementsAt: true });
562
+ const result = await executeElementsAt(pageController, []);
563
563
 
564
564
  assert.ok(result.results || Array.isArray(result));
565
565
  });
566
566
 
567
567
  it('should throw on evaluation error', async () => {
568
- const session = createMockPageController({ evalError: true }).session;
568
+ const pageController = createMockPageController({ evalError: true });
569
569
  await assert.rejects(
570
- async () => executeElementsAt(session, [{ x: 100, y: 100 }]),
570
+ async () => executeElementsAt(pageController, [{ x: 100, y: 100 }]),
571
571
  /Evaluation error/
572
572
  );
573
573
  });
@@ -579,9 +579,9 @@ describe('executeElementsAt', () => {
579
579
 
580
580
  describe('executeElementsNear', () => {
581
581
  it('should get elements near coordinates', async () => {
582
- const session = createMockPageController({ elementsNear: true }).session;
582
+ const pageController = createMockPageController({ elementsNear: true });
583
583
  const params = { x: 100, y: 100, radius: 50 };
584
- const result = await executeElementsNear(session, params);
584
+ const result = await executeElementsNear(pageController, params);
585
585
 
586
586
  assert.ok(result.elements);
587
587
  assert.strictEqual(result.elements.length, 2);
@@ -590,18 +590,18 @@ describe('executeElementsNear', () => {
590
590
  });
591
591
 
592
592
  it('should default radius to 100 if not provided', async () => {
593
- const session = createMockPageController({ elementsNear: true }).session;
593
+ const pageController = createMockPageController({ elementsNear: true });
594
594
  const params = { x: 100, y: 100 };
595
- const result = await executeElementsNear(session, params);
595
+ const result = await executeElementsNear(pageController, params);
596
596
 
597
597
  // Should still work with default radius
598
598
  assert.ok(result.elements || result.searchRadius);
599
599
  });
600
600
 
601
601
  it('should throw on evaluation error', async () => {
602
- const session = createMockPageController({ evalError: true }).session;
602
+ const pageController = createMockPageController({ evalError: true });
603
603
  await assert.rejects(
604
- async () => executeElementsNear(session, { x: 100, y: 100 }),
604
+ async () => executeElementsNear(pageController, { x: 100, y: 100 }),
605
605
  /Evaluation error/
606
606
  );
607
607
  });