cbrowser 18.73.1 → 18.73.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/accessibility-empathy.d.ts.map +1 -1
- package/dist/analysis/accessibility-empathy.js +88 -4
- package/dist/analysis/accessibility-empathy.js.map +1 -1
- package/dist/analysis/agent-ready-audit.d.ts.map +1 -1
- package/dist/analysis/agent-ready-audit.js +66 -5
- package/dist/analysis/agent-ready-audit.js.map +1 -1
- package/dist/analysis/page-understanding.d.ts.map +1 -1
- package/dist/analysis/page-understanding.js +77 -12
- package/dist/analysis/page-understanding.js.map +1 -1
- package/dist/analysis/webmcp-readiness.d.ts.map +1 -1
- package/dist/analysis/webmcp-readiness.js +18 -7
- package/dist/analysis/webmcp-readiness.js.map +1 -1
- package/dist/browser/assertion-value.d.ts +54 -0
- package/dist/browser/assertion-value.d.ts.map +1 -0
- package/dist/browser/assertion-value.js +90 -0
- package/dist/browser/assertion-value.js.map +1 -0
- package/dist/browser.d.ts +8 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +106 -27
- package/dist/browser.js.map +1 -1
- package/dist/cli-args.d.ts +33 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +54 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.js +14 -22
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -1
- package/dist/config.js.map +1 -1
- package/dist/mcp-server-remote.d.ts +17 -1
- package/dist/mcp-server-remote.d.ts.map +1 -1
- package/dist/mcp-server-remote.js +22 -3
- package/dist/mcp-server-remote.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +20 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools/base/analysis-tools.d.ts +1 -1
- package/dist/mcp-tools/base/analysis-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/analysis-tools.js +83 -10
- package/dist/mcp-tools/base/analysis-tools.js.map +1 -1
- package/dist/mcp-tools/base/assertion-tools.d.ts +1 -1
- package/dist/mcp-tools/base/assertion-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/assertion-tools.js +26 -3
- package/dist/mcp-tools/base/assertion-tools.js.map +1 -1
- package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/audit-tools.js +85 -8
- package/dist/mcp-tools/base/audit-tools.js.map +1 -1
- package/dist/mcp-tools/base/browser-management-tools.d.ts +1 -1
- package/dist/mcp-tools/base/browser-management-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/browser-management-tools.js +66 -15
- package/dist/mcp-tools/base/browser-management-tools.js.map +1 -1
- package/dist/mcp-tools/base/browser-state-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/browser-state-tools.js +6 -1
- package/dist/mcp-tools/base/browser-state-tools.js.map +1 -1
- package/dist/mcp-tools/base/cognitive-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/cognitive-tools.js +103 -30
- package/dist/mcp-tools/base/cognitive-tools.js.map +1 -1
- package/dist/mcp-tools/base/extraction-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/extraction-tools.js +6 -0
- package/dist/mcp-tools/base/extraction-tools.js.map +1 -1
- package/dist/mcp-tools/base/interaction-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/interaction-tools.js +76 -11
- package/dist/mcp-tools/base/interaction-tools.js.map +1 -1
- package/dist/mcp-tools/base/session-tools.d.ts +1 -1
- package/dist/mcp-tools/base/session-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/session-tools.js +64 -7
- package/dist/mcp-tools/base/session-tools.js.map +1 -1
- package/dist/mcp-tools/base/site-knowledge-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/site-knowledge-tools.js +15 -1
- package/dist/mcp-tools/base/site-knowledge-tools.js.map +1 -1
- package/dist/mcp-tools/base/testing-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/testing-tools.js +20 -0
- package/dist/mcp-tools/base/testing-tools.js.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.js +52 -23
- package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
- package/dist/mcp-tools/persona-creation-tools.d.ts.map +1 -1
- package/dist/mcp-tools/persona-creation-tools.js +18 -0
- package/dist/mcp-tools/persona-creation-tools.js.map +1 -1
- package/dist/mcp-tools/session-policy.d.ts +43 -0
- package/dist/mcp-tools/session-policy.d.ts.map +1 -0
- package/dist/mcp-tools/session-policy.js +54 -0
- package/dist/mcp-tools/session-policy.js.map +1 -0
- package/dist/performance/metrics.d.ts +0 -3
- package/dist/performance/metrics.d.ts.map +1 -1
- package/dist/performance/metrics.js +45 -1
- package/dist/performance/metrics.js.map +1 -1
- package/dist/personas.d.ts.map +1 -1
- package/dist/personas.js +38 -4
- package/dist/personas.js.map +1 -1
- package/dist/remediation/patch-generator.d.ts.map +1 -1
- package/dist/remediation/patch-generator.js +36 -2
- package/dist/remediation/patch-generator.js.map +1 -1
- package/dist/testing/coverage.d.ts +8 -0
- package/dist/testing/coverage.d.ts.map +1 -1
- package/dist/testing/coverage.js +12 -0
- package/dist/testing/coverage.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/visual/cognitive-transport.d.ts +15 -2
- package/dist/visual/cognitive-transport.d.ts.map +1 -1
- package/dist/visual/cognitive-transport.js +85 -31
- package/dist/visual/cognitive-transport.js.map +1 -1
- package/dist/visual/perceptual-transport.d.ts +8 -0
- package/dist/visual/perceptual-transport.d.ts.map +1 -1
- package/dist/visual/perceptual-transport.js +19 -0
- package/dist/visual/perceptual-transport.js.map +1 -1
- package/dist/visual/regression.d.ts.map +1 -1
- package/dist/visual/regression.js +76 -3
- package/dist/visual/regression.js.map +1 -1
- package/package.json +1 -1
package/dist/browser.js
CHANGED
|
@@ -19,6 +19,7 @@ import { DEVICE_PRESETS, LOCATION_PRESETS, CBrowserErrorCode } from "./types.js"
|
|
|
19
19
|
import { runCognitiveJourney, isApiKeyConfigured, } from "./cognitive/index.js";
|
|
20
20
|
import { SessionManager } from "./browser/session-manager.js";
|
|
21
21
|
import { SelectorCacheManager } from "./browser/selector-cache.js";
|
|
22
|
+
import { extractExpected, extractSubject, UNPARSEABLE_MESSAGE } from "./browser/assertion-value.js";
|
|
22
23
|
import { OverlayHandler } from "./browser/overlay-handler.js";
|
|
23
24
|
import { getRemoteMode, MAX_RESPONSE_SIZE } from "./mcp-tools/screenshot-utils.js";
|
|
24
25
|
import { clampRect } from "./recording/timing.js";
|
|
@@ -152,6 +153,26 @@ export async function launchBrowserWithFallback(browserType = chromium, options
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Compress a Playwright error for a tool response.
|
|
158
|
+
*
|
|
159
|
+
* Playwright appends a "Call log:" listing every retry, which for a click that
|
|
160
|
+
* waits out its timeout runs to dozens of near-identical lines and roughly 4k
|
|
161
|
+
* tokens. The first lines say what failed and the last say how it ended; the
|
|
162
|
+
* middle is the same line repeated. Keep both ends, drop the middle, and say how
|
|
163
|
+
* much was dropped so nobody wonders what they are not seeing. (2026-07-29)
|
|
164
|
+
*/
|
|
165
|
+
function summarizePlaywrightError(message, headLines = 6, tailLines = 4) {
|
|
166
|
+
const lines = message.split("\n");
|
|
167
|
+
if (lines.length <= headLines + tailLines + 2)
|
|
168
|
+
return message;
|
|
169
|
+
const dropped = lines.length - headLines - tailLines;
|
|
170
|
+
return [
|
|
171
|
+
...lines.slice(0, headLines),
|
|
172
|
+
` … ${dropped} more lines of Playwright retry log elided (set verbose for the full log) …`,
|
|
173
|
+
...lines.slice(-tailLines),
|
|
174
|
+
].join("\n");
|
|
175
|
+
}
|
|
155
176
|
export class CBrowser {
|
|
156
177
|
config;
|
|
157
178
|
paths;
|
|
@@ -161,6 +182,14 @@ export class CBrowser {
|
|
|
161
182
|
currentPersona = null;
|
|
162
183
|
networkRequests = [];
|
|
163
184
|
networkResponses = new Map();
|
|
185
|
+
/**
|
|
186
|
+
* In-flight requests awaiting a response, so the response handler can attach
|
|
187
|
+
* status and duration to the originating record. Keyed by url+method, capped
|
|
188
|
+
* so a page that fires requests which never resolve cannot grow it without
|
|
189
|
+
* bound. (2026-07-28)
|
|
190
|
+
*/
|
|
191
|
+
pendingRequests = new Map();
|
|
192
|
+
static MAX_PENDING_REQUESTS = 2000;
|
|
164
193
|
harEntries = [];
|
|
165
194
|
isRecordingHar = false;
|
|
166
195
|
skipSessionRestore;
|
|
@@ -1185,6 +1214,17 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
1185
1214
|
timestamp: new Date().toISOString(),
|
|
1186
1215
|
};
|
|
1187
1216
|
this.networkRequests.push(networkRequest);
|
|
1217
|
+
// Track it so the response handler can complete the record. Evict the
|
|
1218
|
+
// oldest entry rather than growing forever when responses never arrive.
|
|
1219
|
+
if (this.pendingRequests.size >= CBrowser.MAX_PENDING_REQUESTS) {
|
|
1220
|
+
const oldest = this.pendingRequests.keys().next();
|
|
1221
|
+
if (!oldest.done)
|
|
1222
|
+
this.pendingRequests.delete(oldest.value);
|
|
1223
|
+
}
|
|
1224
|
+
this.pendingRequests.set(request.url() + request.method(), {
|
|
1225
|
+
req: networkRequest,
|
|
1226
|
+
startedAt: Date.now(),
|
|
1227
|
+
});
|
|
1188
1228
|
if (this.isRecordingHar) {
|
|
1189
1229
|
// Start HAR entry
|
|
1190
1230
|
const harEntry = {
|
|
@@ -1204,12 +1244,17 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
1204
1244
|
});
|
|
1205
1245
|
this.page.on("response", async (response) => {
|
|
1206
1246
|
const key = response.url() + response.request().method();
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1247
|
+
// This status was already being computed here and then discarded into an
|
|
1248
|
+
// unused local, which is why get_network_requests could never report the
|
|
1249
|
+
// status codes and timing its description promised. Attach it to the
|
|
1250
|
+
// originating request record instead. (2026-07-28)
|
|
1251
|
+
const pending = this.pendingRequests.get(key);
|
|
1252
|
+
if (pending) {
|
|
1253
|
+
pending.req.status = response.status();
|
|
1254
|
+
pending.req.statusText = response.statusText();
|
|
1255
|
+
pending.req.durationMs = Date.now() - pending.startedAt;
|
|
1256
|
+
this.pendingRequests.delete(key);
|
|
1257
|
+
}
|
|
1213
1258
|
if (this.isRecordingHar && this.networkResponses.has(key)) {
|
|
1214
1259
|
const partial = this.networkResponses.get(key);
|
|
1215
1260
|
const startTime = new Date(partial.startedDateTime).getTime();
|
|
@@ -1284,6 +1329,7 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
1284
1329
|
clearNetworkHistory() {
|
|
1285
1330
|
this.networkRequests = [];
|
|
1286
1331
|
this.harEntries = [];
|
|
1332
|
+
this.pendingRequests.clear();
|
|
1287
1333
|
}
|
|
1288
1334
|
// =========================================================================
|
|
1289
1335
|
// Performance Metrics
|
|
@@ -1293,7 +1339,7 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
1293
1339
|
*/
|
|
1294
1340
|
async getPerformanceMetrics() {
|
|
1295
1341
|
const page = await this.getPage();
|
|
1296
|
-
const metrics = await page.evaluate(() => {
|
|
1342
|
+
const metrics = await page.evaluate(async () => {
|
|
1297
1343
|
const result = {};
|
|
1298
1344
|
// Navigation timing
|
|
1299
1345
|
const navTiming = performance.getEntriesByType("navigation")[0];
|
|
@@ -1309,19 +1355,45 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
1309
1355
|
result.fcp = entry.startTime;
|
|
1310
1356
|
}
|
|
1311
1357
|
}
|
|
1312
|
-
// LCP
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
//
|
|
1318
|
-
|
|
1358
|
+
// LCP and CLS are delivered ONLY to a PerformanceObserver. Chromium never
|
|
1359
|
+
// adds largest-contentful-paint or layout-shift entries to the performance
|
|
1360
|
+
// timeline, so the previous getEntriesByType() calls returned [] on every
|
|
1361
|
+
// page. LCP was therefore always undefined, and CLS was always exactly 0 —
|
|
1362
|
+
// which looked like a real measurement of a perfectly stable page rather
|
|
1363
|
+
// than no measurement at all. `buffered: true` replays the entries that
|
|
1364
|
+
// already fired before this observer existed. (2026-07-29)
|
|
1319
1365
|
let clsScore = 0;
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1366
|
+
await new Promise((resolve) => {
|
|
1367
|
+
let settled = false;
|
|
1368
|
+
const finish = () => { if (!settled) {
|
|
1369
|
+
settled = true;
|
|
1370
|
+
resolve();
|
|
1371
|
+
} };
|
|
1372
|
+
try {
|
|
1373
|
+
const lcpObs = new PerformanceObserver((list) => {
|
|
1374
|
+
const entries = list.getEntries();
|
|
1375
|
+
if (entries.length > 0) {
|
|
1376
|
+
result.lcp = entries[entries.length - 1].startTime;
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
lcpObs.observe({ type: "largest-contentful-paint", buffered: true });
|
|
1380
|
+
const clsObs = new PerformanceObserver((list) => {
|
|
1381
|
+
for (const entry of list.getEntries()) {
|
|
1382
|
+
if (!entry.hadRecentInput) {
|
|
1383
|
+
clsScore += entry.value || 0;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
clsObs.observe({ type: "layout-shift", buffered: true });
|
|
1323
1388
|
}
|
|
1324
|
-
|
|
1389
|
+
catch {
|
|
1390
|
+
// Older engines without these entry types: leave lcp undefined rather
|
|
1391
|
+
// than reporting a fabricated value.
|
|
1392
|
+
finish();
|
|
1393
|
+
}
|
|
1394
|
+
// Buffered entries arrive on the next task; give late shifts a moment too.
|
|
1395
|
+
setTimeout(finish, 300);
|
|
1396
|
+
});
|
|
1325
1397
|
result.cls = clsScore;
|
|
1326
1398
|
// Resource counts
|
|
1327
1399
|
const resources = performance.getEntriesByType("resource");
|
|
@@ -2090,7 +2162,10 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
2090
2162
|
const result = {
|
|
2091
2163
|
success: false,
|
|
2092
2164
|
screenshot: await this.screenshot(),
|
|
2093
|
-
|
|
2165
|
+
// Was the raw Playwright error, whose Call log ran to ~4k tokens of
|
|
2166
|
+
// near-identical retry lines and crowded out everything else in the
|
|
2167
|
+
// response. verbose still gets the whole thing. (2026-07-29)
|
|
2168
|
+
message: `Failed to click: ${options.verbose ? errorMessage : summarizePlaywrightError(errorMessage)}`,
|
|
2094
2169
|
};
|
|
2095
2170
|
if (options.verbose) {
|
|
2096
2171
|
const available = await this.getAvailableClickables(page);
|
|
@@ -4036,8 +4111,9 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
4036
4111
|
// Page title assertions
|
|
4037
4112
|
if (lowerAssertion.includes("title") && (lowerAssertion.includes("is") || lowerAssertion.includes("contains"))) {
|
|
4038
4113
|
const title = await page.title();
|
|
4039
|
-
const
|
|
4040
|
-
|
|
4114
|
+
const expected = extractExpected(assertion);
|
|
4115
|
+
if (expected === null)
|
|
4116
|
+
return { passed: false, assertion, actual: title, message: UNPARSEABLE_MESSAGE };
|
|
4041
4117
|
if (lowerAssertion.includes("contains")) {
|
|
4042
4118
|
const passed = title.toLowerCase().includes(expected.toLowerCase());
|
|
4043
4119
|
return { passed, assertion, actual: title, expected, message: passed ? "Title contains expected text" : `Title "${title}" does not contain "${expected}"` };
|
|
@@ -4050,8 +4126,9 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
4050
4126
|
// URL assertions
|
|
4051
4127
|
if (lowerAssertion.includes("url") && (lowerAssertion.includes("is") || lowerAssertion.includes("contains"))) {
|
|
4052
4128
|
const url = page.url();
|
|
4053
|
-
const
|
|
4054
|
-
|
|
4129
|
+
const expected = extractExpected(assertion);
|
|
4130
|
+
if (expected === null)
|
|
4131
|
+
return { passed: false, assertion, actual: url, message: UNPARSEABLE_MESSAGE };
|
|
4055
4132
|
if (lowerAssertion.includes("contains")) {
|
|
4056
4133
|
const passed = url.includes(expected);
|
|
4057
4134
|
return { passed, assertion, actual: url, expected, message: passed ? "URL contains expected text" : `URL "${url}" does not contain "${expected}"` };
|
|
@@ -4064,8 +4141,9 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
4064
4141
|
// Text presence assertions
|
|
4065
4142
|
// v14.3.0: Filter script/style content to avoid ad injection false negatives
|
|
4066
4143
|
if (lowerAssertion.includes("page") && (lowerAssertion.includes("contains") || lowerAssertion.includes("has") || lowerAssertion.includes("shows"))) {
|
|
4067
|
-
const
|
|
4068
|
-
|
|
4144
|
+
const expected = extractExpected(assertion);
|
|
4145
|
+
if (expected === null)
|
|
4146
|
+
return { passed: false, assertion, message: UNPARSEABLE_MESSAGE };
|
|
4069
4147
|
// v14.3.0: Use filtered text extraction (excludes script/style content)
|
|
4070
4148
|
const content = await page.evaluate(() => {
|
|
4071
4149
|
const clone = document.body.cloneNode(true);
|
|
@@ -4079,8 +4157,9 @@ For more help: https://playwright.dev/docs/browsers
|
|
|
4079
4157
|
}
|
|
4080
4158
|
// Element existence assertions
|
|
4081
4159
|
if (lowerAssertion.includes("exists") || lowerAssertion.includes("visible") || lowerAssertion.includes("present")) {
|
|
4082
|
-
const
|
|
4083
|
-
|
|
4160
|
+
const selector = extractSubject(assertion);
|
|
4161
|
+
if (selector === null)
|
|
4162
|
+
return { passed: false, assertion, message: UNPARSEABLE_MESSAGE };
|
|
4084
4163
|
const element = await this.findElement(selector);
|
|
4085
4164
|
const passed = element !== null;
|
|
4086
4165
|
return { passed, assertion, expected: selector, message: passed ? `Element "${selector}" exists` : `Element "${selector}" not found` };
|