browser-pilot 0.0.13 → 0.0.15

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.
@@ -1,6 +1,7 @@
1
1
  import {
2
- createCDPClient
3
- } from "./chunk-HP6R3W32.mjs";
2
+ createCDPClient,
3
+ stringifyUnknown
4
+ } from "./chunk-BVZALQT4.mjs";
4
5
  import {
5
6
  createProvider
6
7
  } from "./chunk-BRAFQUMG.mjs";
@@ -11,7 +12,7 @@ import {
11
12
  TimeoutError,
12
13
  ensureActionable,
13
14
  generateHints
14
- } from "./chunk-A2ZRAEO3.mjs";
15
+ } from "./chunk-7YVCOL2W.mjs";
15
16
 
16
17
  // src/audio/encoding.ts
17
18
  function bufferToBase64(data) {
@@ -142,6 +143,10 @@ async function grantAudioPermissions(cdp, origin) {
142
143
  await cdp.send("Page.addScriptToEvaluateOnNewDocument", {
143
144
  source: PERMISSIONS_OVERRIDE_SCRIPT
144
145
  });
146
+ await cdp.send("Runtime.evaluate", {
147
+ expression: PERMISSIONS_OVERRIDE_SCRIPT,
148
+ awaitPromise: false
149
+ });
145
150
  }
146
151
  var PERMISSIONS_OVERRIDE_SCRIPT = `
147
152
  (function() {
@@ -2327,6 +2332,9 @@ var Page = class {
2327
2332
  brokenFrame = null;
2328
2333
  /** Last matched selector from findElement (for selectorUsed tracking) */
2329
2334
  _lastMatchedSelector;
2335
+ _lastActionCoordinates = null;
2336
+ _lastActionBoundingBox = null;
2337
+ _lastActionTargetMetadata = null;
2330
2338
  /** Last snapshot for stale ref recovery */
2331
2339
  lastSnapshot;
2332
2340
  /** Audio input controller (lazy-initialized) */
@@ -2358,6 +2366,76 @@ var Page = class {
2358
2366
  getLastMatchedSelector() {
2359
2367
  return this._lastMatchedSelector;
2360
2368
  }
2369
+ async getActionTargetMetadata(identifiers) {
2370
+ try {
2371
+ const objectId = identifiers.objectId ?? (identifiers.nodeId ? await this.resolveObjectId(identifiers.nodeId) : void 0);
2372
+ if (!objectId) return null;
2373
+ const response = await this.cdp.send("Runtime.callFunctionOn", {
2374
+ objectId,
2375
+ functionDeclaration: `function() {
2376
+ const tagName = this.tagName?.toLowerCase?.() || '';
2377
+ const inputType =
2378
+ tagName === 'input' && typeof this.type === 'string' ? this.type.toLowerCase() : '';
2379
+ const autocomplete =
2380
+ typeof this.autocomplete === 'string' ? this.autocomplete.toLowerCase() : '';
2381
+ return { tagName, inputType, autocomplete };
2382
+ }`,
2383
+ returnByValue: true
2384
+ });
2385
+ return response.result.value ?? null;
2386
+ } catch {
2387
+ return null;
2388
+ }
2389
+ }
2390
+ async getElementPosition(identifiers) {
2391
+ try {
2392
+ const { quads } = await this.cdp.send(
2393
+ "DOM.getContentQuads",
2394
+ identifiers
2395
+ );
2396
+ if (quads?.length > 0) {
2397
+ const q = quads[0];
2398
+ const minX = Math.min(q[0], q[2], q[4], q[6]);
2399
+ const maxX = Math.max(q[0], q[2], q[4], q[6]);
2400
+ const minY = Math.min(q[1], q[3], q[5], q[7]);
2401
+ const maxY = Math.max(q[1], q[3], q[5], q[7]);
2402
+ return {
2403
+ center: { x: (minX + maxX) / 2, y: (minY + maxY) / 2 },
2404
+ bbox: { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
2405
+ };
2406
+ }
2407
+ } catch {
2408
+ }
2409
+ if (identifiers.nodeId) {
2410
+ const box = await this.getBoxModel(identifiers.nodeId);
2411
+ if (box) {
2412
+ return {
2413
+ center: { x: box.content[0] + box.width / 2, y: box.content[1] + box.height / 2 },
2414
+ bbox: { x: box.content[0], y: box.content[1], width: box.width, height: box.height }
2415
+ };
2416
+ }
2417
+ }
2418
+ return null;
2419
+ }
2420
+ setLastActionPosition(coords, bbox) {
2421
+ this._lastActionCoordinates = coords;
2422
+ this._lastActionBoundingBox = bbox;
2423
+ }
2424
+ getLastActionCoordinates() {
2425
+ return this._lastActionCoordinates;
2426
+ }
2427
+ getLastActionBoundingBox() {
2428
+ return this._lastActionBoundingBox;
2429
+ }
2430
+ getLastActionTargetMetadata() {
2431
+ return this._lastActionTargetMetadata;
2432
+ }
2433
+ /** Reset position tracking (call before each executor step) */
2434
+ resetLastActionPosition() {
2435
+ this._lastActionCoordinates = null;
2436
+ this._lastActionBoundingBox = null;
2437
+ this._lastActionTargetMetadata = null;
2438
+ }
2361
2439
  /**
2362
2440
  * Initialize the page (enable required CDP domains)
2363
2441
  */
@@ -2525,6 +2603,14 @@ var Page = class {
2525
2603
  const quad = quads[0];
2526
2604
  clickX = (quad[0] + quad[2] + quad[4] + quad[6]) / 4;
2527
2605
  clickY = (quad[1] + quad[3] + quad[5] + quad[7]) / 4;
2606
+ const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
2607
+ const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
2608
+ const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
2609
+ const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
2610
+ this.setLastActionPosition(
2611
+ { x: clickX, y: clickY },
2612
+ { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
2613
+ );
2528
2614
  } else {
2529
2615
  throw new Error("No quads");
2530
2616
  }
@@ -2533,6 +2619,10 @@ var Page = class {
2533
2619
  if (!box) throw new Error("Could not get element position");
2534
2620
  clickX = box.content[0] + box.width / 2;
2535
2621
  clickY = box.content[1] + box.height / 2;
2622
+ this.setLastActionPosition(
2623
+ { x: clickX, y: clickY },
2624
+ { x: box.content[0], y: box.content[1], width: box.width, height: box.height }
2625
+ );
2536
2626
  }
2537
2627
  const hitTargetCoordinates = this.currentFrame ? void 0 : { x: clickX, y: clickY };
2538
2628
  const HIT_TARGET_RETRIES = 3;
@@ -2583,13 +2673,20 @@ var Page = class {
2583
2673
  if (options.optional) return false;
2584
2674
  throw e;
2585
2675
  }
2676
+ const fillPos = await this.getElementPosition({ nodeId: element.nodeId });
2677
+ if (fillPos) this.setLastActionPosition(fillPos.center, fillPos.bbox);
2586
2678
  const tagInfo = await this.cdp.send("Runtime.callFunctionOn", {
2587
2679
  objectId,
2588
2680
  functionDeclaration: `function() {
2589
- return { tagName: this.tagName?.toLowerCase() || '', inputType: (this.type || '').toLowerCase() };
2681
+ return {
2682
+ tagName: this.tagName?.toLowerCase() || '',
2683
+ inputType: (this.type || '').toLowerCase(),
2684
+ autocomplete: typeof this.autocomplete === 'string' ? this.autocomplete.toLowerCase() : '',
2685
+ };
2590
2686
  }`,
2591
2687
  returnByValue: true
2592
2688
  });
2689
+ this._lastActionTargetMetadata = tagInfo.result.value;
2593
2690
  const { tagName, inputType } = tagInfo.result.value;
2594
2691
  const specialInputTypes = /* @__PURE__ */ new Set([
2595
2692
  "date",
@@ -2671,6 +2768,9 @@ var Page = class {
2671
2768
  if (options.optional) return false;
2672
2769
  throw e;
2673
2770
  }
2771
+ const typePos = await this.getElementPosition({ nodeId: element.nodeId });
2772
+ if (typePos) this.setLastActionPosition(typePos.center, typePos.bbox);
2773
+ this._lastActionTargetMetadata = await this.getActionTargetMetadata({ objectId });
2674
2774
  await this.cdp.send("DOM.focus", { nodeId: element.nodeId });
2675
2775
  for (const char of text) {
2676
2776
  const def = US_KEYBOARD[char];
@@ -2750,6 +2850,9 @@ var Page = class {
2750
2850
  if (options.optional) return false;
2751
2851
  throw e;
2752
2852
  }
2853
+ const selectPos = await this.getElementPosition({ nodeId: element.nodeId });
2854
+ if (selectPos) this.setLastActionPosition(selectPos.center, selectPos.bbox);
2855
+ this._lastActionTargetMetadata = await this.getActionTargetMetadata({ objectId });
2753
2856
  const metadata = await this.getNativeSelectMetadata(objectId, values);
2754
2857
  if (!metadata.isSelect) {
2755
2858
  throw new Error("select() target must be a native <select> element");
@@ -2886,6 +2989,8 @@ var Page = class {
2886
2989
  if (options.optional) return false;
2887
2990
  throw e;
2888
2991
  }
2992
+ const checkPos = await this.getElementPosition({ nodeId: element.nodeId });
2993
+ if (checkPos) this.setLastActionPosition(checkPos.center, checkPos.bbox);
2889
2994
  const before = await this.cdp.send("Runtime.callFunctionOn", {
2890
2995
  objectId: object.objectId,
2891
2996
  functionDeclaration: "function() { return !!this.checked; }",
@@ -2934,6 +3039,8 @@ var Page = class {
2934
3039
  if (options.optional) return false;
2935
3040
  throw e;
2936
3041
  }
3042
+ const uncheckPos = await this.getElementPosition({ nodeId: element.nodeId });
3043
+ if (uncheckPos) this.setLastActionPosition(uncheckPos.center, uncheckPos.bbox);
2937
3044
  const isRadio = await this.cdp.send(
2938
3045
  "Runtime.callFunctionOn",
2939
3046
  {
@@ -2989,6 +3096,8 @@ var Page = class {
2989
3096
  throw new ElementNotFoundError(selector, hints);
2990
3097
  }
2991
3098
  const objectId = await this.resolveObjectId(element.nodeId);
3099
+ const submitPos = await this.getElementPosition({ nodeId: element.nodeId });
3100
+ if (submitPos) this.setLastActionPosition(submitPos.center, submitPos.bbox);
2992
3101
  const isFormElement = await this.cdp.send(
2993
3102
  "Runtime.callFunctionOn",
2994
3103
  {
@@ -3085,6 +3194,8 @@ var Page = class {
3085
3194
  const hints = await generateHints(this, selectorList, "focus");
3086
3195
  throw new ElementNotFoundError(selector, hints);
3087
3196
  }
3197
+ const focusPos = await this.getElementPosition({ nodeId: element.nodeId });
3198
+ if (focusPos) this.setLastActionPosition(focusPos.center, focusPos.bbox);
3088
3199
  await this.cdp.send("DOM.focus", { nodeId: element.nodeId });
3089
3200
  return true;
3090
3201
  }
@@ -3120,6 +3231,14 @@ var Page = class {
3120
3231
  const quad = quads[0];
3121
3232
  x = (quad[0] + quad[2] + quad[4] + quad[6]) / 4;
3122
3233
  y = (quad[1] + quad[3] + quad[5] + quad[7]) / 4;
3234
+ const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
3235
+ const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
3236
+ const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
3237
+ const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
3238
+ this.setLastActionPosition(
3239
+ { x, y },
3240
+ { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
3241
+ );
3123
3242
  } else {
3124
3243
  throw new Error("No quads");
3125
3244
  }
@@ -3131,6 +3250,10 @@ var Page = class {
3131
3250
  }
3132
3251
  x = box.content[0] + box.width / 2;
3133
3252
  y = box.content[1] + box.height / 2;
3253
+ this.setLastActionPosition(
3254
+ { x, y },
3255
+ { x: box.content[0], y: box.content[1], width: box.width, height: box.height }
3256
+ );
3134
3257
  }
3135
3258
  await this.cdp.send("Input.dispatchMouseEvent", {
3136
3259
  type: "mouseMoved",
@@ -3156,6 +3279,8 @@ var Page = class {
3156
3279
  if (options.optional) return false;
3157
3280
  throw new ElementNotFoundError(selector);
3158
3281
  }
3282
+ const scrollPos = await this.getElementPosition({ nodeId: element.nodeId });
3283
+ if (scrollPos) this.setLastActionPosition(scrollPos.center, scrollPos.bbox);
3159
3284
  await this.scrollIntoView(element.nodeId);
3160
3285
  return true;
3161
3286
  }
@@ -3917,7 +4042,7 @@ var Page = class {
3917
4042
  return {
3918
4043
  role,
3919
4044
  name,
3920
- value: value !== void 0 ? String(value) : void 0,
4045
+ value: value !== void 0 ? stringifyUnknown(value) : void 0,
3921
4046
  ref,
3922
4047
  children: children.length > 0 ? children : void 0,
3923
4048
  disabled,
@@ -3979,7 +4104,7 @@ var Page = class {
3979
4104
  selector,
3980
4105
  disabled,
3981
4106
  checked,
3982
- value: value !== void 0 ? String(value) : void 0
4107
+ value: value !== void 0 ? stringifyUnknown(value) : void 0
3983
4108
  });
3984
4109
  }
3985
4110
  }
@@ -4449,7 +4574,7 @@ var Page = class {
4449
4574
  */
4450
4575
  formatConsoleArgs(args) {
4451
4576
  return args.map((arg) => {
4452
- if (arg.value !== void 0) return String(arg.value);
4577
+ if (arg.value !== void 0) return stringifyUnknown(arg.value);
4453
4578
  if (arg.description) return arg.description;
4454
4579
  return "[object]";
4455
4580
  }).join(" ");
@@ -5238,6 +5363,25 @@ var Browser = class _Browser {
5238
5363
  this.cdp = cdp;
5239
5364
  this.providerSession = providerSession;
5240
5365
  }
5366
+ /**
5367
+ * Create a Browser from an existing CDPClient (used by daemon fast-path).
5368
+ * The caller is responsible for the CDP connection lifecycle.
5369
+ */
5370
+ static fromCDP(cdp, sessionInfo) {
5371
+ const providerSession = {
5372
+ wsUrl: sessionInfo.wsUrl,
5373
+ sessionId: sessionInfo.sessionId,
5374
+ async close() {
5375
+ }
5376
+ };
5377
+ const provider = {
5378
+ name: sessionInfo.provider ?? "daemon",
5379
+ async createSession() {
5380
+ return providerSession;
5381
+ }
5382
+ };
5383
+ return new _Browser(cdp, provider, providerSession, { provider: "generic" });
5384
+ }
5241
5385
  /**
5242
5386
  * Connect to a browser instance
5243
5387
  */