@wenathlan/extension 1.1.45 → 1.1.46

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.
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOEjO8Z0PDgQyfvawGcaO2j+o0GLCFTLNj7TkYC/Avo9l2NenMRq7gp90Nfd7E9MViv/OMcCKSYZ5unv12QPRtv31C+a5UQWDFAOP/cH5mwMd6hsayElrSoW8ta+FwFqmr9dIFkn7cQEU3YhZr4Gcbs+ycUHOxVgDA4NBKB0rQ6e9VW5LvTw0isRYUrqM+M72vKxHk9zUIYYn/LGPvottKBYi2GLr0PHSeC2UE+Shmq7vcFIXj6hDjvD4kLJ5sKoUllEcZ1TPuBcnHUQ9ndKA5iktXDQOIJCUJmi7a0YJ2PGg7fvpYfT9k0ai/qZ+pIoRfoOEwE01bPoDn7NjeYnNQIDAQAB",
4
4
  "name": "Devthink",
5
- "version": "1.1.45",
5
+ "version": "1.1.46",
6
6
  "description": "A consent-first bridge for reviewed browser-agent tasks.",
7
7
  "permissions": [
8
8
  "activeTab",
@@ -1,5 +1,37 @@
1
1
  "use strict";
2
2
  (() => {
3
+ // cdpbus.ts
4
+ function breakpointinputof(value) {
5
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
6
+ const entry = value;
7
+ const url = typeof entry.url === "string" && entry.url.trim() ? entry.url.trim() : void 0;
8
+ const line = typeof entry.line === "number" && Number.isInteger(entry.line) && entry.line >= 0 ? entry.line : void 0;
9
+ if (url === void 0 || line === void 0) return void 0;
10
+ const column = typeof entry.column === "number" && Number.isInteger(entry.column) && entry.column >= 0 ? entry.column : void 0;
11
+ const condition = typeof entry.condition === "string" && entry.condition.trim() ? entry.condition.trim() : void 0;
12
+ return { url, line, ...column !== void 0 ? { column } : {}, ...condition !== void 0 ? { condition } : {} };
13
+ }
14
+ function stepmodeof(value) {
15
+ const modes = ["stepover", "stepinto", "stepout", "resume"];
16
+ return typeof value === "string" && modes.includes(value) ? value : void 0;
17
+ }
18
+ function watchexpressionof(value) {
19
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
20
+ const entry = value;
21
+ const expression = typeof entry.expression === "string" && entry.expression.trim() ? entry.expression.trim() : void 0;
22
+ if (expression === void 0) return void 0;
23
+ const scope = typeof entry.scope === "string" && entry.scope.trim() ? entry.scope.trim() : "topframe";
24
+ return { expression, scope };
25
+ }
26
+ function overrideinputof(value) {
27
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
28
+ const entry = value;
29
+ const urlpattern = typeof entry.urlpattern === "string" && entry.urlpattern.trim() ? entry.urlpattern.trim() : void 0;
30
+ const source = typeof entry.source === "string" ? entry.source : void 0;
31
+ if (urlpattern === void 0 || source === void 0 || source.trim().length === 0) return void 0;
32
+ return { urlpattern, source };
33
+ }
34
+
3
35
  // runtimeline.ts
4
36
  var loglevels = ["error", "warn", "info", "log", "debug", "trace"];
5
37
  function levelrank(level) {
@@ -88,9 +120,9 @@
88
120
  }
89
121
 
90
122
  // policy.ts
91
- var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"]);
92
- var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies"]);
93
- var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi", "readcookies", "watchconsole", "watcherrors", "watchtasks"]);
123
+ var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript"]);
124
+ var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr"]);
125
+ var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp"]);
94
126
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
95
127
  function parseoptions(step) {
96
128
  if (step.options === void 0) return {};
@@ -2446,6 +2478,204 @@
2446
2478
  }
2447
2479
 
2448
2480
  // extension/pagedebug.ts
2481
+ var harnesskey = "__devthinkcdp";
2482
+ function readharness() {
2483
+ return globalThis[harnesskey];
2484
+ }
2485
+ function writeharness(harness) {
2486
+ if (harness === void 0) delete globalThis[harnesskey];
2487
+ else globalThis[harnesskey] = harness;
2488
+ }
2489
+ var instrumentedmethods = /* @__PURE__ */ new Set(["Runtime.evaluate", "Log.enable", "Debugger.enable", "DOM.enable", "Network.enable", "Page.enable", "DOM.getSnapshot", "Page.getNavigationHistory"]);
2490
+ function cdpstepoptions(step) {
2491
+ let options = {};
2492
+ try {
2493
+ options = parseoptions(step);
2494
+ } catch {
2495
+ options = {};
2496
+ }
2497
+ const teardown = options.teardown && typeof options.teardown === "object" && !Array.isArray(options.teardown) && Array.isArray(options.teardown.revertsteps) ? { revertsteps: options.teardown.revertsteps.filter((item) => typeof item === "string"), resumepolicy: String(options.teardown.resumepolicy ?? "ask") } : void 0;
2498
+ const command = options.command && typeof options.command === "object" && !Array.isArray(options.command) ? options.command : void 0;
2499
+ const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
2500
+ const breakpoint = breakpointinputof(options.breakpoint);
2501
+ const expression = watchexpressionof(options.expression);
2502
+ const override = overrideinputof(options.override);
2503
+ return {
2504
+ domains: Array.isArray(options.domains) ? options.domains.filter((domain) => typeof domain === "string") : [],
2505
+ ...teardown !== void 0 ? { teardown } : {},
2506
+ ...command !== void 0 && typeof command.method === "string" ? { command: { method: command.method, ...command.params && typeof command.params === "object" && !Array.isArray(command.params) ? { params: command.params } : {}, ...typeof command.resultpath === "string" ? { resultpath: command.resultpath } : {} } } : {},
2507
+ events: Array.isArray(options.events) ? options.events.flatMap((rule) => {
2508
+ const parsed = rule && typeof rule === "object" && !Array.isArray(rule) ? rule : void 0;
2509
+ if (!parsed || typeof parsed.domain !== "string" || typeof parsed.event !== "string") return [];
2510
+ return [{ domain: parsed.domain, event: parsed.event, ...typeof parsed.match === "string" ? { match: parsed.match } : {} }];
2511
+ }) : [],
2512
+ watchwindow: typeof watch.window === "number" && Number.isFinite(watch.window) && watch.window >= 0 ? watch.window : 0,
2513
+ ...breakpoint !== void 0 ? { breakpoint } : {},
2514
+ ...options.mode !== void 0 && stepmodeof(options.mode) !== void 0 ? { mode: options.mode } : {},
2515
+ ...expression !== void 0 ? { expression } : {},
2516
+ ...override !== void 0 ? { override } : {}
2517
+ };
2518
+ }
2519
+ function domstate() {
2520
+ return { url: location.href, title: document.title, nodes: document.querySelectorAll("*").length, forms: document.forms.length };
2521
+ }
2522
+ async function runcdpstep(step) {
2523
+ const options = cdpstepoptions(step);
2524
+ if (step.kind === "attachcdp") {
2525
+ const existing = readharness();
2526
+ if (existing) {
2527
+ for (const detach of existing.hooks) detach();
2528
+ }
2529
+ const harness = { domains: options.domains, breakpoints: [], overrides: [], events: [], hooks: [] };
2530
+ if (options.domains.includes("Log") || options.domains.includes("Runtime")) {
2531
+ for (const level of loglevels) {
2532
+ const original = console[level];
2533
+ const hooked = (...args) => {
2534
+ try {
2535
+ original.apply(console, args);
2536
+ } catch {
2537
+ }
2538
+ harness.events.push({ domain: "Log", event: "entryAdded", payload: args.map((arg) => serializearg(arg, 2)).join(" "), at: Date.now() });
2539
+ };
2540
+ console[level] = hooked;
2541
+ harness.hooks.push(() => {
2542
+ console[level] = original;
2543
+ });
2544
+ }
2545
+ }
2546
+ writeharness(harness);
2547
+ return { ok: true, summary: `Attached the instrumented devtools harness with the reviewed domains ${options.domains.join(", ")} enabled.`, details: { attached: true, domains: [...harness.domains], derivation: "The chrome devtools protocol needs the debugger permission, which the manifest gate forbids; the session runs through the page-instrumented harness injected by the scripting api." } };
2548
+ }
2549
+ if (step.kind === "detachcdp") {
2550
+ const harness = readharness();
2551
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2552
+ for (const detach of harness.hooks) detach();
2553
+ const reverted = { breakpoints: harness.breakpoints.length, overrides: harness.overrides.length };
2554
+ writeharness(void 0);
2555
+ return { ok: true, summary: `Detached the instrumented devtools harness cleanly after reverting ${reverted.breakpoints} breakpoint${reverted.breakpoints === 1 ? "" : "s"} and ${reverted.overrides} override${reverted.overrides === 1 ? "" : "s"}.`, details: { detached: true, ...reverted } };
2556
+ }
2557
+ if (step.kind === "cdpcmd") {
2558
+ const harness = readharness();
2559
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2560
+ const method = options.command?.method ?? "";
2561
+ const params = options.command?.params ?? {};
2562
+ if (!instrumentedmethods.has(method)) return { ok: false, summary: `The reviewed command ${method} reports the uninstrumented error class: the page harness implements ${[...instrumentedmethods].join(", ")} only.`, details: { method, errorclass: "uninstrumented" } };
2563
+ const started = Date.now();
2564
+ try {
2565
+ if (method === "Runtime.evaluate") {
2566
+ const expression = typeof params.expression === "string" ? params.expression : "";
2567
+ const probeurl = typeof params.url === "string" ? params.url : "inline";
2568
+ const scope = params.scope && typeof params.scope === "object" && !Array.isArray(params.scope) ? params.scope : {};
2569
+ const override = harness.overrides.find((spec) => overridematch(spec.urlpattern, probeurl));
2570
+ const source = override !== void 0 && overridematch(override.urlpattern, probeurl) ? override.source : expression;
2571
+ const value = new Function(...Object.keys(scope), `"use strict"; return (${source});`)(...Object.values(scope));
2572
+ let tripped;
2573
+ for (const breakpoint of harness.breakpoints) {
2574
+ if (breakpoint.url !== probeurl) continue;
2575
+ const conditionok = breakpoint.condition === void 0 ? true : Boolean(new Function(...Object.keys(scope), `"use strict"; return (${breakpoint.condition});`)(...Object.values(scope)));
2576
+ if (!conditionok) continue;
2577
+ breakpoint.hits += 1;
2578
+ tripped = { reason: "breakpoint", hitbreakpoint: breakpoint.id, frames: stackframes(new Error().stack ?? ""), scope, cursor: breakpoint.line, lines: Math.max(1, source.split("\n").length) };
2579
+ harness.paused = tripped;
2580
+ break;
2581
+ }
2582
+ const serialized = serializearg(value, 3);
2583
+ harness.events.push({ domain: "Runtime", event: "executionContextDestroyed", payload: serialized.slice(0, 200), at: Date.now() });
2584
+ return { ok: true, summary: `The reviewed command ${method} returned in ${Date.now() - started} milliseconds${tripped !== void 0 ? " and paused the run on the reviewed breakpoint" : ""}.`, details: { method, duration: Date.now() - started, result: { value: serialized }, ...tripped !== void 0 ? { paused: { reason: tripped.reason, hitbreakpoint: tripped.hitbreakpoint, frames: tripped.frames } } : {} } };
2585
+ }
2586
+ if (method === "DOM.getSnapshot") {
2587
+ const state = domstate();
2588
+ return { ok: true, summary: `The reviewed command ${method} returned the dom snapshot of ${state.nodes} nodes in ${Date.now() - started} milliseconds.`, details: { method, duration: Date.now() - started, result: state } };
2589
+ }
2590
+ if (method === "Page.getNavigationHistory") {
2591
+ const state = domstate();
2592
+ return { ok: true, summary: `The reviewed command ${method} returned the page navigation history in ${Date.now() - started} milliseconds.`, details: { method, duration: Date.now() - started, result: { url: state.url, title: state.title } } };
2593
+ }
2594
+ return { ok: true, summary: `The reviewed command ${method} enabled its domain through the instrumented harness in ${Date.now() - started} milliseconds.`, details: { method, duration: Date.now() - started, result: {} } };
2595
+ } catch (error) {
2596
+ return { ok: false, summary: `The reviewed command ${method} failed with the evaluationerror class: ${error instanceof Error ? error.message : String(error)}.`, details: { method, duration: Date.now() - started, errorclass: "evaluationerror" } };
2597
+ }
2598
+ }
2599
+ if (step.kind === "watchcdp") {
2600
+ const harness = readharness();
2601
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2602
+ const started = Date.now();
2603
+ const navigation = performance.getEntriesByType("navigation")[0];
2604
+ if (harness.domains.includes("Page") && navigation !== void 0 && navigation.loadEventStart > 0) harness.events.push({ domain: "Page", event: "loadEventFired", payload: location.href, at: started });
2605
+ await wait4(options.watchwindow);
2606
+ const observed = harness.events.filter((event) => event.at >= started);
2607
+ return { ok: true, summary: `Observed ${observed.length} domain event${observed.length === 1 ? "" : "s"} for the reviewed window of ${options.watchwindow} milliseconds.`, details: { events: observed, watchwindow: options.watchwindow, derivation: "Domain events derive from the instrumented console hooks and the page performance navigation buffer because no debugger permission exists in the manifest." } };
2608
+ }
2609
+ if (step.kind === "setbreakpoint") {
2610
+ const harness = readharness();
2611
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2612
+ if (!options.breakpoint) return { ok: false, summary: "The breakpoint input is absent." };
2613
+ const id = `bp-${options.breakpoint.url}-${options.breakpoint.line}-${options.breakpoint.column ?? 0}`;
2614
+ const registered = { id, ...options.breakpoint, hits: 0 };
2615
+ harness.breakpoints.push(registered);
2616
+ return { ok: true, summary: `Registered the reviewed breakpoint at ${options.breakpoint.url}:${options.breakpoint.line}${options.breakpoint.condition !== void 0 ? ` under the condition ${options.breakpoint.condition}` : ""}.`, details: { breakpoint: registered } };
2617
+ }
2618
+ if (step.kind === "stepcode") {
2619
+ const harness = readharness();
2620
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2621
+ const mode = stepmodeof(options.mode);
2622
+ if (mode === void 0) return { ok: false, summary: "The step code mode is absent." };
2623
+ if (harness.paused === void 0) return { ok: false, summary: "No paused instrumented probe exists to step through; pause on a reviewed breakpoint first." };
2624
+ if (mode === "resume" || mode === "stepout") {
2625
+ const reason = harness.paused.reason;
2626
+ const frames = harness.paused.frames;
2627
+ delete harness.paused;
2628
+ return { ok: true, summary: `The ${mode} mode ${mode === "resume" ? "resumed" : "stepped out of"} the paused probe after ${frames.length} call frame${frames.length === 1 ? "" : "s"}.`, details: { mode, paused: false, reason } };
2629
+ }
2630
+ harness.paused.cursor += 1;
2631
+ const state = domstate();
2632
+ return { ok: true, summary: `The ${mode} mode advanced to line ${harness.paused.cursor} of the paused probe and captured the pause state with ${harness.paused.frames.length} call frame${harness.paused.frames.length === 1 ? "" : "s"} and the dom state.`, details: { mode, paused: true, pausestate: { reason: harness.paused.reason, ...harness.paused.hitbreakpoint !== void 0 ? { hitbreakpoint: harness.paused.hitbreakpoint } : {}, frames: harness.paused.frames, cursor: harness.paused.cursor, dom: state } } };
2633
+ }
2634
+ if (step.kind === "watchexpr") {
2635
+ const harness = readharness();
2636
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2637
+ if (!options.expression) return { ok: false, summary: "The watch expression input is absent." };
2638
+ if (harness.paused === void 0) return { ok: false, summary: "No paused instrumented probe exists to evaluate the watch expression in; pause on a reviewed breakpoint first." };
2639
+ try {
2640
+ const value = new Function(...Object.keys(harness.paused.scope), `"use strict"; return (${options.expression.expression});`)(...Object.values(harness.paused.scope));
2641
+ return { ok: true, summary: `Evaluated the reviewed watch expression at the pause in the ${options.expression.scope} scope.`, details: { expression: options.expression.expression, scope: options.expression.scope, value: serializearg(value, 3) } };
2642
+ } catch (error) {
2643
+ return { ok: false, summary: `The reviewed watch expression failed with the evaluationerror class: ${error instanceof Error ? error.message : String(error)}.`, details: { errorclass: "evaluationerror" } };
2644
+ }
2645
+ }
2646
+ if (step.kind === "overridescript") {
2647
+ const harness = readharness();
2648
+ if (!harness) return { ok: false, summary: "No instrumented devtools harness is attached to this page." };
2649
+ if (!options.override) return { ok: false, summary: "The script override input is absent." };
2650
+ const id = `ov-${options.override.urlpattern}`;
2651
+ harness.overrides = harness.overrides.filter((spec) => spec.id !== id);
2652
+ harness.overrides.push({ id, urlpattern: options.override.urlpattern, source: options.override.source });
2653
+ try {
2654
+ new Function(options.override.source)();
2655
+ return { ok: true, summary: `Applied the reviewed script fixture for ${options.override.urlpattern} on the current document and on later instrumented evaluations of the pattern.`, details: { override: { id, urlpattern: options.override.urlpattern, applied: true } } };
2656
+ } catch (error) {
2657
+ return { ok: false, summary: `The reviewed script fixture failed with the evaluationerror class: ${error instanceof Error ? error.message : String(error)}.`, details: { errorclass: "evaluationerror" } };
2658
+ }
2659
+ }
2660
+ return { ok: false, summary: "The devtools step is not part of the instrumented family." };
2661
+ }
2662
+ function overridematch(urlpattern, url) {
2663
+ const patternmatch = /^(https:\/\/[^/]+|inline)(\/.*)?$/.exec(urlpattern);
2664
+ const urlmatch = /^(https:\/\/[^/]+|inline)(\/.*)?$/.exec(url);
2665
+ if (!patternmatch || !urlmatch) return false;
2666
+ if (patternmatch[1] !== urlmatch[1]) return false;
2667
+ const patternpath = (patternmatch[2] ?? "/").split("/").filter((segment) => segment.length > 0);
2668
+ const urlpath = (urlmatch[2] ?? "/").split("/").filter((segment) => segment.length > 0);
2669
+ const walk = (patternindex, urlindex) => {
2670
+ if (patternindex >= patternpath.length) return urlindex >= urlpath.length;
2671
+ const segment = patternpath[patternindex];
2672
+ if (segment === "**") return walk(patternindex + 1, urlindex) || urlindex < urlpath.length && walk(patternindex, urlindex + 1);
2673
+ if (urlindex >= urlpath.length) return false;
2674
+ if (segment !== "*" && segment !== urlpath[urlindex]) return false;
2675
+ return walk(patternindex + 1, urlindex + 1);
2676
+ };
2677
+ return walk(0, 0);
2678
+ }
2449
2679
  function debugwatchoptions(step) {
2450
2680
  let options = {};
2451
2681
  try {
@@ -3429,6 +3659,7 @@
3429
3659
  var detectionkinds = /* @__PURE__ */ new Set(["detectlists", "detecttables", "detectinfinitescroll", "detectvirtual", "detectlazy", "detectsticky", "detectscrolllock", "countpages", "classifypage", "fingerprintsection", "readscrollpos"]);
3430
3660
  var watchstepkinds = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "waitquiet", "readjson", "diffsnapshots", "deriveselector"]);
3431
3661
  var debugstepkinds = /* @__PURE__ */ new Set(["watchconsole", "watcherrors", "watchtasks"]);
3662
+ var cdpstepkinds = /* @__PURE__ */ new Set(["attachcdp", "detachcdp", "cdpcmd", "watchcdp", "setbreakpoint", "stepcode", "watchexpr", "overridescript"]);
3432
3663
  var navstepkinds = /* @__PURE__ */ new Set(["waitload", "waiturl", "followlink", "spanav", "spawait", "rewritequery", "setfragment", "stopnav", "prefetch", "preconnect", "printpdf"]);
3433
3664
  var formkinds = /* @__PURE__ */ new Set(["fillform", "filllabel", "fillplaceholder", "detectfields", "generatevalues", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "asksubmit", "submitform", "consentpassword", "attachfile"]);
3434
3665
  var wizardkinds = /* @__PURE__ */ new Set(["runwizard", "selectchain", "picktypeahead", "pickdate", "fillcard", "fillcode"]);
@@ -3495,6 +3726,7 @@
3495
3726
  else if (detectionkinds.has(step.kind)) result = runpagedetection(step, element, rootdocument);
3496
3727
  else if (watchstepkinds.has(step.kind)) result = runpagewatch(step, element, rootdocument);
3497
3728
  else if (debugstepkinds.has(step.kind)) return await rundebugwatch(step);
3729
+ else if (cdpstepkinds.has(step.kind)) return await runcdpstep(step);
3498
3730
  else if (mutatingkinds.has(step.kind)) result = runpageaction(step, element);
3499
3731
  else {
3500
3732
  if (!element) return { ok: false, summary: "Action target is no longer available." };