@dyyz1993/agent-browser 0.11.5 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/bin/agent-browser-linux-x64 +0 -0
  2. package/dist/__tests__/utils/parseCli.d.ts.map +1 -1
  3. package/dist/__tests__/utils/parseCli.js +97 -2
  4. package/dist/__tests__/utils/parseCli.js.map +1 -1
  5. package/dist/actions.d.ts +2 -1
  6. package/dist/actions.d.ts.map +1 -1
  7. package/dist/actions.js +254 -105
  8. package/dist/actions.js.map +1 -1
  9. package/dist/browser.d.ts +41 -0
  10. package/dist/browser.d.ts.map +1 -1
  11. package/dist/browser.js +125 -30
  12. package/dist/browser.js.map +1 -1
  13. package/dist/cli/commands.d.ts.map +1 -1
  14. package/dist/cli/commands.js +129 -5
  15. package/dist/cli/commands.js.map +1 -1
  16. package/dist/cli/connection.d.ts.map +1 -1
  17. package/dist/cli/connection.js +12 -29
  18. package/dist/cli/connection.js.map +1 -1
  19. package/dist/cli/help.d.ts.map +1 -1
  20. package/dist/cli/help.js +35 -25
  21. package/dist/cli/help.js.map +1 -1
  22. package/dist/cli/output.d.ts.map +1 -1
  23. package/dist/cli/output.js +27 -0
  24. package/dist/cli/output.js.map +1 -1
  25. package/dist/cli.js +117 -3
  26. package/dist/cli.js.map +1 -1
  27. package/dist/daemon.d.ts +18 -2
  28. package/dist/daemon.d.ts.map +1 -1
  29. package/dist/daemon.js +71 -33
  30. package/dist/daemon.js.map +1 -1
  31. package/dist/message-bridge.d.ts.map +1 -1
  32. package/dist/message-bridge.js +4 -1
  33. package/dist/message-bridge.js.map +1 -1
  34. package/dist/protocol.d.ts.map +1 -1
  35. package/dist/protocol.js +18 -0
  36. package/dist/protocol.js.map +1 -1
  37. package/dist/rc-config.d.ts +42 -0
  38. package/dist/rc-config.d.ts.map +1 -0
  39. package/dist/rc-config.js +171 -0
  40. package/dist/rc-config.js.map +1 -0
  41. package/dist/recorder/inject.js +30 -24
  42. package/dist/types.d.ts +16 -1
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/package.json +2 -1
  46. package/scripts/generate-skill.cjs +303 -0
  47. package/skills/agent-browser/SKILL.md +135 -370
package/dist/browser.js CHANGED
@@ -26,6 +26,9 @@ export class BrowserManager {
26
26
  trackedRequests = [];
27
27
  isRequestTrackingEnabled = false;
28
28
  isResponseCaptureEnabled = false;
29
+ get trackingEnabled() {
30
+ return this.isRequestTrackingEnabled;
31
+ }
29
32
  // Map to track requests for response matching (instance variable for cross-listener access)
30
33
  pendingRequests = new Map();
31
34
  // Store request listener references for proper cleanup
@@ -34,10 +37,17 @@ export class BrowserManager {
34
37
  routes = new Map();
35
38
  consoleMessages = [];
36
39
  pageErrors = [];
40
+ trackedWebSockets = [];
41
+ isWebSocketTrackingEnabled = false;
42
+ wsListener = null;
43
+ get wsTrackingEnabled() {
44
+ return this.isWebSocketTrackingEnabled;
45
+ }
37
46
  isRecordingHar = false;
38
47
  refMap = {};
39
48
  lastSnapshot = '';
40
49
  scopedHeaderRoutes = new Map();
50
+ commandHistory = [];
41
51
  // CDP session for screencast and input injection
42
52
  cdpSession = null;
43
53
  screencastActive = false;
@@ -91,6 +101,19 @@ export class BrowserManager {
91
101
  getRefMap() {
92
102
  return this.refMap;
93
103
  }
104
+ recordCommand(action, selector, value, success) {
105
+ this.commandHistory.push({ action, selector, value, success, timestamp: Date.now() });
106
+ }
107
+ getHistory(filter) {
108
+ let history = this.commandHistory;
109
+ if (filter) {
110
+ history = history.filter((h) => h.selector.includes(filter) || h.action.includes(filter));
111
+ }
112
+ return history;
113
+ }
114
+ clearHistory() {
115
+ this.commandHistory = [];
116
+ }
94
117
  /**
95
118
  * Get a locator from a ref (e.g., "e1", "@e1", "ref=e1")
96
119
  * Returns null if ref doesn't exist or is invalid
@@ -191,9 +214,12 @@ export class BrowserManager {
191
214
  name: f.name(),
192
215
  url: f.url(),
193
216
  }));
217
+ const suggestion = childFrames.length > 0
218
+ ? ` Use 'agent-browser frames' to list all iframes, or try: ${childFrames.map((f, idx) => `--in-frame "${idx}"`).join(', ')}`
219
+ : '';
194
220
  throw new Error(`Frame not found for selector "${selector}" at path position ${i + 1}. ` +
195
221
  `Path: "${framePath}". ` +
196
- `Available child frames: ${JSON.stringify(availableInfo, null, 2)}`);
222
+ `Available child frames: ${JSON.stringify(availableInfo, null, 2)}.${suggestion}`);
197
223
  }
198
224
  current = matchedFrame;
199
225
  }
@@ -228,6 +254,23 @@ export class BrowserManager {
228
254
  return urlPathMatch;
229
255
  return undefined;
230
256
  }
257
+ listFrames() {
258
+ const page = this.getPage();
259
+ const result = [];
260
+ const walk = (frame, pathSoFar) => {
261
+ const children = frame.childFrames();
262
+ for (let i = 0; i < children.length; i++) {
263
+ const child = children[i];
264
+ const name = child.name() || '';
265
+ const segment = name || String(i);
266
+ const childPath = pathSoFar ? `${pathSoFar}/${segment}` : segment;
267
+ result.push({ name, url: child.url(), path: childPath });
268
+ walk(child, childPath);
269
+ }
270
+ };
271
+ walk(page.mainFrame(), '');
272
+ return result;
273
+ }
231
274
  /**
232
275
  * Set up dialog handler
233
276
  */
@@ -364,6 +407,57 @@ export class BrowserManager {
364
407
  clearRequests() {
365
408
  this.trackedRequests = [];
366
409
  }
410
+ startWebSocketTracking() {
411
+ const page = this.getPage();
412
+ if (this.isWebSocketTrackingEnabled)
413
+ return;
414
+ this.isWebSocketTrackingEnabled = true;
415
+ this.wsListener = (ws) => {
416
+ const id = `ws_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
417
+ const tracked = {
418
+ id,
419
+ url: ws.url(),
420
+ openedAt: Date.now(),
421
+ frames: [],
422
+ };
423
+ this.trackedWebSockets.push(tracked);
424
+ ws.on('framesent', (frame) => {
425
+ tracked.frames.push({
426
+ direction: 'send',
427
+ data: typeof frame.payload === 'string'
428
+ ? frame.payload
429
+ : `[binary ${frame.payload.byteLength}B]`,
430
+ timestamp: Date.now(),
431
+ });
432
+ });
433
+ ws.on('framereceived', (frame) => {
434
+ tracked.frames.push({
435
+ direction: 'recv',
436
+ data: typeof frame.payload === 'string'
437
+ ? frame.payload
438
+ : `[binary ${frame.payload.byteLength}B]`,
439
+ timestamp: Date.now(),
440
+ });
441
+ });
442
+ ws.on('socketerror', (err) => {
443
+ tracked.error = err;
444
+ });
445
+ ws.on('close', () => {
446
+ tracked.closedAt = Date.now();
447
+ });
448
+ };
449
+ page.on('websocket', this.wsListener);
450
+ }
451
+ getWebSockets(filter) {
452
+ let sockets = this.trackedWebSockets;
453
+ if (filter) {
454
+ sockets = sockets.filter((ws) => ws.url.includes(filter));
455
+ }
456
+ return sockets;
457
+ }
458
+ clearWebSockets() {
459
+ this.trackedWebSockets = [];
460
+ }
367
461
  /**
368
462
  * Save tracked requests to a directory
369
463
  * @param outputDir - Directory path to save requests
@@ -748,24 +842,16 @@ export class BrowserManager {
748
842
  * by verifying we can access browser contexts and that at least one has pages
749
843
  */
750
844
  isCdpConnectionAlive() {
751
- console.log('[DEBUG isCdpConnectionAlive] browser exists:', !!this.browser);
752
845
  if (!this.browser)
753
846
  return false;
754
847
  try {
755
848
  const contexts = this.browser.contexts();
756
- console.log('[DEBUG isCdpConnectionAlive] contexts count:', contexts.length);
757
849
  if (contexts.length === 0) {
758
- console.log('[DEBUG isCdpConnectionAlive] returning false: no contexts');
759
850
  return false;
760
851
  }
761
- const pagesPerContext = contexts.map((context) => context.pages().length);
762
- console.log('[DEBUG isCdpConnectionAlive] pages per context:', pagesPerContext);
763
- const hasPages = contexts.some((context) => context.pages().length > 0);
764
- console.log('[DEBUG isCdpConnectionAlive] hasPages:', hasPages);
765
- return hasPages;
852
+ return contexts.some((context) => context.pages().length > 0);
766
853
  }
767
- catch (e) {
768
- console.log('[DEBUG isCdpConnectionAlive] exception:', e);
854
+ catch (_e) {
769
855
  return false;
770
856
  }
771
857
  }
@@ -773,25 +859,15 @@ export class BrowserManager {
773
859
  * Check if CDP connection needs to be re-established
774
860
  */
775
861
  needsCdpReconnect(cdpEndpoint) {
776
- const isConnected = this.browser?.isConnected();
777
- const endpointMatch = this.cdpEndpoint === cdpEndpoint;
778
- const isAlive = this.isCdpConnectionAlive();
779
- console.log('[DEBUG needsCdpReconnect] isConnected:', isConnected);
780
- console.log('[DEBUG needsCdpReconnect] endpointMatch:', endpointMatch, '(this:', this.cdpEndpoint, 'vs param:', cdpEndpoint, ')');
781
- console.log('[DEBUG needsCdpReconnect] isCdpConnectionAlive:', isAlive);
782
- if (!isConnected) {
783
- console.log('[DEBUG needsCdpReconnect] returning true: not connected');
862
+ if (!this.browser?.isConnected()) {
784
863
  return true;
785
864
  }
786
- if (!endpointMatch) {
787
- console.log('[DEBUG needsCdpReconnect] returning true: endpoint mismatch');
865
+ if (this.cdpEndpoint !== cdpEndpoint) {
788
866
  return true;
789
867
  }
790
- if (!isAlive) {
791
- console.log('[DEBUG needsCdpReconnect] returning true: not alive');
868
+ if (!this.isCdpConnectionAlive()) {
792
869
  return true;
793
870
  }
794
- console.log('[DEBUG needsCdpReconnect] returning false: all checks passed');
795
871
  return false;
796
872
  }
797
873
  /**
@@ -1259,8 +1335,6 @@ export class BrowserManager {
1259
1335
  context.setDefaultTimeout(60000);
1260
1336
  this.contexts.push(context);
1261
1337
  this.setupContextTracking(context);
1262
- // Set up context tracking to catch window.open() popups
1263
- this.setupContextTracking(context);
1264
1338
  const page = context.pages()[0] ?? (await context.newPage());
1265
1339
  // Only add if not already tracked (setupContextTracking may have already added it via 'page' event)
1266
1340
  if (!this.pages.includes(page)) {
@@ -1434,8 +1508,6 @@ export class BrowserManager {
1434
1508
  this.setupPageTracking(page);
1435
1509
  }
1436
1510
  this.activePageIndex = this.pages.length - 1;
1437
- // Set up tracking for the new page
1438
- this.setupPageTracking(page);
1439
1511
  // Trigger tab created event callback
1440
1512
  const callbacks = getEventCallbacks();
1441
1513
  if (callbacks.onTabCreated) {
@@ -1468,8 +1540,6 @@ export class BrowserManager {
1468
1540
  this.setupPageTracking(page);
1469
1541
  }
1470
1542
  this.activePageIndex = this.pages.length - 1;
1471
- // Set up tracking for the new page
1472
- this.setupPageTracking(page);
1473
1543
  // Trigger tab created event callback
1474
1544
  const callbacks = getEventCallbacks();
1475
1545
  if (callbacks.onTabCreated) {
@@ -2705,6 +2775,22 @@ export class BrowserManager {
2705
2775
  return `agent-browser click "xpath=${escapeShell(step.xpath)}"`;
2706
2776
  }
2707
2777
  return null;
2778
+ case 'check':
2779
+ if (step.selector) {
2780
+ return `agent-browser check "${escapeShell(step.selector)}"`;
2781
+ }
2782
+ if (step.xpath) {
2783
+ return `agent-browser check "xpath=${escapeShell(step.xpath)}"`;
2784
+ }
2785
+ return null;
2786
+ case 'uncheck':
2787
+ if (step.selector) {
2788
+ return `agent-browser uncheck "${escapeShell(step.selector)}"`;
2789
+ }
2790
+ if (step.xpath) {
2791
+ return `agent-browser uncheck "xpath=${escapeShell(step.xpath)}"`;
2792
+ }
2793
+ return null;
2708
2794
  case 'fill':
2709
2795
  if (step.value !== undefined) {
2710
2796
  if (step.selector) {
@@ -2845,6 +2931,15 @@ export class BrowserManager {
2845
2931
  this.pendingRequests.clear();
2846
2932
  this.isRequestTrackingEnabled = false;
2847
2933
  this.isResponseCaptureEnabled = false;
2934
+ if (this.wsListener) {
2935
+ try {
2936
+ page?.off('websocket', this.wsListener);
2937
+ }
2938
+ catch { }
2939
+ this.wsListener = null;
2940
+ }
2941
+ this.isWebSocketTrackingEnabled = false;
2942
+ this.trackedWebSockets = [];
2848
2943
  this.routes.clear();
2849
2944
  this.consoleMessages = [];
2850
2945
  this.pageErrors = [];