@canaryai/cli 0.2.6 → 0.2.8
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/dist/{chunk-PDC425CK.js → chunk-FK3EZADZ.js} +646 -212
- package/dist/chunk-FK3EZADZ.js.map +1 -0
- package/dist/{chunk-RYCPA32L.js → chunk-K2OB72B6.js} +2 -2
- package/dist/{chunk-AHYNXUHF.js → chunk-XAA5VQ5N.js} +1 -1
- package/dist/{chunk-AHYNXUHF.js.map → chunk-XAA5VQ5N.js.map} +1 -1
- package/dist/{debug-workflow-G5ZAZCYG.js → debug-workflow-55G4Y6YT.js} +4 -4
- package/dist/{docs-QLCF2LS6.js → docs-RPFT7ZJB.js} +2 -2
- package/dist/index.js +101 -8
- package/dist/index.js.map +1 -1
- package/dist/{local-browser-5ZVPHF5H.js → local-browser-X7J27IGS.js} +4 -4
- package/dist/{mcp-Q666YHHT.js → mcp-4JVLADZL.js} +4 -4
- package/dist/{record-W5QERB5Z.js → record-4OX7HXWQ.js} +4 -4
- package/dist/record-4OX7HXWQ.js.map +1 -0
- package/dist/{src-GSLFE4NP.js → src-I4EXB5OD.js} +5 -3
- package/package.json +2 -2
- package/dist/chunk-PDC425CK.js.map +0 -1
- package/dist/record-W5QERB5Z.js.map +0 -1
- /package/dist/{chunk-RYCPA32L.js.map → chunk-K2OB72B6.js.map} +0 -0
- /package/dist/{debug-workflow-G5ZAZCYG.js.map → debug-workflow-55G4Y6YT.js.map} +0 -0
- /package/dist/{docs-QLCF2LS6.js.map → docs-RPFT7ZJB.js.map} +0 -0
- /package/dist/{local-browser-5ZVPHF5H.js.map → local-browser-X7J27IGS.js.map} +0 -0
- /package/dist/{mcp-Q666YHHT.js.map → mcp-4JVLADZL.js.map} +0 -0
- /package/dist/{src-GSLFE4NP.js.map → src-I4EXB5OD.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
getCanaryTmpDir
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XAA5VQ5N.js";
|
|
5
5
|
import {
|
|
6
6
|
consoleLogger
|
|
7
7
|
} from "./chunk-P5Z2Y5VV.js";
|
|
@@ -119,7 +119,7 @@ var require_omggif = __commonJS({
|
|
|
119
119
|
var min_code_size = 0;
|
|
120
120
|
while (num_colors >>= 1) ++min_code_size;
|
|
121
121
|
num_colors = 1 << min_code_size;
|
|
122
|
-
var
|
|
122
|
+
var delay2 = opts.delay === void 0 ? 0 : opts.delay;
|
|
123
123
|
var disposal = opts.disposal === void 0 ? 0 : opts.disposal;
|
|
124
124
|
if (disposal < 0 || disposal > 3)
|
|
125
125
|
throw new Error("Disposal out of range.");
|
|
@@ -131,13 +131,13 @@ var require_omggif = __commonJS({
|
|
|
131
131
|
if (transparent_index < 0 || transparent_index >= num_colors)
|
|
132
132
|
throw new Error("Transparent color index.");
|
|
133
133
|
}
|
|
134
|
-
if (disposal !== 0 || use_transparency ||
|
|
134
|
+
if (disposal !== 0 || use_transparency || delay2 !== 0) {
|
|
135
135
|
buf[p++] = 33;
|
|
136
136
|
buf[p++] = 249;
|
|
137
137
|
buf[p++] = 4;
|
|
138
138
|
buf[p++] = disposal << 2 | (use_transparency === true ? 1 : 0);
|
|
139
|
-
buf[p++] =
|
|
140
|
-
buf[p++] =
|
|
139
|
+
buf[p++] = delay2 & 255;
|
|
140
|
+
buf[p++] = delay2 >> 8 & 255;
|
|
141
141
|
buf[p++] = transparent_index;
|
|
142
142
|
buf[p++] = 0;
|
|
143
143
|
}
|
|
@@ -279,7 +279,7 @@ var require_omggif = __commonJS({
|
|
|
279
279
|
}
|
|
280
280
|
var no_eof = true;
|
|
281
281
|
var frames = [];
|
|
282
|
-
var
|
|
282
|
+
var delay2 = 0;
|
|
283
283
|
var transparent_index = null;
|
|
284
284
|
var disposal = 0;
|
|
285
285
|
var loop_count = null;
|
|
@@ -311,7 +311,7 @@ var require_omggif = __commonJS({
|
|
|
311
311
|
if (buf[p++] !== 4 || buf[p + 4] !== 0)
|
|
312
312
|
throw new Error("Invalid graphics extension block.");
|
|
313
313
|
var pf1 = buf[p++];
|
|
314
|
-
|
|
314
|
+
delay2 = buf[p++] | buf[p++] << 8;
|
|
315
315
|
transparent_index = buf[p++];
|
|
316
316
|
if ((pf1 & 1) === 0) transparent_index = null;
|
|
317
317
|
disposal = pf1 >> 2 & 7;
|
|
@@ -370,7 +370,7 @@ var require_omggif = __commonJS({
|
|
|
370
370
|
data_length: p - data_offset,
|
|
371
371
|
transparent_index,
|
|
372
372
|
interlaced: !!interlace_flag,
|
|
373
|
-
delay,
|
|
373
|
+
delay: delay2,
|
|
374
374
|
disposal
|
|
375
375
|
});
|
|
376
376
|
break;
|
|
@@ -3777,7 +3777,7 @@ var require_gifframe = __commonJS({
|
|
|
3777
3777
|
var require_gifutil = __commonJS({
|
|
3778
3778
|
"../../node_modules/.bun/gifwrap@0.10.1/node_modules/gifwrap/src/gifutil.js"(exports2) {
|
|
3779
3779
|
"use strict";
|
|
3780
|
-
var
|
|
3780
|
+
var fs5 = __require("fs");
|
|
3781
3781
|
var ImageQ = require_image_q();
|
|
3782
3782
|
var BitmapImage2 = require_bitmapimage();
|
|
3783
3783
|
var { GifFrame: GifFrame2 } = require_gifframe();
|
|
@@ -3892,14 +3892,14 @@ var require_gifutil = __commonJS({
|
|
|
3892
3892
|
jimpImage.bitmap.data = bitmapImageToShare.bitmap.data;
|
|
3893
3893
|
return jimpImage;
|
|
3894
3894
|
};
|
|
3895
|
-
exports2.write = function(
|
|
3895
|
+
exports2.write = function(path5, frames, spec, encoder) {
|
|
3896
3896
|
encoder = encoder || defaultCodec;
|
|
3897
|
-
const matches =
|
|
3897
|
+
const matches = path5.match(/\.[a-zA-Z]+$/);
|
|
3898
3898
|
if (matches !== null && INVALID_SUFFIXES.includes(matches[0].toLowerCase())) {
|
|
3899
|
-
throw new Error(`GIF '${
|
|
3899
|
+
throw new Error(`GIF '${path5}' has an unexpected suffix`);
|
|
3900
3900
|
}
|
|
3901
3901
|
return encoder.encodeGif(frames, spec).then((gif2) => {
|
|
3902
|
-
return _writeBinary(
|
|
3902
|
+
return _writeBinary(path5, gif2.buffer).then(() => {
|
|
3903
3903
|
return gif2;
|
|
3904
3904
|
});
|
|
3905
3905
|
});
|
|
@@ -3971,9 +3971,9 @@ var require_gifutil = __commonJS({
|
|
|
3971
3971
|
}
|
|
3972
3972
|
}
|
|
3973
3973
|
}
|
|
3974
|
-
function _readBinary(
|
|
3974
|
+
function _readBinary(path5) {
|
|
3975
3975
|
return new Promise((resolve2, reject2) => {
|
|
3976
|
-
|
|
3976
|
+
fs5.readFile(path5, (err, buffer) => {
|
|
3977
3977
|
if (err) {
|
|
3978
3978
|
return reject2(err);
|
|
3979
3979
|
}
|
|
@@ -3981,9 +3981,9 @@ var require_gifutil = __commonJS({
|
|
|
3981
3981
|
});
|
|
3982
3982
|
});
|
|
3983
3983
|
}
|
|
3984
|
-
function _writeBinary(
|
|
3984
|
+
function _writeBinary(path5, buffer) {
|
|
3985
3985
|
return new Promise((resolve2, reject2) => {
|
|
3986
|
-
|
|
3986
|
+
fs5.writeFile(path5, buffer, (err) => {
|
|
3987
3987
|
if (err) {
|
|
3988
3988
|
return reject2(err);
|
|
3989
3989
|
}
|
|
@@ -5964,9 +5964,9 @@ var require_decoder = __commonJS({
|
|
|
5964
5964
|
return a < 0 ? 0 : a > 255 ? 255 : a;
|
|
5965
5965
|
}
|
|
5966
5966
|
constructor.prototype = {
|
|
5967
|
-
load: function load(
|
|
5967
|
+
load: function load(path5) {
|
|
5968
5968
|
var xhr = new XMLHttpRequest();
|
|
5969
|
-
xhr.open("GET",
|
|
5969
|
+
xhr.open("GET", path5, true);
|
|
5970
5970
|
xhr.responseType = "arraybuffer";
|
|
5971
5971
|
xhr.onload = (function() {
|
|
5972
5972
|
var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
|
|
@@ -18862,11 +18862,11 @@ var require_Mime = __commonJS({
|
|
|
18862
18862
|
}
|
|
18863
18863
|
}
|
|
18864
18864
|
};
|
|
18865
|
-
Mime.prototype.getType = function(
|
|
18866
|
-
|
|
18867
|
-
let last =
|
|
18865
|
+
Mime.prototype.getType = function(path5) {
|
|
18866
|
+
path5 = String(path5);
|
|
18867
|
+
let last = path5.replace(/^.*[/\\]/, "").toLowerCase();
|
|
18868
18868
|
let ext = last.replace(/^.*\./, "").toLowerCase();
|
|
18869
|
-
let hasPath = last.length <
|
|
18869
|
+
let hasPath = last.length < path5.length;
|
|
18870
18870
|
let hasDot = ext.length < last.length - 1;
|
|
18871
18871
|
return (hasDot || !hasPath) && this._types[ext] || null;
|
|
18872
18872
|
};
|
|
@@ -32623,9 +32623,9 @@ function createJimp({ plugins: pluginsArg, formats: formatsArg } = {}) {
|
|
|
32623
32623
|
* await image.write("test/output.png");
|
|
32624
32624
|
* ```
|
|
32625
32625
|
*/
|
|
32626
|
-
async write(
|
|
32627
|
-
const mimeType = import_lite.default.getType(
|
|
32628
|
-
await writeFile(
|
|
32626
|
+
async write(path5, options) {
|
|
32627
|
+
const mimeType = import_lite.default.getType(path5);
|
|
32628
|
+
await writeFile(path5, await this.getBuffer(mimeType, options));
|
|
32629
32629
|
}
|
|
32630
32630
|
/**
|
|
32631
32631
|
* Clone the image into a new Jimp instance.
|
|
@@ -38485,6 +38485,27 @@ function resolveContainerFieldLabel(container) {
|
|
|
38485
38485
|
}
|
|
38486
38486
|
return void 0;
|
|
38487
38487
|
}
|
|
38488
|
+
function shouldDropInheritedFieldLabel(element, inheritedFieldLabel) {
|
|
38489
|
+
if (!inheritedFieldLabel) return false;
|
|
38490
|
+
if (INTERACTIVE_LEAF_ROLES.has(element.role)) return false;
|
|
38491
|
+
if (!isClickableByAttribute(element)) return false;
|
|
38492
|
+
const directText = getElementText(element);
|
|
38493
|
+
if (directText) {
|
|
38494
|
+
return directText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
38495
|
+
}
|
|
38496
|
+
const childTexts = [];
|
|
38497
|
+
for (const child of element.children) {
|
|
38498
|
+
if (!INTERACTIVE_LEAF_ROLES.has(child.role)) {
|
|
38499
|
+
const text = getElementText(child);
|
|
38500
|
+
if (text && TEXT_CARRYING_ROLES.has(child.role)) {
|
|
38501
|
+
childTexts.push(text);
|
|
38502
|
+
}
|
|
38503
|
+
}
|
|
38504
|
+
}
|
|
38505
|
+
const composedText = childTexts.join(" ");
|
|
38506
|
+
if (!composedText) return false;
|
|
38507
|
+
return composedText.toLowerCase() !== inheritedFieldLabel.toLowerCase();
|
|
38508
|
+
}
|
|
38488
38509
|
var TEXT_CARRYING_ROLES = /* @__PURE__ */ new Set([
|
|
38489
38510
|
"generic",
|
|
38490
38511
|
"paragraph",
|
|
@@ -38571,10 +38592,10 @@ function extractDataValue(text) {
|
|
|
38571
38592
|
}
|
|
38572
38593
|
function findRelevanceScope(elements, activeElementRef) {
|
|
38573
38594
|
if (!activeElementRef) return null;
|
|
38574
|
-
const
|
|
38595
|
+
const path5 = [];
|
|
38575
38596
|
function findPath(el) {
|
|
38576
38597
|
if (el.ref) {
|
|
38577
|
-
|
|
38598
|
+
path5.push({ ref: el.ref, role: el.role });
|
|
38578
38599
|
}
|
|
38579
38600
|
if (el.ref === activeElementRef) {
|
|
38580
38601
|
return true;
|
|
@@ -38582,15 +38603,15 @@ function findRelevanceScope(elements, activeElementRef) {
|
|
|
38582
38603
|
for (const child of el.children) {
|
|
38583
38604
|
if (findPath(child)) return true;
|
|
38584
38605
|
}
|
|
38585
|
-
if (el.ref)
|
|
38606
|
+
if (el.ref) path5.pop();
|
|
38586
38607
|
return false;
|
|
38587
38608
|
}
|
|
38588
38609
|
for (const el of elements) {
|
|
38589
38610
|
if (findPath(el)) break;
|
|
38590
38611
|
}
|
|
38591
|
-
for (let i =
|
|
38592
|
-
if (SECTION_BOUNDARY_ROLES.has(
|
|
38593
|
-
return
|
|
38612
|
+
for (let i = path5.length - 1; i >= 0; i--) {
|
|
38613
|
+
if (SECTION_BOUNDARY_ROLES.has(path5[i].role)) {
|
|
38614
|
+
return path5[i].ref;
|
|
38594
38615
|
}
|
|
38595
38616
|
}
|
|
38596
38617
|
return null;
|
|
@@ -38639,9 +38660,9 @@ function searchElements(elements, searchTerms, scopeRef = null) {
|
|
|
38639
38660
|
function findElementInSections(sections, targetRef, ancestors = []) {
|
|
38640
38661
|
for (const section of sections) {
|
|
38641
38662
|
const newAncestors = [...ancestors, section];
|
|
38642
|
-
const
|
|
38663
|
+
const path5 = newAncestors.map((s) => s.heading);
|
|
38643
38664
|
if (section.elements.some((el) => el.ref === targetRef)) {
|
|
38644
|
-
return { section, ancestors: newAncestors, path:
|
|
38665
|
+
return { section, ancestors: newAncestors, path: path5 };
|
|
38645
38666
|
}
|
|
38646
38667
|
const found = findElementInSections(section.subsections, targetRef, newAncestors);
|
|
38647
38668
|
if (found) return found;
|
|
@@ -38652,7 +38673,7 @@ function populateSearchContext(matches, sections) {
|
|
|
38652
38673
|
for (const match of matches) {
|
|
38653
38674
|
const result = findElementInSections(sections, match.ref);
|
|
38654
38675
|
if (result) {
|
|
38655
|
-
const { section, ancestors, path:
|
|
38676
|
+
const { section, ancestors, path: path5 } = result;
|
|
38656
38677
|
const inFocusedDialog = ancestors.some((s) => s.isFocused);
|
|
38657
38678
|
const inBackground = section.isBackground || ancestors.some((s) => s.isBackground);
|
|
38658
38679
|
if (inFocusedDialog) {
|
|
@@ -38663,7 +38684,7 @@ function populateSearchContext(matches, sections) {
|
|
|
38663
38684
|
match.context = "foreground";
|
|
38664
38685
|
}
|
|
38665
38686
|
const SKIP_HEADINGS = ["generic", "main", "iframe"];
|
|
38666
|
-
match.sectionPath =
|
|
38687
|
+
match.sectionPath = path5.filter((p) => !SKIP_HEADINGS.includes(p.toLowerCase())).slice(-3).join(" > ");
|
|
38667
38688
|
}
|
|
38668
38689
|
}
|
|
38669
38690
|
}
|
|
@@ -38825,6 +38846,24 @@ function findPrimaryColumnLabel(columnHeader) {
|
|
|
38825
38846
|
};
|
|
38826
38847
|
return search(columnHeader);
|
|
38827
38848
|
}
|
|
38849
|
+
function isWidgetTable(element) {
|
|
38850
|
+
if (element.role !== "table") return false;
|
|
38851
|
+
const rows = element.children.filter((c2) => c2.role === "row");
|
|
38852
|
+
if (rows.length === 0 || rows.length > 2) return false;
|
|
38853
|
+
let totalCells = 0;
|
|
38854
|
+
let interactiveCells = 0;
|
|
38855
|
+
for (const row of rows) {
|
|
38856
|
+
for (const cell of row.children) {
|
|
38857
|
+
if (cell.role === "cell" || cell.role === "gridcell" || cell.role === "columnheader") {
|
|
38858
|
+
totalCells++;
|
|
38859
|
+
if (hasInteractiveDescendants(cell)) {
|
|
38860
|
+
interactiveCells++;
|
|
38861
|
+
}
|
|
38862
|
+
}
|
|
38863
|
+
}
|
|
38864
|
+
}
|
|
38865
|
+
return totalCells > 0 && interactiveCells >= totalCells * 0.5;
|
|
38866
|
+
}
|
|
38828
38867
|
function detectGrid(element) {
|
|
38829
38868
|
if (element.role !== "grid" && element.role !== "treegrid" && element.role !== "table") {
|
|
38830
38869
|
return null;
|
|
@@ -39150,7 +39189,7 @@ function formatElement(element, options) {
|
|
|
39150
39189
|
const textSource = normalizeIconLabelText(element.role, rawTextSource);
|
|
39151
39190
|
const extracted = extractDataValue(textSource);
|
|
39152
39191
|
const normalizedAttributes = Object.entries(element.attributes).filter(
|
|
39153
|
-
([key]) => key !== "ref" && key !== "cursor" && key !== "aria-controls" && key !== "aria-owns" && key !== "options"
|
|
39192
|
+
([key]) => key !== "ref" && key !== "cursor" && key !== "aria-controls" && key !== "aria-owns" && key !== "options" && key !== "field"
|
|
39154
39193
|
).map(([key, val]) => {
|
|
39155
39194
|
if (key === "aria-haspopup") return "haspopup";
|
|
39156
39195
|
if (key === "aria-expanded") return `expanded=${val}`;
|
|
@@ -39169,7 +39208,7 @@ function formatElement(element, options) {
|
|
|
39169
39208
|
ref: element.ref,
|
|
39170
39209
|
role: element.role,
|
|
39171
39210
|
name: textSource,
|
|
39172
|
-
fieldLabel: options?.fieldLabel,
|
|
39211
|
+
fieldLabel: options?.fieldLabel || element.attributes["field"] || void 0,
|
|
39173
39212
|
label: extracted.label || void 0,
|
|
39174
39213
|
value: extracted.value,
|
|
39175
39214
|
status: extracted.status,
|
|
@@ -39396,22 +39435,23 @@ function buildGridSection(element, gridInfo) {
|
|
|
39396
39435
|
}
|
|
39397
39436
|
function collectInteractiveElements(element, elements, subsections, depth, inheritedFieldLabel) {
|
|
39398
39437
|
if ((INTERACTIVE_LEAF_ROLES.has(element.role) || isClickableByAttribute(element)) && element.ref) {
|
|
39438
|
+
const effectiveFieldLabel = shouldDropInheritedFieldLabel(element, inheritedFieldLabel) ? void 0 : inheritedFieldLabel;
|
|
39399
39439
|
if (INTERACTIVE_LEAF_ROLES.has(element.role) && isExpandedWithActionableChildren(element)) {
|
|
39400
|
-
elements.push(formatElement(element, { overrideLabel: composeTriggerLabel(element), fieldLabel:
|
|
39440
|
+
elements.push(formatElement(element, { overrideLabel: composeTriggerLabel(element), fieldLabel: effectiveFieldLabel }));
|
|
39401
39441
|
collectExpandedChildren(element, elements);
|
|
39402
39442
|
return;
|
|
39403
39443
|
}
|
|
39404
39444
|
if (!isMenuTriggerNoise(element)) {
|
|
39405
|
-
elements.push(formatElement(element, { fieldLabel:
|
|
39445
|
+
elements.push(formatElement(element, { fieldLabel: effectiveFieldLabel }));
|
|
39406
39446
|
}
|
|
39407
39447
|
if (!INTERACTIVE_LEAF_ROLES.has(element.role) && isClickableByAttribute(element)) {
|
|
39408
39448
|
for (const child of element.children) {
|
|
39409
|
-
collectInteractiveElements(child, elements, subsections, depth + 1,
|
|
39449
|
+
collectInteractiveElements(child, elements, subsections, depth + 1, effectiveFieldLabel);
|
|
39410
39450
|
}
|
|
39411
39451
|
}
|
|
39412
39452
|
return;
|
|
39413
39453
|
}
|
|
39414
|
-
if (element.role === "heading" || STRUCTURAL_ROLES.has(element.role) || element.role === "grid" || element.role === "treegrid" || element.role === "table") {
|
|
39454
|
+
if (element.role === "heading" || STRUCTURAL_ROLES.has(element.role) || element.role === "grid" || element.role === "treegrid" || element.role === "table" && !isWidgetTable(element)) {
|
|
39415
39455
|
const section = buildSection(element, depth);
|
|
39416
39456
|
if (section) {
|
|
39417
39457
|
subsections.push(section);
|
|
@@ -39449,7 +39489,8 @@ function collectInteractiveElements(element, elements, subsections, depth, inher
|
|
|
39449
39489
|
collectInteractiveElements(child, elements, subsections, depth + 1);
|
|
39450
39490
|
}
|
|
39451
39491
|
} else if ((INTERACTIVE_LEAF_ROLES.has(child.role) || isClickableByAttribute(child)) && child.ref) {
|
|
39452
|
-
const
|
|
39492
|
+
const rawFieldLabel = findFieldLabelInContext(child, kids, ki) ?? inheritedFieldLabel;
|
|
39493
|
+
const fieldLabel = shouldDropInheritedFieldLabel(child, rawFieldLabel) ? void 0 : rawFieldLabel;
|
|
39453
39494
|
if (!isMenuTriggerNoise(child)) {
|
|
39454
39495
|
if (INTERACTIVE_LEAF_ROLES.has(child.role) && isExpandedWithActionableChildren(child)) {
|
|
39455
39496
|
elements.push(formatElement(child, { overrideLabel: composeTriggerLabel(child), fieldLabel }));
|
|
@@ -39464,7 +39505,7 @@ function collectInteractiveElements(element, elements, subsections, depth, inher
|
|
|
39464
39505
|
}
|
|
39465
39506
|
}
|
|
39466
39507
|
} else {
|
|
39467
|
-
const containerLabel = resolveContainerFieldLabel(child) ?? inheritedFieldLabel;
|
|
39508
|
+
const containerLabel = resolveContainerFieldLabel(child) ?? (child.role === "table" ? findFieldLabelFromSiblings(kids, ki) : void 0) ?? inheritedFieldLabel;
|
|
39468
39509
|
collectInteractiveElements(child, elements, subsections, depth + 1, containerLabel);
|
|
39469
39510
|
}
|
|
39470
39511
|
}
|
|
@@ -39608,7 +39649,7 @@ var COLOR_NAMES = [
|
|
|
39608
39649
|
"teal",
|
|
39609
39650
|
"pink"
|
|
39610
39651
|
];
|
|
39611
|
-
function generateFrontmatter(elementCount, sectionCount, activeElement, dialogStack, searchMatches, totalMatchCount, snapshotFilePath, probeResult) {
|
|
39652
|
+
function generateFrontmatter(elementCount, sectionCount, activeElement, dialogStack, searchMatches, totalMatchCount, snapshotFilePath, probeResult, currentTime, capturedToasts) {
|
|
39612
39653
|
const activeLabel = activeElement ? normalizeIconLabelText(
|
|
39613
39654
|
activeElement.role,
|
|
39614
39655
|
INTERACTIVE_LEAF_ROLES.has(activeElement.role) && isExpandedWithActionableChildren(activeElement) ? composeTriggerLabel(activeElement) : activeElement.text || ""
|
|
@@ -39616,6 +39657,16 @@ function generateFrontmatter(elementCount, sectionCount, activeElement, dialogSt
|
|
|
39616
39657
|
const activeDesc = activeElement ? `${activeElement.ref} ${activeElement.role} "${activeLabel}"` : "None";
|
|
39617
39658
|
const dialogStackLine = dialogStack.length > 0 ? `
|
|
39618
39659
|
DIALOG STACK: ${dialogStack.join(" \u2192 ")}` : "";
|
|
39660
|
+
let toastSection = "";
|
|
39661
|
+
if (capturedToasts && capturedToasts.length > 0) {
|
|
39662
|
+
const toastLines = capturedToasts.map((t) => {
|
|
39663
|
+
const ttl = t.snapshotsRemaining !== void 0 ? ` (expires in ${t.snapshotsRemaining} snapshots)` : "";
|
|
39664
|
+
return ` - [${t.role}] "${t.text}"${ttl}`;
|
|
39665
|
+
});
|
|
39666
|
+
toastSection = `
|
|
39667
|
+
TOAST NOTIFICATIONS:
|
|
39668
|
+
${toastLines.join("\n")}`;
|
|
39669
|
+
}
|
|
39619
39670
|
let searchSection = "";
|
|
39620
39671
|
if (searchMatches && searchMatches.length > 0) {
|
|
39621
39672
|
const hasContextInfo = searchMatches.some((m) => m.context);
|
|
@@ -39665,10 +39716,12 @@ PROBE RESULT:
|
|
|
39665
39716
|
FULL TREE FILE: ${snapshotFilePath}
|
|
39666
39717
|
Use bash or python_execute to grep/parse this file for detailed element analysis.`;
|
|
39667
39718
|
}
|
|
39719
|
+
const browserTime = currentTime ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
39668
39720
|
return `---
|
|
39669
39721
|
SEMANTIC SNAPSHOT - ${elementCount} elements in ${sectionCount} sections
|
|
39722
|
+
BROWSER TIME: ${browserTime} (UTC)
|
|
39670
39723
|
FORMAT: Sections grouped by headings. [ref] tags identify clickable elements.
|
|
39671
|
-
ACTIVE ELEMENT: ${activeDesc}${dialogStackLine}${searchSection}${probeSection}${fullTreeFileSection}
|
|
39724
|
+
ACTIVE ELEMENT: ${activeDesc}${dialogStackLine}${toastSection}${searchSection}${probeSection}${fullTreeFileSection}
|
|
39672
39725
|
ACTIONS:
|
|
39673
39726
|
- Click/type using [ref] values (e.g., browser_click ref=e123)${typeActionHint}
|
|
39674
39727
|
- Click using coordinates from search results (e.g., browser_click x=450 y=320)
|
|
@@ -39738,7 +39791,9 @@ function formatSemanticSnapshot(yaml, options) {
|
|
|
39738
39791
|
// Use re-sorted matches with context
|
|
39739
39792
|
options?.totalMatchCount,
|
|
39740
39793
|
options?.snapshotFilePath,
|
|
39741
|
-
options?.probeResult
|
|
39794
|
+
options?.probeResult,
|
|
39795
|
+
options?.currentTime,
|
|
39796
|
+
options?.capturedToasts
|
|
39742
39797
|
)
|
|
39743
39798
|
);
|
|
39744
39799
|
lines.push("");
|
|
@@ -40137,10 +40192,11 @@ function generateHint(diff2, networkInfo) {
|
|
|
40137
40192
|
}
|
|
40138
40193
|
return hints.join(" ");
|
|
40139
40194
|
}
|
|
40140
|
-
function formatSemanticDiff(diff2, actionDescription, networkInfo) {
|
|
40195
|
+
function formatSemanticDiff(diff2, actionDescription, networkInfo, currentTime) {
|
|
40141
40196
|
const lines = [];
|
|
40142
40197
|
lines.push("---");
|
|
40143
40198
|
lines.push("SEMANTIC DIFF: Page state changes after browser action.");
|
|
40199
|
+
lines.push(`BROWSER TIME: ${currentTime ?? (/* @__PURE__ */ new Date()).toISOString()} (UTC)`);
|
|
40144
40200
|
lines.push("Format: [PREVIOUS] value [CURRENT] value");
|
|
40145
40201
|
lines.push("");
|
|
40146
40202
|
lines.push(`ACTION: ${actionDescription}`);
|
|
@@ -40219,6 +40275,38 @@ function formatValue(value) {
|
|
|
40219
40275
|
return `"${truncate(value, 20)}"`;
|
|
40220
40276
|
}
|
|
40221
40277
|
|
|
40278
|
+
// ../browser-core/src/playwright-client/download-utils.ts
|
|
40279
|
+
import * as path from "path";
|
|
40280
|
+
function formatFileSize(bytes) {
|
|
40281
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
40282
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
40283
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
40284
|
+
}
|
|
40285
|
+
function guessMimeType(filename) {
|
|
40286
|
+
const ext = path.extname(filename).toLowerCase();
|
|
40287
|
+
const mimeMap = {
|
|
40288
|
+
".pdf": "application/pdf",
|
|
40289
|
+
".txt": "text/plain",
|
|
40290
|
+
".csv": "text/csv",
|
|
40291
|
+
".json": "application/json",
|
|
40292
|
+
".xml": "application/xml",
|
|
40293
|
+
".html": "text/html",
|
|
40294
|
+
".htm": "text/html",
|
|
40295
|
+
".md": "text/markdown",
|
|
40296
|
+
".png": "image/png",
|
|
40297
|
+
".jpg": "image/jpeg",
|
|
40298
|
+
".jpeg": "image/jpeg",
|
|
40299
|
+
".gif": "image/gif",
|
|
40300
|
+
".svg": "image/svg+xml",
|
|
40301
|
+
".zip": "application/zip",
|
|
40302
|
+
".doc": "application/msword",
|
|
40303
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
40304
|
+
".xls": "application/vnd.ms-excel",
|
|
40305
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
40306
|
+
};
|
|
40307
|
+
return mimeMap[ext] ?? "application/octet-stream";
|
|
40308
|
+
}
|
|
40309
|
+
|
|
40222
40310
|
// ../browser-core/src/playwright-client/element-inspection.ts
|
|
40223
40311
|
function errorMessage(error) {
|
|
40224
40312
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -40618,7 +40706,7 @@ async function extractElementMetadata(page, locator, ref, logger2) {
|
|
|
40618
40706
|
}
|
|
40619
40707
|
|
|
40620
40708
|
// ../browser-core/src/tools/executor.ts
|
|
40621
|
-
import * as
|
|
40709
|
+
import * as path2 from "path";
|
|
40622
40710
|
import * as fs2 from "fs/promises";
|
|
40623
40711
|
import * as crypto2 from "crypto";
|
|
40624
40712
|
|
|
@@ -40747,7 +40835,10 @@ var BrowserToolExecutor = class {
|
|
|
40747
40835
|
this.allowedHosts = options?.allowedHosts;
|
|
40748
40836
|
this.autoSnapshotAfterAction = options?.autoSnapshotAfterAction !== false;
|
|
40749
40837
|
this.includeScreenshotWithSnapshot = options?.includeScreenshotWithSnapshot !== false;
|
|
40750
|
-
|
|
40838
|
+
if (!options?.workspaceDir && !options?.tmpBaseDir) {
|
|
40839
|
+
options?.logger?.debug?.("[BrowserToolExecutor] No tmpBaseDir provided, using flat canary dir (not org-scoped)");
|
|
40840
|
+
}
|
|
40841
|
+
this.workspaceDir = options?.workspaceDir ?? path2.join(options?.tmpBaseDir ?? getCanaryTmpDir(), `browser-workspace-${Date.now()}-${crypto2.randomUUID().slice(0, 8)}`);
|
|
40751
40842
|
this.logger = options?.logger;
|
|
40752
40843
|
fs2.mkdir(this.workspaceDir, { recursive: true }).catch(() => {
|
|
40753
40844
|
});
|
|
@@ -40912,15 +41003,18 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
40912
41003
|
try {
|
|
40913
41004
|
await fs2.mkdir(this.workspaceDir, { recursive: true });
|
|
40914
41005
|
const filename = `snapshot-${Date.now()}-${crypto2.randomUUID().slice(0, 8)}.yaml`;
|
|
40915
|
-
snapshotFilePath =
|
|
41006
|
+
snapshotFilePath = path2.join(this.workspaceDir, filename);
|
|
40916
41007
|
await fs2.writeFile(snapshotFilePath, yaml, "utf-8");
|
|
40917
41008
|
} catch {
|
|
40918
41009
|
}
|
|
41010
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
40919
41011
|
const semanticText = formatSemanticSnapshot(yaml, {
|
|
40920
41012
|
searchMatches: searchMatches.length > 0 ? searchMatches : void 0,
|
|
40921
41013
|
totalMatchCount: totalMatchCount > 0 ? totalMatchCount : void 0,
|
|
40922
41014
|
snapshotFilePath,
|
|
40923
|
-
probeResult
|
|
41015
|
+
probeResult,
|
|
41016
|
+
currentTime: now,
|
|
41017
|
+
capturedToasts: this.client.getCapturedToasts?.() ?? []
|
|
40924
41018
|
});
|
|
40925
41019
|
if (hasImages) {
|
|
40926
41020
|
const resolutionNote = buildResolutionNote(
|
|
@@ -41163,7 +41257,7 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41163
41257
|
if (!afterModal) {
|
|
41164
41258
|
const afterState2 = captureSnapshotState(afterUrl2, afterYaml2);
|
|
41165
41259
|
const diff3 = compareSnapshots(beforeState, afterState2);
|
|
41166
|
-
return formatSemanticDiff(diff3, `Dismissed overlay using ${strategy}
|
|
41260
|
+
return formatSemanticDiff(diff3, `Dismissed overlay using ${strategy}`, void 0, (/* @__PURE__ */ new Date()).toISOString());
|
|
41167
41261
|
}
|
|
41168
41262
|
} catch (err) {
|
|
41169
41263
|
this.logger?.debug?.(`[BrowserTools] Dismiss strategy ${strategy} failed`, {
|
|
@@ -41179,7 +41273,7 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41179
41273
|
const diff2 = compareSnapshots(beforeState, afterState);
|
|
41180
41274
|
return `Could not dismiss overlay with strategies: ${strategies.join(", ")}. Modal may require specific interaction.
|
|
41181
41275
|
|
|
41182
|
-
` + formatSemanticDiff(diff2, "Dismiss overlay attempted (failed)");
|
|
41276
|
+
` + formatSemanticDiff(diff2, "Dismiss overlay attempted (failed)", void 0, (/* @__PURE__ */ new Date()).toISOString());
|
|
41183
41277
|
}
|
|
41184
41278
|
// ==================== Waiting ====================
|
|
41185
41279
|
async waitFor(opts) {
|
|
@@ -41293,7 +41387,8 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41293
41387
|
}
|
|
41294
41388
|
const diff2 = compareSnapshots(beforeState, afterState);
|
|
41295
41389
|
const networkInfo = this.client.getPendingNetworkInfo?.() ?? void 0;
|
|
41296
|
-
const
|
|
41390
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41391
|
+
const diffText = formatSemanticDiff(diff2, actionDescription, networkInfo, now);
|
|
41297
41392
|
const hasChanges = hasDiffChanges(diff2);
|
|
41298
41393
|
const isStable = !networkInfo || networkInfo.pendingCount === 0;
|
|
41299
41394
|
let autoSnapshot;
|
|
@@ -41303,11 +41398,11 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41303
41398
|
try {
|
|
41304
41399
|
await fs2.mkdir(this.workspaceDir, { recursive: true });
|
|
41305
41400
|
const filename = `snapshot-${Date.now()}-${crypto2.randomUUID().slice(0, 8)}.yaml`;
|
|
41306
|
-
snapshotFilePath =
|
|
41401
|
+
snapshotFilePath = path2.join(this.workspaceDir, filename);
|
|
41307
41402
|
await fs2.writeFile(snapshotFilePath, afterYaml, "utf-8");
|
|
41308
41403
|
} catch {
|
|
41309
41404
|
}
|
|
41310
|
-
const semanticText = formatSemanticSnapshot(afterYaml, { snapshotFilePath });
|
|
41405
|
+
const semanticText = formatSemanticSnapshot(afterYaml, { snapshotFilePath, currentTime: now, capturedToasts: this.client.getCapturedToasts?.() ?? [] });
|
|
41311
41406
|
const afterImages = isMCPContentWithImages(afterResult) ? afterResult.images : void 0;
|
|
41312
41407
|
if (afterImages?.length && this.onScreenshot) {
|
|
41313
41408
|
const img = afterImages[0];
|
|
@@ -41344,11 +41439,11 @@ ${effectiveShowCoordinateGrid ? "Coordinate grid enabled - read coordinates from
|
|
|
41344
41439
|
try {
|
|
41345
41440
|
await fs2.mkdir(this.workspaceDir, { recursive: true });
|
|
41346
41441
|
const filename = `snapshot-${Date.now()}-${crypto2.randomUUID().slice(0, 8)}.yaml`;
|
|
41347
|
-
snapshotFilePath =
|
|
41442
|
+
snapshotFilePath = path2.join(this.workspaceDir, filename);
|
|
41348
41443
|
await fs2.writeFile(snapshotFilePath, yaml, "utf-8");
|
|
41349
41444
|
} catch {
|
|
41350
41445
|
}
|
|
41351
|
-
const semanticText = formatSemanticSnapshot(yaml, { snapshotFilePath });
|
|
41446
|
+
const semanticText = formatSemanticSnapshot(yaml, { snapshotFilePath, currentTime: (/* @__PURE__ */ new Date()).toISOString(), capturedToasts: this.client.getCapturedToasts?.() ?? [] });
|
|
41352
41447
|
const yamlBlockPattern = /- Page Snapshot:\n```yaml\n[\s\S]*?```/;
|
|
41353
41448
|
if (yamlBlockPattern.test(result)) {
|
|
41354
41449
|
return result.replace(yamlBlockPattern, `- Page Snapshot (semantic):
|
|
@@ -42583,8 +42678,8 @@ var errors = playwrightLoader.lazyloadExportOrDie("errors");
|
|
|
42583
42678
|
|
|
42584
42679
|
// ../browser-core/src/playwright-client.ts
|
|
42585
42680
|
var import_puppeteer_extra_plugin_stealth = __toESM(require_puppeteer_extra_plugin_stealth(), 1);
|
|
42586
|
-
import * as
|
|
42587
|
-
import * as
|
|
42681
|
+
import * as fs4 from "fs/promises";
|
|
42682
|
+
import * as path4 from "path";
|
|
42588
42683
|
|
|
42589
42684
|
// ../browser-core/src/playwright-client/toast-capture-script.ts
|
|
42590
42685
|
var TOAST_CAPTURE_SCRIPT = `
|
|
@@ -42687,7 +42782,7 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42687
42782
|
return (clone.textContent || '').trim();
|
|
42688
42783
|
}
|
|
42689
42784
|
|
|
42690
|
-
function pushToast(text, role) {
|
|
42785
|
+
function pushToast(text, role, el) {
|
|
42691
42786
|
if (!text || text.length === 0 || text.length >= 1000) return;
|
|
42692
42787
|
// Deduplicate: skip if we already have the same text from the last 2 seconds
|
|
42693
42788
|
const now = Date.now();
|
|
@@ -42695,7 +42790,21 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42695
42790
|
(t) => t.text === text && now - t.time < 2000
|
|
42696
42791
|
);
|
|
42697
42792
|
if (isDupe) return;
|
|
42698
|
-
|
|
42793
|
+
|
|
42794
|
+
let placement = null;
|
|
42795
|
+
if (el && el.getBoundingClientRect) {
|
|
42796
|
+
const rect = el.getBoundingClientRect();
|
|
42797
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
42798
|
+
placement = {
|
|
42799
|
+
x: Math.round(rect.x),
|
|
42800
|
+
y: Math.round(rect.y),
|
|
42801
|
+
width: Math.round(rect.width),
|
|
42802
|
+
height: Math.round(rect.height),
|
|
42803
|
+
};
|
|
42804
|
+
}
|
|
42805
|
+
}
|
|
42806
|
+
|
|
42807
|
+
window.__capturedToasts.push({ text: text, role: role, time: now, placement: placement });
|
|
42699
42808
|
if (window.__capturedToasts.length > MAX_TOASTS) {
|
|
42700
42809
|
window.__capturedToasts.shift();
|
|
42701
42810
|
}
|
|
@@ -42714,7 +42823,7 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42714
42823
|
if (el.matches && el.matches(TOAST_SELECTORS) && isElementVisible(el)) {
|
|
42715
42824
|
const text = extractToastText(el);
|
|
42716
42825
|
if (text) {
|
|
42717
|
-
pushToast(text, el.getAttribute('role') || el.getAttribute('aria-live') || 'toast');
|
|
42826
|
+
pushToast(text, el.getAttribute('role') || el.getAttribute('aria-live') || 'toast', el);
|
|
42718
42827
|
return;
|
|
42719
42828
|
}
|
|
42720
42829
|
}
|
|
@@ -42725,7 +42834,7 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42725
42834
|
if (isElementVisible(desc)) {
|
|
42726
42835
|
const text = extractToastText(desc);
|
|
42727
42836
|
if (text) {
|
|
42728
|
-
pushToast(text, desc.getAttribute('role') || desc.getAttribute('aria-live') || 'toast');
|
|
42837
|
+
pushToast(text, desc.getAttribute('role') || desc.getAttribute('aria-live') || 'toast', desc);
|
|
42729
42838
|
}
|
|
42730
42839
|
}
|
|
42731
42840
|
}
|
|
@@ -42772,7 +42881,8 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42772
42881
|
if (el.matches(TOAST_SELECTORS)) {
|
|
42773
42882
|
pushToast(
|
|
42774
42883
|
extractToastText(el),
|
|
42775
|
-
el.getAttribute('role') || el.getAttribute('aria-live') || 'toast'
|
|
42884
|
+
el.getAttribute('role') || el.getAttribute('aria-live') || 'toast',
|
|
42885
|
+
el
|
|
42776
42886
|
);
|
|
42777
42887
|
// Install secondary observer if this is also a live-region container
|
|
42778
42888
|
if (el.matches(LIVE_REGION_CONTAINER)) {
|
|
@@ -42787,7 +42897,8 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42787
42897
|
for (const child of children) {
|
|
42788
42898
|
pushToast(
|
|
42789
42899
|
extractToastText(child),
|
|
42790
|
-
child.getAttribute('role') || child.getAttribute('aria-live') || 'toast'
|
|
42900
|
+
child.getAttribute('role') || child.getAttribute('aria-live') || 'toast',
|
|
42901
|
+
child
|
|
42791
42902
|
);
|
|
42792
42903
|
}
|
|
42793
42904
|
if (children.length > 0) return;
|
|
@@ -42803,7 +42914,7 @@ var TOAST_CAPTURE_SCRIPT = `
|
|
|
42803
42914
|
const role = container
|
|
42804
42915
|
? container.getAttribute('role') || container.getAttribute('aria-live') || 'live-region'
|
|
42805
42916
|
: 'live-region';
|
|
42806
|
-
pushToast(text, role);
|
|
42917
|
+
pushToast(text, role, el);
|
|
42807
42918
|
}
|
|
42808
42919
|
// Install secondary observer on the container for future CSS toggles
|
|
42809
42920
|
installContainerObserver(container);
|
|
@@ -43291,11 +43402,44 @@ async function enrichHiddenClickableElements(page, logger2) {
|
|
|
43291
43402
|
try {
|
|
43292
43403
|
const enrichedCount = await page.evaluate(() => {
|
|
43293
43404
|
let count = 0;
|
|
43294
|
-
const
|
|
43295
|
-
|
|
43405
|
+
const chosenCloseButtons = document.querySelectorAll("abbr.search-choice-close");
|
|
43406
|
+
for (const el of chosenCloseButtons) {
|
|
43407
|
+
if (el.getAttribute("data-enriched-clickable") === "true") continue;
|
|
43408
|
+
if (el.getAttribute("role") === "button") continue;
|
|
43409
|
+
let fieldName;
|
|
43410
|
+
const container = el.closest(".chosen-container");
|
|
43411
|
+
if (container) {
|
|
43412
|
+
const selectEl = container.previousElementSibling;
|
|
43413
|
+
if (selectEl && selectEl.tagName === "SELECT") {
|
|
43414
|
+
const selectId = selectEl.id;
|
|
43415
|
+
if (selectId) {
|
|
43416
|
+
const labelEl = document.querySelector(`label[for="${selectId}"]`);
|
|
43417
|
+
if (labelEl?.textContent?.trim()) {
|
|
43418
|
+
fieldName = labelEl.textContent.trim();
|
|
43419
|
+
}
|
|
43420
|
+
}
|
|
43421
|
+
if (!fieldName) {
|
|
43422
|
+
fieldName = selectEl.getAttribute("aria-label") || void 0;
|
|
43423
|
+
}
|
|
43424
|
+
}
|
|
43425
|
+
if (!fieldName && container.parentElement) {
|
|
43426
|
+
const prev = container.parentElement.previousElementSibling;
|
|
43427
|
+
if (prev && (prev.tagName === "LABEL" || prev.querySelector("label"))) {
|
|
43428
|
+
const labelText = prev.textContent?.trim();
|
|
43429
|
+
if (labelText && labelText.length < 80) fieldName = labelText;
|
|
43430
|
+
}
|
|
43431
|
+
}
|
|
43432
|
+
}
|
|
43433
|
+
const label = fieldName ? `Clear ${fieldName}` : "Clear selection";
|
|
43434
|
+
el.setAttribute("role", "button");
|
|
43435
|
+
el.setAttribute("aria-label", label);
|
|
43436
|
+
el.setAttribute("data-enriched-clickable", "true");
|
|
43437
|
+
count++;
|
|
43438
|
+
}
|
|
43439
|
+
const genericPatterns = [
|
|
43296
43440
|
[".select2-selection__clear", "select2-selection__clear"]
|
|
43297
43441
|
];
|
|
43298
|
-
for (const [selector, fallbackLabel] of
|
|
43442
|
+
for (const [selector, fallbackLabel] of genericPatterns) {
|
|
43299
43443
|
const elements = document.querySelectorAll(selector);
|
|
43300
43444
|
for (const el of elements) {
|
|
43301
43445
|
if (el.getAttribute("data-enriched-clickable") === "true") continue;
|
|
@@ -43307,6 +43451,12 @@ async function enrichHiddenClickableElements(page, logger2) {
|
|
|
43307
43451
|
count++;
|
|
43308
43452
|
}
|
|
43309
43453
|
}
|
|
43454
|
+
const chosenSearchInputs = document.querySelectorAll(
|
|
43455
|
+
".chosen-container:not(.chosen-with-drop) .chosen-search-input"
|
|
43456
|
+
);
|
|
43457
|
+
for (const input of chosenSearchInputs) {
|
|
43458
|
+
input.setAttribute("aria-hidden", "true");
|
|
43459
|
+
}
|
|
43310
43460
|
return count;
|
|
43311
43461
|
});
|
|
43312
43462
|
if (enrichedCount > 0) {
|
|
@@ -43345,10 +43495,29 @@ async function augmentHiddenSelectOptions(page, yaml, logger2) {
|
|
|
43345
43495
|
if (!trigger) continue;
|
|
43346
43496
|
const rect = trigger.getBoundingClientRect();
|
|
43347
43497
|
const triggerText = trigger.textContent?.trim()?.slice(0, 80) || null;
|
|
43498
|
+
let fieldLabel = null;
|
|
43499
|
+
const selectId = sel.id;
|
|
43500
|
+
if (selectId) {
|
|
43501
|
+
const labelEl = document.querySelector(`label[for="${selectId}"]`);
|
|
43502
|
+
if (labelEl?.textContent?.trim()) {
|
|
43503
|
+
fieldLabel = labelEl.textContent.trim();
|
|
43504
|
+
}
|
|
43505
|
+
}
|
|
43506
|
+
if (!fieldLabel) {
|
|
43507
|
+
fieldLabel = sel.getAttribute("aria-label") || null;
|
|
43508
|
+
}
|
|
43509
|
+
if (!fieldLabel && parent.previousElementSibling) {
|
|
43510
|
+
const prev = parent.previousElementSibling;
|
|
43511
|
+
if (prev.tagName === "LABEL" || prev.querySelector("label")) {
|
|
43512
|
+
const labelText = prev.textContent?.trim();
|
|
43513
|
+
if (labelText && labelText.length < 80) fieldLabel = labelText;
|
|
43514
|
+
}
|
|
43515
|
+
}
|
|
43348
43516
|
results.push({
|
|
43349
43517
|
options: opts.slice(0, 15),
|
|
43350
43518
|
triggerText,
|
|
43351
|
-
triggerRect: rect.width > 0 ? { x: rect.x, y: rect.y, width: rect.width, height: rect.height } : null
|
|
43519
|
+
triggerRect: rect.width > 0 ? { x: rect.x, y: rect.y, width: rect.width, height: rect.height } : null,
|
|
43520
|
+
fieldLabel
|
|
43352
43521
|
});
|
|
43353
43522
|
}
|
|
43354
43523
|
return results;
|
|
@@ -43360,7 +43529,7 @@ async function augmentHiddenSelectOptions(page, yaml, logger2) {
|
|
|
43360
43529
|
const elements = parseSnapshot(yaml);
|
|
43361
43530
|
let augmented = yaml;
|
|
43362
43531
|
for (const selectInfo of hiddenSelects) {
|
|
43363
|
-
const { options: opts, triggerText, triggerRect } = selectInfo;
|
|
43532
|
+
const { options: opts, triggerText, triggerRect, fieldLabel } = selectInfo;
|
|
43364
43533
|
if (!opts.length) continue;
|
|
43365
43534
|
let matchedRef = null;
|
|
43366
43535
|
if (triggerText) {
|
|
@@ -43409,11 +43578,13 @@ async function augmentHiddenSelectOptions(page, yaml, logger2) {
|
|
|
43409
43578
|
}
|
|
43410
43579
|
if (!matchedRef) continue;
|
|
43411
43580
|
const optionsValue = opts.join("|");
|
|
43412
|
-
augmented = updateElementLineByRef(
|
|
43413
|
-
|
|
43414
|
-
|
|
43415
|
-
|
|
43416
|
-
|
|
43581
|
+
augmented = updateElementLineByRef(augmented, matchedRef, (line) => {
|
|
43582
|
+
let next = appendAttributeIfMissing(line, "options", optionsValue);
|
|
43583
|
+
if (fieldLabel) {
|
|
43584
|
+
next = appendAttributeIfMissing(next, "field", fieldLabel);
|
|
43585
|
+
}
|
|
43586
|
+
return next;
|
|
43587
|
+
});
|
|
43417
43588
|
}
|
|
43418
43589
|
return augmented;
|
|
43419
43590
|
} catch (err) {
|
|
@@ -43469,38 +43640,6 @@ async function enrichInteractiveSVGElements(page, logger2) {
|
|
|
43469
43640
|
}
|
|
43470
43641
|
}
|
|
43471
43642
|
|
|
43472
|
-
// ../browser-core/src/playwright-client/download-utils.ts
|
|
43473
|
-
import * as path2 from "path";
|
|
43474
|
-
function formatFileSize(bytes) {
|
|
43475
|
-
if (bytes < 1024) return `${bytes}B`;
|
|
43476
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
43477
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
43478
|
-
}
|
|
43479
|
-
function guessMimeType(filename) {
|
|
43480
|
-
const ext = path2.extname(filename).toLowerCase();
|
|
43481
|
-
const mimeMap = {
|
|
43482
|
-
".pdf": "application/pdf",
|
|
43483
|
-
".txt": "text/plain",
|
|
43484
|
-
".csv": "text/csv",
|
|
43485
|
-
".json": "application/json",
|
|
43486
|
-
".xml": "application/xml",
|
|
43487
|
-
".html": "text/html",
|
|
43488
|
-
".htm": "text/html",
|
|
43489
|
-
".md": "text/markdown",
|
|
43490
|
-
".png": "image/png",
|
|
43491
|
-
".jpg": "image/jpeg",
|
|
43492
|
-
".jpeg": "image/jpeg",
|
|
43493
|
-
".gif": "image/gif",
|
|
43494
|
-
".svg": "image/svg+xml",
|
|
43495
|
-
".zip": "application/zip",
|
|
43496
|
-
".doc": "application/msword",
|
|
43497
|
-
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
43498
|
-
".xls": "application/vnd.ms-excel",
|
|
43499
|
-
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
43500
|
-
};
|
|
43501
|
-
return mimeMap[ext] ?? "application/octet-stream";
|
|
43502
|
-
}
|
|
43503
|
-
|
|
43504
43643
|
// ../browser-core/src/playwright-client/response-format.ts
|
|
43505
43644
|
var TOAST_SNAPSHOT_TTL = 5;
|
|
43506
43645
|
function formatMcpResponse(input) {
|
|
@@ -43509,7 +43648,8 @@ function formatMcpResponse(input) {
|
|
|
43509
43648
|
lines.push("### Toast Notifications");
|
|
43510
43649
|
for (const toast of input.capturedToasts) {
|
|
43511
43650
|
const remaining = toast.snapshotsRemaining ?? 1;
|
|
43512
|
-
|
|
43651
|
+
const placementHint = toast.placement ? ` [visible at (${toast.placement.x}, ${toast.placement.y}), ${toast.placement.width}\xD7${toast.placement.height}px]` : "";
|
|
43652
|
+
lines.push(`- [${toast.role}] ${toast.text}${placementHint} (expires in ${remaining} snapshot${remaining !== 1 ? "s" : ""})`);
|
|
43513
43653
|
}
|
|
43514
43654
|
lines.push("");
|
|
43515
43655
|
}
|
|
@@ -43558,17 +43698,184 @@ function formatMcpResponse(input) {
|
|
|
43558
43698
|
};
|
|
43559
43699
|
}
|
|
43560
43700
|
|
|
43701
|
+
// ../browser-core/src/playwright-client/launch-retry.ts
|
|
43702
|
+
var TRANSIENT_BROWSER_LAUNCH_PATTERNS = [
|
|
43703
|
+
/failed to connect/i,
|
|
43704
|
+
/syscall["':\s]+connect/i,
|
|
43705
|
+
/\bENOENT\b/i,
|
|
43706
|
+
/browser has been closed/i,
|
|
43707
|
+
/target page, context or browser has been closed/i,
|
|
43708
|
+
/failed to launch/i,
|
|
43709
|
+
/\bSIGKILL\b/i,
|
|
43710
|
+
/process was terminated/i
|
|
43711
|
+
];
|
|
43712
|
+
function formatBrowserLaunchError(error) {
|
|
43713
|
+
if (error instanceof Error) {
|
|
43714
|
+
const extra = error;
|
|
43715
|
+
const parts = [error.message];
|
|
43716
|
+
if (extra.code) parts.push(`code=${extra.code}`);
|
|
43717
|
+
if (typeof extra.errno === "number") parts.push(`errno=${extra.errno}`);
|
|
43718
|
+
if (extra.syscall) parts.push(`syscall=${extra.syscall}`);
|
|
43719
|
+
if (extra.cause) parts.push(`cause=${formatBrowserLaunchError(extra.cause)}`);
|
|
43720
|
+
return parts.join(" ");
|
|
43721
|
+
}
|
|
43722
|
+
return String(error);
|
|
43723
|
+
}
|
|
43724
|
+
function isTransientBrowserLaunchError(error) {
|
|
43725
|
+
const text = formatBrowserLaunchError(error);
|
|
43726
|
+
return TRANSIENT_BROWSER_LAUNCH_PATTERNS.some((pattern) => pattern.test(text));
|
|
43727
|
+
}
|
|
43728
|
+
async function withBrowserLaunchRetry(operation, options) {
|
|
43729
|
+
const maxAttempts = options.maxAttempts ?? 3;
|
|
43730
|
+
const initialDelayMs = options.initialDelayMs ?? 150;
|
|
43731
|
+
let lastError;
|
|
43732
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
43733
|
+
try {
|
|
43734
|
+
return await operation(attempt);
|
|
43735
|
+
} catch (error) {
|
|
43736
|
+
lastError = error;
|
|
43737
|
+
if (attempt >= maxAttempts || !isTransientBrowserLaunchError(error)) {
|
|
43738
|
+
throw error;
|
|
43739
|
+
}
|
|
43740
|
+
const delayMs = initialDelayMs * 2 ** (attempt - 1);
|
|
43741
|
+
options.logger.warn("[DirectPlaywright] Browser launch failed transiently, retrying", {
|
|
43742
|
+
label: options.label,
|
|
43743
|
+
attempt,
|
|
43744
|
+
nextAttempt: attempt + 1,
|
|
43745
|
+
delayMs,
|
|
43746
|
+
error: formatBrowserLaunchError(error)
|
|
43747
|
+
});
|
|
43748
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
43749
|
+
}
|
|
43750
|
+
}
|
|
43751
|
+
throw lastError;
|
|
43752
|
+
}
|
|
43753
|
+
|
|
43754
|
+
// ../browser-core/src/playwright-client/test-browser-lock.ts
|
|
43755
|
+
import * as fs3 from "fs/promises";
|
|
43756
|
+
import * as path3 from "path";
|
|
43757
|
+
var TEST_BROWSER_LOCK_DIR = path3.join(getCanaryTmpDir(), "playwright-test-browser-lock");
|
|
43758
|
+
var TEST_BROWSER_LOCK_METADATA_PATH = path3.join(TEST_BROWSER_LOCK_DIR, "owner.json");
|
|
43759
|
+
var TEST_BROWSER_LOCK_POLL_MS = 100;
|
|
43760
|
+
var TEST_BROWSER_LOCK_TIMEOUT_MS = 12e4;
|
|
43761
|
+
var TEST_BROWSER_LOCK_STALE_MS = 15 * 6e4;
|
|
43762
|
+
function shouldUseTestBrowserLock(options) {
|
|
43763
|
+
return process.env.NODE_ENV === "test" && !options.browserLease && !options.cdpUrl && options.browserMode !== "headed";
|
|
43764
|
+
}
|
|
43765
|
+
async function acquireTestBrowserLock(logger2) {
|
|
43766
|
+
const startedAt = Date.now();
|
|
43767
|
+
const owner = {
|
|
43768
|
+
pid: process.pid,
|
|
43769
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
43770
|
+
};
|
|
43771
|
+
while (true) {
|
|
43772
|
+
try {
|
|
43773
|
+
await fs3.mkdir(TEST_BROWSER_LOCK_DIR);
|
|
43774
|
+
await fs3.writeFile(TEST_BROWSER_LOCK_METADATA_PATH, JSON.stringify(owner), "utf8");
|
|
43775
|
+
logger2.debug("[DirectPlaywright] Acquired test browser lock", {
|
|
43776
|
+
lockDir: TEST_BROWSER_LOCK_DIR,
|
|
43777
|
+
pid: process.pid
|
|
43778
|
+
});
|
|
43779
|
+
let released = false;
|
|
43780
|
+
return async () => {
|
|
43781
|
+
if (released) return;
|
|
43782
|
+
released = true;
|
|
43783
|
+
try {
|
|
43784
|
+
await fs3.rm(TEST_BROWSER_LOCK_DIR, { recursive: true, force: true });
|
|
43785
|
+
logger2.debug("[DirectPlaywright] Released test browser lock", {
|
|
43786
|
+
lockDir: TEST_BROWSER_LOCK_DIR,
|
|
43787
|
+
pid: process.pid
|
|
43788
|
+
});
|
|
43789
|
+
} catch (error) {
|
|
43790
|
+
logger2.warn("[DirectPlaywright] Failed to release test browser lock", {
|
|
43791
|
+
lockDir: TEST_BROWSER_LOCK_DIR,
|
|
43792
|
+
pid: process.pid,
|
|
43793
|
+
error: error instanceof Error ? error.message : String(error)
|
|
43794
|
+
});
|
|
43795
|
+
}
|
|
43796
|
+
};
|
|
43797
|
+
} catch (error) {
|
|
43798
|
+
const code = error.code;
|
|
43799
|
+
if (code !== "EEXIST") {
|
|
43800
|
+
throw error;
|
|
43801
|
+
}
|
|
43802
|
+
await cleanupStaleTestBrowserLock(logger2);
|
|
43803
|
+
if (Date.now() - startedAt >= TEST_BROWSER_LOCK_TIMEOUT_MS) {
|
|
43804
|
+
throw new Error(
|
|
43805
|
+
`Timed out acquiring test browser lock after ${TEST_BROWSER_LOCK_TIMEOUT_MS}ms`
|
|
43806
|
+
);
|
|
43807
|
+
}
|
|
43808
|
+
await delay(TEST_BROWSER_LOCK_POLL_MS);
|
|
43809
|
+
}
|
|
43810
|
+
}
|
|
43811
|
+
}
|
|
43812
|
+
async function cleanupStaleTestBrowserLock(logger2) {
|
|
43813
|
+
const metadata = await readLockMetadata();
|
|
43814
|
+
if (!metadata) {
|
|
43815
|
+
const orphanedLockStats = await fs3.stat(TEST_BROWSER_LOCK_DIR).catch(() => null);
|
|
43816
|
+
if (!orphanedLockStats) {
|
|
43817
|
+
return;
|
|
43818
|
+
}
|
|
43819
|
+
const orphanedAgeMs = Date.now() - orphanedLockStats.mtimeMs;
|
|
43820
|
+
if (orphanedAgeMs < 1e3) {
|
|
43821
|
+
return;
|
|
43822
|
+
}
|
|
43823
|
+
logger2.warn("[DirectPlaywright] Removing orphaned test browser lock", {
|
|
43824
|
+
lockDir: TEST_BROWSER_LOCK_DIR,
|
|
43825
|
+
ageMs: orphanedAgeMs
|
|
43826
|
+
});
|
|
43827
|
+
await fs3.rm(TEST_BROWSER_LOCK_DIR, { recursive: true, force: true });
|
|
43828
|
+
return;
|
|
43829
|
+
}
|
|
43830
|
+
const ageMs = Date.now() - Date.parse(metadata.acquiredAt);
|
|
43831
|
+
if (ageMs < TEST_BROWSER_LOCK_STALE_MS && isProcessAlive(metadata.pid)) {
|
|
43832
|
+
return;
|
|
43833
|
+
}
|
|
43834
|
+
logger2.warn("[DirectPlaywright] Removing stale test browser lock", {
|
|
43835
|
+
lockDir: TEST_BROWSER_LOCK_DIR,
|
|
43836
|
+
ownerPid: metadata.pid,
|
|
43837
|
+
ageMs
|
|
43838
|
+
});
|
|
43839
|
+
await fs3.rm(TEST_BROWSER_LOCK_DIR, { recursive: true, force: true });
|
|
43840
|
+
}
|
|
43841
|
+
async function readLockMetadata() {
|
|
43842
|
+
try {
|
|
43843
|
+
const raw = await fs3.readFile(TEST_BROWSER_LOCK_METADATA_PATH, "utf8");
|
|
43844
|
+
return JSON.parse(raw);
|
|
43845
|
+
} catch {
|
|
43846
|
+
return null;
|
|
43847
|
+
}
|
|
43848
|
+
}
|
|
43849
|
+
function isProcessAlive(pid) {
|
|
43850
|
+
try {
|
|
43851
|
+
process.kill(pid, 0);
|
|
43852
|
+
return true;
|
|
43853
|
+
} catch (error) {
|
|
43854
|
+
const code = error.code;
|
|
43855
|
+
return code !== "ESRCH";
|
|
43856
|
+
}
|
|
43857
|
+
}
|
|
43858
|
+
function delay(ms) {
|
|
43859
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
43860
|
+
}
|
|
43861
|
+
|
|
43561
43862
|
// ../browser-core/src/playwright-client.ts
|
|
43562
43863
|
var PlaywrightClient = class _PlaywrightClient {
|
|
43563
43864
|
disconnectInProgress = false;
|
|
43564
43865
|
browserLease;
|
|
43866
|
+
releaseTestBrowserLock = null;
|
|
43565
43867
|
logger;
|
|
43566
43868
|
screencastEncoderFactory;
|
|
43869
|
+
tmpBaseDir;
|
|
43567
43870
|
constructor(options) {
|
|
43568
43871
|
this.browserLease = options?.browserLease ?? null;
|
|
43569
43872
|
this.logger = options?.logger ?? consoleLogger;
|
|
43570
43873
|
this.screencastEncoderFactory = options?.screencastEncoderFactory ?? null;
|
|
43571
43874
|
this.cursorOverlay = new CursorOverlay({ enabled: false });
|
|
43875
|
+
if (!options?.tmpBaseDir) {
|
|
43876
|
+
this.logger.debug("[PlaywrightClient] No tmpBaseDir provided, using flat canary dir (not org-scoped)");
|
|
43877
|
+
}
|
|
43878
|
+
this.tmpBaseDir = options?.tmpBaseDir ?? getCanaryTmpDir();
|
|
43572
43879
|
}
|
|
43573
43880
|
/** Assign a stable monotonic ID to a page and return it. */
|
|
43574
43881
|
_assignPageId(page) {
|
|
@@ -43718,8 +44025,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43718
44025
|
const cursorOpts = typeof cursorOverlay === "object" ? cursorOverlay : {};
|
|
43719
44026
|
this.cursorOverlay = new CursorOverlay({ ...cursorOpts, enabled: cursorEnabled });
|
|
43720
44027
|
}
|
|
43721
|
-
this._downloadDir =
|
|
43722
|
-
await
|
|
44028
|
+
this._downloadDir = path4.join(this.tmpBaseDir, `playwright-downloads-${Date.now()}`);
|
|
44029
|
+
await fs4.mkdir(this._downloadDir, { recursive: true });
|
|
43723
44030
|
this.logger.info("[DirectPlaywright] Launching browser", {
|
|
43724
44031
|
browserMode: resolvedBrowserMode,
|
|
43725
44032
|
hasStorageState: !!storageStatePath,
|
|
@@ -43730,82 +44037,100 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43730
44037
|
highlightEnabled: this.highlightEnabled,
|
|
43731
44038
|
downloadDir: this._downloadDir
|
|
43732
44039
|
});
|
|
43733
|
-
|
|
43734
|
-
|
|
43735
|
-
|
|
43736
|
-
|
|
43737
|
-
|
|
43738
|
-
|
|
43739
|
-
|
|
43740
|
-
|
|
43741
|
-
|
|
43742
|
-
|
|
43743
|
-
|
|
43744
|
-
|
|
43745
|
-
|
|
43746
|
-
|
|
43747
|
-
|
|
43748
|
-
|
|
43749
|
-
|
|
43750
|
-
|
|
43751
|
-
|
|
43752
|
-
|
|
44040
|
+
try {
|
|
44041
|
+
if (shouldUseTestBrowserLock({
|
|
44042
|
+
browserLease: !!this.browserLease,
|
|
44043
|
+
cdpUrl,
|
|
44044
|
+
browserMode: resolvedBrowserMode
|
|
44045
|
+
}) && !this.releaseTestBrowserLock) {
|
|
44046
|
+
this.releaseTestBrowserLock = await acquireTestBrowserLock(this.logger);
|
|
44047
|
+
}
|
|
44048
|
+
if (cdpUrl) {
|
|
44049
|
+
this.logger.info("[DirectPlaywright] Connecting via CDP", { cdpUrl });
|
|
44050
|
+
this.browser = await this.withOperationTimeout(
|
|
44051
|
+
playwrightChromium.connectOverCDP(cdpUrl),
|
|
44052
|
+
3e4,
|
|
44053
|
+
"[DirectPlaywright] connectOverCDP"
|
|
44054
|
+
);
|
|
44055
|
+
const existingContexts = this.browser.contexts();
|
|
44056
|
+
this.context = existingContexts[0] ?? await this.browser.newContext({ viewport: resolvedViewport });
|
|
44057
|
+
} else if (this.browserLease && !this.stealthEnabled && !this.extensionsEnabled && resolvedBrowserMode !== "headed") {
|
|
44058
|
+
const videoConfig2 = this.resolveVideoConfig(recordVideo);
|
|
44059
|
+
const contextOptions = {
|
|
44060
|
+
viewport: resolvedViewport,
|
|
44061
|
+
acceptDownloads: true
|
|
44062
|
+
};
|
|
44063
|
+
if (storageStatePath) {
|
|
44064
|
+
try {
|
|
44065
|
+
await fs4.access(storageStatePath);
|
|
44066
|
+
contextOptions.storageState = storageStatePath;
|
|
44067
|
+
} catch {
|
|
44068
|
+
}
|
|
43753
44069
|
}
|
|
43754
|
-
|
|
43755
|
-
|
|
43756
|
-
|
|
43757
|
-
|
|
43758
|
-
|
|
43759
|
-
|
|
43760
|
-
|
|
43761
|
-
|
|
43762
|
-
|
|
43763
|
-
this.logger.info("[DirectPlaywright] Using pooled browser via lease", {
|
|
43764
|
-
leaseId: this.browserLease.leaseId,
|
|
43765
|
-
browserId: this.browserLease.browserId
|
|
43766
|
-
});
|
|
43767
|
-
this.context = await this.withOperationTimeout(
|
|
43768
|
-
this.browserLease.createContext(contextOptions),
|
|
43769
|
-
3e4,
|
|
43770
|
-
"[DirectPlaywright] browserLease.createContext"
|
|
43771
|
-
);
|
|
43772
|
-
this.browser = null;
|
|
43773
|
-
} else {
|
|
43774
|
-
if (this.browserLease) {
|
|
43775
|
-
this.logger.info("[DirectPlaywright] Releasing pool lease for direct launch", {
|
|
44070
|
+
if (videoConfig2) {
|
|
44071
|
+
await fs4.mkdir(videoConfig2.dir, { recursive: true });
|
|
44072
|
+
contextOptions.recordVideo = videoConfig2;
|
|
44073
|
+
this.videoDir = videoConfig2.dir;
|
|
44074
|
+
}
|
|
44075
|
+
if (extraHTTPHeaders && Object.keys(extraHTTPHeaders).length > 0) {
|
|
44076
|
+
contextOptions.extraHTTPHeaders = extraHTTPHeaders;
|
|
44077
|
+
}
|
|
44078
|
+
this.logger.info("[DirectPlaywright] Using pooled browser via lease", {
|
|
43776
44079
|
leaseId: this.browserLease.leaseId,
|
|
43777
|
-
|
|
44080
|
+
browserId: this.browserLease.browserId
|
|
43778
44081
|
});
|
|
43779
|
-
await this.
|
|
43780
|
-
|
|
44082
|
+
this.context = await this.withOperationTimeout(
|
|
44083
|
+
this.browserLease.createContext(contextOptions),
|
|
44084
|
+
3e4,
|
|
44085
|
+
"[DirectPlaywright] browserLease.createContext"
|
|
44086
|
+
);
|
|
44087
|
+
this.browser = null;
|
|
44088
|
+
} else {
|
|
44089
|
+
if (this.browserLease) {
|
|
44090
|
+
this.logger.info("[DirectPlaywright] Releasing pool lease for direct launch", {
|
|
44091
|
+
leaseId: this.browserLease.leaseId,
|
|
44092
|
+
reason: resolvedBrowserMode === "headed" ? "headed-mode" : "requires-dedicated-browser"
|
|
44093
|
+
});
|
|
44094
|
+
await this.browserLease.release();
|
|
44095
|
+
this.browserLease = null;
|
|
44096
|
+
}
|
|
44097
|
+
const { browser, context } = await withBrowserLaunchRetry(
|
|
44098
|
+
() => this.launchBrowser({
|
|
44099
|
+
browserMode: resolvedBrowserMode,
|
|
44100
|
+
storageStatePath,
|
|
44101
|
+
viewport,
|
|
44102
|
+
recordVideo,
|
|
44103
|
+
stealth,
|
|
44104
|
+
extensions,
|
|
44105
|
+
extraHTTPHeaders
|
|
44106
|
+
}),
|
|
44107
|
+
{
|
|
44108
|
+
logger: this.logger,
|
|
44109
|
+
label: "direct-launch"
|
|
44110
|
+
}
|
|
44111
|
+
);
|
|
44112
|
+
this.browser = browser;
|
|
44113
|
+
this.context = context;
|
|
43781
44114
|
}
|
|
43782
|
-
|
|
44115
|
+
this.attachContextListeners(this.context);
|
|
44116
|
+
if (this.browser) {
|
|
44117
|
+
this.attachBrowserListeners(this.browser);
|
|
44118
|
+
}
|
|
44119
|
+
await this.createPageWithListeners(this.context, "initial_connect");
|
|
44120
|
+
const now = Date.now();
|
|
44121
|
+
const initialPageId = this._assignPageId(this.page);
|
|
44122
|
+
this._pageCreationTimes.set(initialPageId, now);
|
|
44123
|
+
this._tabFocusLog.push({ pageIndex: initialPageId, timestamp: now });
|
|
44124
|
+
this.logger.info("[DirectPlaywright] Browser connected successfully", {
|
|
43783
44125
|
browserMode: resolvedBrowserMode,
|
|
43784
|
-
|
|
43785
|
-
|
|
43786
|
-
|
|
43787
|
-
stealth,
|
|
43788
|
-
extensions,
|
|
43789
|
-
extraHTTPHeaders
|
|
44126
|
+
stealthEnabled: this.stealthEnabled,
|
|
44127
|
+
extensionsEnabled: this.extensionsEnabled,
|
|
44128
|
+
pooled: !!this.browserLease
|
|
43790
44129
|
});
|
|
43791
|
-
|
|
43792
|
-
this.
|
|
43793
|
-
|
|
43794
|
-
this.attachContextListeners(this.context);
|
|
43795
|
-
if (this.browser) {
|
|
43796
|
-
this.attachBrowserListeners(this.browser);
|
|
44130
|
+
} catch (error) {
|
|
44131
|
+
await this.cleanupFailedConnect(error);
|
|
44132
|
+
throw error;
|
|
43797
44133
|
}
|
|
43798
|
-
await this.createPageWithListeners(this.context, "initial_connect");
|
|
43799
|
-
const now = Date.now();
|
|
43800
|
-
const initialPageId = this._assignPageId(this.page);
|
|
43801
|
-
this._pageCreationTimes.set(initialPageId, now);
|
|
43802
|
-
this._tabFocusLog.push({ pageIndex: initialPageId, timestamp: now });
|
|
43803
|
-
this.logger.info("[DirectPlaywright] Browser connected successfully", {
|
|
43804
|
-
browserMode: resolvedBrowserMode,
|
|
43805
|
-
stealthEnabled: this.stealthEnabled,
|
|
43806
|
-
extensionsEnabled: this.extensionsEnabled,
|
|
43807
|
-
pooled: !!this.browserLease
|
|
43808
|
-
});
|
|
43809
44134
|
}
|
|
43810
44135
|
supportsContextSwap() {
|
|
43811
44136
|
return !this.extensionsEnabled && (!!this.browser || !!this.browserLease);
|
|
@@ -43877,7 +44202,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43877
44202
|
}
|
|
43878
44203
|
if (nextStorageStatePath) {
|
|
43879
44204
|
try {
|
|
43880
|
-
await
|
|
44205
|
+
await fs4.access(nextStorageStatePath);
|
|
43881
44206
|
contextOptions.storageState = nextStorageStatePath;
|
|
43882
44207
|
this.logger.debug("[DirectPlaywright] Loading storage state for swapped context", {
|
|
43883
44208
|
storageStatePath: nextStorageStatePath
|
|
@@ -43898,7 +44223,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43898
44223
|
this._pageCreationTimes.clear();
|
|
43899
44224
|
this._closedPageVideos = [];
|
|
43900
44225
|
if (videoConfig) {
|
|
43901
|
-
await
|
|
44226
|
+
await fs4.mkdir(videoConfig.dir, { recursive: true });
|
|
43902
44227
|
contextOptions.recordVideo = videoConfig;
|
|
43903
44228
|
this.videoDir = videoConfig.dir;
|
|
43904
44229
|
this.highlightEnabled = true;
|
|
@@ -43955,6 +44280,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43955
44280
|
this.logger.debug("[DirectPlaywright] Stealth plugin applied");
|
|
43956
44281
|
}
|
|
43957
44282
|
const chromiumLauncher = useStealthMode ? chromium : playwrightChromium;
|
|
44283
|
+
const executablePath = await _PlaywrightClient.resolveChromiumExecutable(this.logger);
|
|
43958
44284
|
const args = ["--no-sandbox", "--disable-dev-shm-usage"];
|
|
43959
44285
|
if (browserMode === "headed" && process.platform === "darwin") {
|
|
43960
44286
|
args.push(
|
|
@@ -43976,7 +44302,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43976
44302
|
}
|
|
43977
44303
|
if (storageStatePath) {
|
|
43978
44304
|
try {
|
|
43979
|
-
await
|
|
44305
|
+
await fs4.access(storageStatePath);
|
|
43980
44306
|
contextOptions.storageState = storageStatePath;
|
|
43981
44307
|
this.logger.debug("[DirectPlaywright] Loading storage state from file", {
|
|
43982
44308
|
storageStatePath
|
|
@@ -43988,7 +44314,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43988
44314
|
}
|
|
43989
44315
|
}
|
|
43990
44316
|
if (videoConfig) {
|
|
43991
|
-
await
|
|
44317
|
+
await fs4.mkdir(videoConfig.dir, { recursive: true });
|
|
43992
44318
|
contextOptions.recordVideo = videoConfig;
|
|
43993
44319
|
this.videoDir = videoConfig.dir;
|
|
43994
44320
|
this.logger.info("[DirectPlaywright] Video recording enabled", {
|
|
@@ -43997,9 +44323,9 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
43997
44323
|
});
|
|
43998
44324
|
}
|
|
43999
44325
|
if (hasExtensions) {
|
|
44000
|
-
this.userDataDir = extensions.userDataDir ||
|
|
44326
|
+
this.userDataDir = extensions.userDataDir || path4.join(this.tmpBaseDir, `playwright-userdata-${Date.now()}`);
|
|
44001
44327
|
this.shouldCleanupUserDataDir = !extensions.persistUserData;
|
|
44002
|
-
await
|
|
44328
|
+
await fs4.mkdir(this.userDataDir, { recursive: true });
|
|
44003
44329
|
if (browserMode === "headless") {
|
|
44004
44330
|
args.push("--headless=new");
|
|
44005
44331
|
}
|
|
@@ -44015,6 +44341,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44015
44341
|
headless: false,
|
|
44016
44342
|
// We use --headless=new in args for extension support
|
|
44017
44343
|
args,
|
|
44344
|
+
...executablePath ? { executablePath } : {},
|
|
44018
44345
|
...contextOptions
|
|
44019
44346
|
}),
|
|
44020
44347
|
3e4,
|
|
@@ -44025,7 +44352,8 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44025
44352
|
const browser = await this.withOperationTimeout(
|
|
44026
44353
|
chromiumLauncher.launch({
|
|
44027
44354
|
headless: browserMode === "headless",
|
|
44028
|
-
args
|
|
44355
|
+
args,
|
|
44356
|
+
...executablePath ? { executablePath } : {}
|
|
44029
44357
|
}),
|
|
44030
44358
|
3e4,
|
|
44031
44359
|
"[DirectPlaywright] chromium.launch"
|
|
@@ -44037,6 +44365,68 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44037
44365
|
);
|
|
44038
44366
|
return { browser, context };
|
|
44039
44367
|
}
|
|
44368
|
+
/**
|
|
44369
|
+
* Resolve a working Chromium executable path, handling version mismatches
|
|
44370
|
+
* between the Playwright version bundled in this package and the browser
|
|
44371
|
+
* binaries installed on the system.
|
|
44372
|
+
*
|
|
44373
|
+
* When the exact expected binary doesn't exist (e.g. Playwright expects
|
|
44374
|
+
* chromium-1191 but only chromium-1194 is installed), this finds the
|
|
44375
|
+
* newest available chromium binary as a fallback.
|
|
44376
|
+
*/
|
|
44377
|
+
static async resolveChromiumExecutable(logger2) {
|
|
44378
|
+
const defaultPath = playwrightChromium.executablePath();
|
|
44379
|
+
try {
|
|
44380
|
+
await fs4.access(defaultPath);
|
|
44381
|
+
return void 0;
|
|
44382
|
+
} catch {
|
|
44383
|
+
}
|
|
44384
|
+
const parts = defaultPath.split(path4.sep);
|
|
44385
|
+
const msPlaywrightIdx = parts.findIndex((p) => p === "ms-playwright");
|
|
44386
|
+
if (msPlaywrightIdx === -1) {
|
|
44387
|
+
logger2.warn("[DirectPlaywright] Cannot locate ms-playwright cache directory", {
|
|
44388
|
+
defaultPath
|
|
44389
|
+
});
|
|
44390
|
+
return void 0;
|
|
44391
|
+
}
|
|
44392
|
+
const cacheDir = parts.slice(0, msPlaywrightIdx + 1).join(path4.sep);
|
|
44393
|
+
const relativeBinaryPath = parts.slice(msPlaywrightIdx + 2).join(path4.sep);
|
|
44394
|
+
try {
|
|
44395
|
+
const entries = await fs4.readdir(cacheDir);
|
|
44396
|
+
const chromiumDirs = entries.filter((e) => e.startsWith("chromium-") && !e.includes("headless")).sort((a, b) => {
|
|
44397
|
+
const revA = parseInt(a.split("-")[1] ?? "0", 10);
|
|
44398
|
+
const revB = parseInt(b.split("-")[1] ?? "0", 10);
|
|
44399
|
+
return revB - revA;
|
|
44400
|
+
});
|
|
44401
|
+
for (const dir of chromiumDirs) {
|
|
44402
|
+
const candidate = path4.join(cacheDir, dir, relativeBinaryPath);
|
|
44403
|
+
try {
|
|
44404
|
+
await fs4.access(candidate);
|
|
44405
|
+
logger2.warn(
|
|
44406
|
+
"[DirectPlaywright] Using fallback Chromium binary (version mismatch)",
|
|
44407
|
+
{
|
|
44408
|
+
expected: defaultPath,
|
|
44409
|
+
using: candidate
|
|
44410
|
+
}
|
|
44411
|
+
);
|
|
44412
|
+
return candidate;
|
|
44413
|
+
} catch {
|
|
44414
|
+
continue;
|
|
44415
|
+
}
|
|
44416
|
+
}
|
|
44417
|
+
logger2.warn("[DirectPlaywright] No compatible Chromium binary found", {
|
|
44418
|
+
cacheDir,
|
|
44419
|
+
candidates: chromiumDirs,
|
|
44420
|
+
expectedRelativePath: relativeBinaryPath
|
|
44421
|
+
});
|
|
44422
|
+
} catch (err) {
|
|
44423
|
+
logger2.warn("[DirectPlaywright] Failed to scan browser cache directory", {
|
|
44424
|
+
cacheDir,
|
|
44425
|
+
error: String(err)
|
|
44426
|
+
});
|
|
44427
|
+
}
|
|
44428
|
+
return void 0;
|
|
44429
|
+
}
|
|
44040
44430
|
async disconnect() {
|
|
44041
44431
|
this.logger.info("[DirectPlaywright] Disconnecting");
|
|
44042
44432
|
this.disconnectInProgress = true;
|
|
@@ -44096,7 +44486,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44096
44486
|
this.lastSnapshotYaml = "";
|
|
44097
44487
|
if (this._downloadDir) {
|
|
44098
44488
|
try {
|
|
44099
|
-
await
|
|
44489
|
+
await fs4.rm(this._downloadDir, { recursive: true, force: true });
|
|
44100
44490
|
this.logger.debug("[DirectPlaywright] Cleaned up download directory", {
|
|
44101
44491
|
downloadDir: this._downloadDir
|
|
44102
44492
|
});
|
|
@@ -44108,12 +44498,26 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44108
44498
|
}
|
|
44109
44499
|
this._downloadDir = null;
|
|
44110
44500
|
}
|
|
44501
|
+
if (this.traceDir) {
|
|
44502
|
+
try {
|
|
44503
|
+
await fs4.rm(this.traceDir, { recursive: true, force: true });
|
|
44504
|
+
this.logger.debug("[DirectPlaywright] Cleaned up trace directory", {
|
|
44505
|
+
traceDir: this.traceDir
|
|
44506
|
+
});
|
|
44507
|
+
} catch (err) {
|
|
44508
|
+
this.logger.warn("[DirectPlaywright] Failed to clean up trace directory", {
|
|
44509
|
+
traceDir: this.traceDir,
|
|
44510
|
+
error: err instanceof Error ? err.message : String(err)
|
|
44511
|
+
});
|
|
44512
|
+
}
|
|
44513
|
+
this.traceDir = null;
|
|
44514
|
+
}
|
|
44111
44515
|
this._capturedDownloads = [];
|
|
44112
44516
|
this._downloadCounter = 0;
|
|
44113
44517
|
this._lastReportedDownloadIndex = 0;
|
|
44114
44518
|
if (this.shouldCleanupUserDataDir && this.userDataDir) {
|
|
44115
44519
|
try {
|
|
44116
|
-
await
|
|
44520
|
+
await fs4.rm(this.userDataDir, { recursive: true, force: true });
|
|
44117
44521
|
this.logger.debug("[DirectPlaywright] Cleaned up user data directory", {
|
|
44118
44522
|
userDataDir: this.userDataDir
|
|
44119
44523
|
});
|
|
@@ -44127,7 +44531,7 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44127
44531
|
if (this.snapshotFilePaths.size > 0) {
|
|
44128
44532
|
for (const filePath of this.snapshotFilePaths) {
|
|
44129
44533
|
try {
|
|
44130
|
-
await
|
|
44534
|
+
await fs4.unlink(filePath);
|
|
44131
44535
|
} catch (err) {
|
|
44132
44536
|
this.logger.warn("[DirectPlaywright] Failed to clean up snapshot file", {
|
|
44133
44537
|
filePath,
|
|
@@ -44146,11 +44550,33 @@ var PlaywrightClient = class _PlaywrightClient {
|
|
|
44146
44550
|
this.stealthEnabled = false;
|
|
44147
44551
|
this.logger.info("[DirectPlaywright] Disconnected");
|
|
44148
44552
|
} finally {
|
|
44553
|
+
await this.releaseTestBrowserLockIfHeld();
|
|
44149
44554
|
this.contextClosedIntentionally = false;
|
|
44150
44555
|
this.pageClosedIntentionally = false;
|
|
44151
44556
|
this.disconnectInProgress = false;
|
|
44152
44557
|
}
|
|
44153
44558
|
}
|
|
44559
|
+
async cleanupFailedConnect(error) {
|
|
44560
|
+
this.logger.warn("[DirectPlaywright] Cleaning up after failed connect", {
|
|
44561
|
+
error: error instanceof Error ? error.message : String(error)
|
|
44562
|
+
});
|
|
44563
|
+
try {
|
|
44564
|
+
await this.disconnect();
|
|
44565
|
+
} catch (disconnectError) {
|
|
44566
|
+
this.logger.warn("[DirectPlaywright] Failed cleanup after connect error", {
|
|
44567
|
+
error: disconnectError instanceof Error ? disconnectError.message : String(disconnectError)
|
|
44568
|
+
});
|
|
44569
|
+
await this.releaseTestBrowserLockIfHeld();
|
|
44570
|
+
}
|
|
44571
|
+
}
|
|
44572
|
+
async releaseTestBrowserLockIfHeld() {
|
|
44573
|
+
if (!this.releaseTestBrowserLock) {
|
|
44574
|
+
return;
|
|
44575
|
+
}
|
|
44576
|
+
const release = this.releaseTestBrowserLock;
|
|
44577
|
+
this.releaseTestBrowserLock = null;
|
|
44578
|
+
await release();
|
|
44579
|
+
}
|
|
44154
44580
|
// ================ NAVIGATION ================
|
|
44155
44581
|
async navigate(url, opts) {
|
|
44156
44582
|
const dialogMsg = this.getPendingDialogMessage();
|
|
@@ -44423,8 +44849,8 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
44423
44849
|
}
|
|
44424
44850
|
const sampleUrls = pendingRequests.slice(0, 3).map((url) => {
|
|
44425
44851
|
try {
|
|
44426
|
-
const
|
|
44427
|
-
return
|
|
44852
|
+
const path5 = new URL(url).pathname + new URL(url).search;
|
|
44853
|
+
return path5.length > 60 ? path5.slice(0, 57) + "..." : path5;
|
|
44428
44854
|
} catch {
|
|
44429
44855
|
return url.length > 60 ? url.slice(0, 57) + "..." : url;
|
|
44430
44856
|
}
|
|
@@ -45099,7 +45525,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45099
45525
|
const video = closingPage.video();
|
|
45100
45526
|
if (video) {
|
|
45101
45527
|
const videoFileName = `video-tab${closePageId}-${Date.now()}.webm`;
|
|
45102
|
-
const savePath =
|
|
45528
|
+
const savePath = path4.join(this.videoDir, videoFileName);
|
|
45103
45529
|
await closingPage.close();
|
|
45104
45530
|
await video.saveAs(savePath);
|
|
45105
45531
|
const createdAt = this._pageCreationTimes.get(closePageId) ?? Date.now();
|
|
@@ -45196,8 +45622,8 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45196
45622
|
const timestamp = Date.now();
|
|
45197
45623
|
const shortId = crypto.randomUUID().slice(0, 8);
|
|
45198
45624
|
const filename = `snapshot-${timestamp}-${shortId}.yaml`;
|
|
45199
|
-
const filePath =
|
|
45200
|
-
await
|
|
45625
|
+
const filePath = path4.join(this.tmpBaseDir, filename);
|
|
45626
|
+
await fs4.writeFile(filePath, yaml, "utf-8");
|
|
45201
45627
|
this.snapshotFilePaths.add(filePath);
|
|
45202
45628
|
this.logger.debug("[DirectPlaywright] Wrote snapshot to disk", {
|
|
45203
45629
|
filePath,
|
|
@@ -45341,8 +45767,8 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45341
45767
|
async startTracing(_opts) {
|
|
45342
45768
|
const context = await this.getContext();
|
|
45343
45769
|
this.logger.info("[DirectPlaywright] Starting trace recording");
|
|
45344
|
-
this.traceDir =
|
|
45345
|
-
await
|
|
45770
|
+
this.traceDir = path4.join(this.tmpBaseDir, `playwright-trace-${Date.now()}`);
|
|
45771
|
+
await fs4.mkdir(this.traceDir, { recursive: true });
|
|
45346
45772
|
await context.tracing.start({ screenshots: true, snapshots: true });
|
|
45347
45773
|
this.tracingActive = true;
|
|
45348
45774
|
}
|
|
@@ -45358,7 +45784,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
45358
45784
|
const context = await this.getContext();
|
|
45359
45785
|
if (!this.traceDir) throw new Error("Tracing not started");
|
|
45360
45786
|
this.logger.info("[DirectPlaywright] Stopping trace recording");
|
|
45361
|
-
const tracePath =
|
|
45787
|
+
const tracePath = path4.join(this.traceDir, "trace.zip");
|
|
45362
45788
|
await context.tracing.stop({ path: tracePath });
|
|
45363
45789
|
this.tracingActive = false;
|
|
45364
45790
|
return {
|
|
@@ -46022,18 +46448,18 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46022
46448
|
this.logger.error("[DirectPlaywright] Download failed: no download directory", { id });
|
|
46023
46449
|
return;
|
|
46024
46450
|
}
|
|
46025
|
-
const savePath =
|
|
46451
|
+
const savePath = path4.join(this._downloadDir, `${id}-${suggestedFilename}`);
|
|
46026
46452
|
download.saveAs(savePath).then(
|
|
46027
46453
|
async () => {
|
|
46028
46454
|
try {
|
|
46029
|
-
const
|
|
46455
|
+
const stat3 = await fs4.stat(savePath);
|
|
46030
46456
|
entry.savedPath = savePath;
|
|
46031
|
-
entry.sizeBytes =
|
|
46457
|
+
entry.sizeBytes = stat3.size;
|
|
46032
46458
|
entry.completed = true;
|
|
46033
46459
|
this.logger.info("[DirectPlaywright] Download completed", {
|
|
46034
46460
|
id,
|
|
46035
46461
|
suggestedFilename,
|
|
46036
|
-
sizeBytes:
|
|
46462
|
+
sizeBytes: stat3.size,
|
|
46037
46463
|
savedPath: savePath
|
|
46038
46464
|
});
|
|
46039
46465
|
} catch {
|
|
@@ -46175,13 +46601,13 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46175
46601
|
};
|
|
46176
46602
|
if (ssp) {
|
|
46177
46603
|
try {
|
|
46178
|
-
await
|
|
46604
|
+
await fs4.access(ssp);
|
|
46179
46605
|
ctxOpts.storageState = ssp;
|
|
46180
46606
|
} catch {
|
|
46181
46607
|
}
|
|
46182
46608
|
}
|
|
46183
46609
|
if (videoConfig2) {
|
|
46184
|
-
await
|
|
46610
|
+
await fs4.mkdir(videoConfig2.dir, { recursive: true });
|
|
46185
46611
|
ctxOpts.recordVideo = videoConfig2;
|
|
46186
46612
|
}
|
|
46187
46613
|
if (headers && Object.keys(headers).length > 0) {
|
|
@@ -46207,7 +46633,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46207
46633
|
}
|
|
46208
46634
|
if (this.shouldCleanupUserDataDir && this.userDataDir) {
|
|
46209
46635
|
try {
|
|
46210
|
-
await
|
|
46636
|
+
await fs4.rm(this.userDataDir, { recursive: true, force: true });
|
|
46211
46637
|
} catch {
|
|
46212
46638
|
}
|
|
46213
46639
|
this.userDataDir = null;
|
|
@@ -46296,7 +46722,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46296
46722
|
*/
|
|
46297
46723
|
resolveVideoConfig(recordVideo) {
|
|
46298
46724
|
if (!recordVideo) return null;
|
|
46299
|
-
const dir = recordVideo === true || !recordVideo.dir ?
|
|
46725
|
+
const dir = recordVideo === true || !recordVideo.dir ? path4.join(this.tmpBaseDir, `playwright-video-${Date.now()}`) : recordVideo.dir;
|
|
46300
46726
|
const size = recordVideo !== true && recordVideo.size ? recordVideo.size : DEFAULT_VIEWPORT;
|
|
46301
46727
|
return { dir, size };
|
|
46302
46728
|
}
|
|
@@ -46355,7 +46781,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46355
46781
|
for (const handle of videoHandles) {
|
|
46356
46782
|
try {
|
|
46357
46783
|
const videoFileName = `video-tab${handle.pageIndex}-${timestamp}.webm`;
|
|
46358
|
-
const savePath =
|
|
46784
|
+
const savePath = path4.join(this.videoDir, videoFileName);
|
|
46359
46785
|
await handle.video.saveAs(savePath);
|
|
46360
46786
|
const createdAt = this._pageCreationTimes.get(handle.pageIndex) ?? timestamp;
|
|
46361
46787
|
allPageVideos.push({
|
|
@@ -46421,7 +46847,14 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46421
46847
|
);
|
|
46422
46848
|
return null;
|
|
46423
46849
|
}
|
|
46850
|
+
// ================ TOASTS ================
|
|
46851
|
+
getCapturedToasts() {
|
|
46852
|
+
return this._lastCapturedToasts;
|
|
46853
|
+
}
|
|
46424
46854
|
// ================ DOWNLOADS ================
|
|
46855
|
+
getCapturedDownloads() {
|
|
46856
|
+
return this._capturedDownloads;
|
|
46857
|
+
}
|
|
46425
46858
|
async listDownloads() {
|
|
46426
46859
|
if (this._capturedDownloads.length === 0) {
|
|
46427
46860
|
return "No downloads captured during this session.";
|
|
@@ -46462,7 +46895,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46462
46895
|
const filename = target.suggestedFilename;
|
|
46463
46896
|
const sizeBytes = target.sizeBytes ?? 0;
|
|
46464
46897
|
const mimeType = this.guessMimeType(filename);
|
|
46465
|
-
const ext =
|
|
46898
|
+
const ext = path4.extname(filename).toLowerCase();
|
|
46466
46899
|
if (ext === ".pdf") {
|
|
46467
46900
|
const { extractPdfText: extractPdfText2 } = await import("./pdf-extract-XYDS42VL.js");
|
|
46468
46901
|
const { text } = await extractPdfText2(target.savedPath);
|
|
@@ -46483,7 +46916,7 @@ Use coordinate-based clicking (x, y) to interact with elements visible in the sc
|
|
|
46483
46916
|
".svg"
|
|
46484
46917
|
]);
|
|
46485
46918
|
if (textExtensions.has(ext)) {
|
|
46486
|
-
const content = await
|
|
46919
|
+
const content = await fs4.readFile(target.savedPath, "utf-8");
|
|
46487
46920
|
return { filename, sizeBytes, mimeType, textContent: content };
|
|
46488
46921
|
}
|
|
46489
46922
|
return { filename, sizeBytes, mimeType, textContent: null };
|
|
@@ -46594,6 +47027,7 @@ export {
|
|
|
46594
47027
|
compareSnapshots,
|
|
46595
47028
|
hasDiffChanges,
|
|
46596
47029
|
formatSemanticDiff,
|
|
47030
|
+
guessMimeType,
|
|
46597
47031
|
captureElementAtPoint,
|
|
46598
47032
|
AUTO_SNAPSHOT_MARKER,
|
|
46599
47033
|
isMCPContentWithImages,
|
|
@@ -46890,4 +47324,4 @@ playwright-extra/dist/index.esm.js:
|
|
|
46890
47324
|
* @license MIT
|
|
46891
47325
|
*)
|
|
46892
47326
|
*/
|
|
46893
|
-
//# sourceMappingURL=chunk-
|
|
47327
|
+
//# sourceMappingURL=chunk-FK3EZADZ.js.map
|