cbrowser 14.2.2 → 14.2.4
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/analysis/agent-ready-audit.d.ts.map +1 -1
- package/dist/analysis/agent-ready-audit.js +5 -3
- package/dist/analysis/agent-ready-audit.js.map +1 -1
- package/dist/analysis/chaos-testing.d.ts.map +1 -1
- package/dist/analysis/chaos-testing.js +19 -0
- package/dist/analysis/chaos-testing.js.map +1 -1
- package/dist/analysis/natural-language.d.ts.map +1 -1
- package/dist/analysis/natural-language.js +28 -3
- package/dist/analysis/natural-language.js.map +1 -1
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +70 -2
- package/dist/browser.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +151 -89
- package/dist/mcp-server.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/visual/regression.d.ts.map +1 -1
- package/dist/visual/regression.js +5 -4
- package/dist/visual/regression.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AAkYH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA2xEpD"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -49,6 +49,44 @@ async function getBrowser() {
|
|
|
49
49
|
}
|
|
50
50
|
return browser;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* v14.2.1: Retry wrapper for transient browser errors.
|
|
54
|
+
* Retries operations that fail with common transient error patterns.
|
|
55
|
+
*/
|
|
56
|
+
async function withRetry(operation, options = {}) {
|
|
57
|
+
const maxRetries = options.maxRetries ?? 2;
|
|
58
|
+
const retryDelay = options.retryDelay ?? 500;
|
|
59
|
+
let lastError = null;
|
|
60
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
61
|
+
try {
|
|
62
|
+
return await operation();
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
lastError = e;
|
|
66
|
+
const errorMessage = lastError.message || "";
|
|
67
|
+
// Check if this is a transient error worth retrying
|
|
68
|
+
const isTransient = errorMessage.includes("Target closed") ||
|
|
69
|
+
errorMessage.includes("Execution context") ||
|
|
70
|
+
errorMessage.includes("Session closed") ||
|
|
71
|
+
errorMessage.includes("Connection refused") ||
|
|
72
|
+
errorMessage.includes("Browser disconnected");
|
|
73
|
+
if (!isTransient || attempt === maxRetries) {
|
|
74
|
+
throw lastError;
|
|
75
|
+
}
|
|
76
|
+
// Wait before retry with exponential backoff
|
|
77
|
+
await new Promise((r) => setTimeout(r, retryDelay * (attempt + 1)));
|
|
78
|
+
// Try to recover the browser before retrying
|
|
79
|
+
try {
|
|
80
|
+
const b = await getBrowser();
|
|
81
|
+
await b.recoverBrowser();
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Recovery failed, will retry operation anyway
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw lastError;
|
|
89
|
+
}
|
|
52
90
|
// Session storage (in-memory, cleared when server restarts)
|
|
53
91
|
const comparisonSessions = new Map();
|
|
54
92
|
// WCAG criteria reference for barrier mapping
|
|
@@ -230,22 +268,25 @@ export async function startMcpServer() {
|
|
|
230
268
|
server.tool("navigate", "Navigate to a URL and take a screenshot", {
|
|
231
269
|
url: z.string().url().describe("The URL to navigate to"),
|
|
232
270
|
}, async ({ url }) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
271
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
272
|
+
return await withRetry(async () => {
|
|
273
|
+
const b = await getBrowser();
|
|
274
|
+
const result = await b.navigate(url);
|
|
275
|
+
return {
|
|
276
|
+
content: [
|
|
277
|
+
{
|
|
278
|
+
type: "text",
|
|
279
|
+
text: JSON.stringify({
|
|
280
|
+
success: true,
|
|
281
|
+
url: result.url,
|
|
282
|
+
title: result.title,
|
|
283
|
+
loadTime: result.loadTime,
|
|
284
|
+
screenshot: result.screenshot,
|
|
285
|
+
}, null, 2),
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
});
|
|
249
290
|
});
|
|
250
291
|
// =========================================================================
|
|
251
292
|
// Interaction Tools
|
|
@@ -255,24 +296,27 @@ export async function startMcpServer() {
|
|
|
255
296
|
force: z.boolean().optional().describe("Bypass safety checks for destructive actions"),
|
|
256
297
|
verbose: z.boolean().optional().describe("Return available elements and AI suggestions on failure"),
|
|
257
298
|
}, async ({ selector, force, verbose }) => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
299
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
300
|
+
return await withRetry(async () => {
|
|
301
|
+
const b = await getBrowser();
|
|
302
|
+
const result = await b.click(selector, { force, verbose });
|
|
303
|
+
const response = {
|
|
304
|
+
success: result.success,
|
|
305
|
+
message: result.message,
|
|
306
|
+
screenshot: result.screenshot,
|
|
307
|
+
};
|
|
308
|
+
if (verbose && !result.success) {
|
|
309
|
+
if (result.availableElements)
|
|
310
|
+
response.availableElements = result.availableElements;
|
|
311
|
+
if (result.aiSuggestion)
|
|
312
|
+
response.aiSuggestion = result.aiSuggestion;
|
|
313
|
+
if (result.debugScreenshot)
|
|
314
|
+
response.debugScreenshot = result.debugScreenshot;
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
318
|
+
};
|
|
319
|
+
});
|
|
276
320
|
});
|
|
277
321
|
server.tool("smart_click", "Click with auto-retry and self-healing selectors. v11.8.0: Added confidence gating - only reports success if healed selector has >= 60% confidence.", {
|
|
278
322
|
selector: z.string().describe("Element to click"),
|
|
@@ -326,23 +370,26 @@ export async function startMcpServer() {
|
|
|
326
370
|
value: z.string().describe("Value to enter"),
|
|
327
371
|
verbose: z.boolean().optional().describe("Return available inputs and AI suggestions on failure"),
|
|
328
372
|
}, async ({ selector, value, verbose }) => {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
373
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
374
|
+
return await withRetry(async () => {
|
|
375
|
+
const b = await getBrowser();
|
|
376
|
+
const result = await b.fill(selector, value, { verbose });
|
|
377
|
+
const response = {
|
|
378
|
+
success: result.success,
|
|
379
|
+
message: result.message,
|
|
380
|
+
};
|
|
381
|
+
if (verbose && !result.success) {
|
|
382
|
+
if (result.availableInputs)
|
|
383
|
+
response.availableInputs = result.availableInputs;
|
|
384
|
+
if (result.aiSuggestion)
|
|
385
|
+
response.aiSuggestion = result.aiSuggestion;
|
|
386
|
+
if (result.debugScreenshot)
|
|
387
|
+
response.debugScreenshot = result.debugScreenshot;
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
391
|
+
};
|
|
392
|
+
});
|
|
346
393
|
});
|
|
347
394
|
// =========================================================================
|
|
348
395
|
// Extraction Tools
|
|
@@ -350,30 +397,36 @@ export async function startMcpServer() {
|
|
|
350
397
|
server.tool("screenshot", "Take a screenshot of the current page", {
|
|
351
398
|
path: z.string().optional().describe("Optional path to save the screenshot"),
|
|
352
399
|
}, async ({ path }) => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
400
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
401
|
+
return await withRetry(async () => {
|
|
402
|
+
const b = await getBrowser();
|
|
403
|
+
const file = await b.screenshot(path);
|
|
404
|
+
return {
|
|
405
|
+
content: [
|
|
406
|
+
{
|
|
407
|
+
type: "text",
|
|
408
|
+
text: JSON.stringify({ screenshot: file }, null, 2),
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
};
|
|
412
|
+
});
|
|
363
413
|
});
|
|
364
414
|
server.tool("extract", "Extract data from the page", {
|
|
365
415
|
what: z.enum(["links", "headings", "forms", "images", "text"]).describe("What to extract"),
|
|
366
416
|
}, async ({ what }) => {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
417
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
418
|
+
return await withRetry(async () => {
|
|
419
|
+
const b = await getBrowser();
|
|
420
|
+
const result = await b.extract(what);
|
|
421
|
+
return {
|
|
422
|
+
content: [
|
|
423
|
+
{
|
|
424
|
+
type: "text",
|
|
425
|
+
text: JSON.stringify(result.data, null, 2),
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
};
|
|
429
|
+
});
|
|
377
430
|
});
|
|
378
431
|
// =========================================================================
|
|
379
432
|
// Assertion Tools
|
|
@@ -503,16 +556,19 @@ export async function startMcpServer() {
|
|
|
503
556
|
// Self-Healing Tools
|
|
504
557
|
// =========================================================================
|
|
505
558
|
server.tool("heal_stats", "Get self-healing selector cache statistics", {}, async () => {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
559
|
+
// v14.2.1: Wrap with retry for transient errors
|
|
560
|
+
return await withRetry(async () => {
|
|
561
|
+
const b = await getBrowser();
|
|
562
|
+
const stats = b.getSelectorCacheStats();
|
|
563
|
+
return {
|
|
564
|
+
content: [
|
|
565
|
+
{
|
|
566
|
+
type: "text",
|
|
567
|
+
text: JSON.stringify(stats, null, 2),
|
|
568
|
+
},
|
|
569
|
+
],
|
|
570
|
+
};
|
|
571
|
+
});
|
|
516
572
|
});
|
|
517
573
|
// =========================================================================
|
|
518
574
|
// Visual Testing Tools (v7.0.0+)
|
|
@@ -1914,14 +1970,20 @@ Begin the simulation now. Narrate your thoughts as this persona.
|
|
|
1914
1970
|
url: result.url,
|
|
1915
1971
|
goal: result.goal,
|
|
1916
1972
|
overallScore: result.overallScore,
|
|
1917
|
-
resultsSummary: result.results.map((r) =>
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1973
|
+
resultsSummary: result.results.map((r) => {
|
|
1974
|
+
// v14.2.4: Show both total barriers and unique barrier types
|
|
1975
|
+
const uniqueTypes = new Set(r.barriers.map(b => b.type));
|
|
1976
|
+
return {
|
|
1977
|
+
persona: r.persona,
|
|
1978
|
+
disabilityType: r.disabilityType,
|
|
1979
|
+
goalAchieved: r.goalAchieved,
|
|
1980
|
+
empathyScore: r.empathyScore,
|
|
1981
|
+
barrierCount: r.barriers.length,
|
|
1982
|
+
uniqueBarrierTypes: uniqueTypes.size,
|
|
1983
|
+
barrierTypes: Array.from(uniqueTypes),
|
|
1984
|
+
wcagViolationCount: r.wcagViolations.length,
|
|
1985
|
+
};
|
|
1986
|
+
}),
|
|
1925
1987
|
allWcagViolations: result.allWcagViolations,
|
|
1926
1988
|
topBarriers: result.topBarriers.slice(0, 5), // v11.11.0: Deduplicated by type
|
|
1927
1989
|
topRemediation: result.combinedRemediation.slice(0, 5),
|