@wenathlan/extension 1.1.45 → 1.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
3
  <head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Devthink review</title><link rel="stylesheet" href="style.css"></head>
4
- <body><main class="wide"><header><p class="eyebrow">REVIEW GATE</p><h1>Plan before action</h1><p>Every browser operation remains blocked until the user reviews and approves it here.</p></header><label for="objective">Objective</label><textarea id="objective" rows="4" placeholder="Describe a browser task to turn into a reviewable plan."></textarea><div class="actions"><button id="localplan">Create local observation plan</button><button id="remoteplan" class="secondary">Ask configured endpoint</button><button id="diagnostic" class="secondary">Capture local diagnostics</button></div><p id="status" role="status">Loading session state.</p><p id="capabilitiestext" role="status" class="muted">Optional capabilities unknown.</p><section><h2>Current plan</h2><progress id="planprogress" max="1" value="0"></progress><div id="plan" class="panel"></div></section><section><h2>Clickable map</h2><ol id="map" class="audit maplist"></ol></section><section><h2>Navigation trail</h2><ol id="trail" class="audit"></ol></section><section><h2>Navigation state</h2><div id="navigation" class="panel"></div></section><section><h2>Tabs and windows</h2><div id="tabswindows" class="panel"></div></section><section><h2>Forms and data</h2><div id="forms" class="panel"></div></section><section><h2>Files and downloads</h2><div id="files" class="panel"></div></section><section><h2>Capture gallery</h2><div id="captures" class="panel"></div></section><section><h2>Media</h2><div id="media" class="panel"></div></section><section><h2>Network calls</h2><div id="calls" class="panel"></div></section><section><h2>Network view</h2><div id="netview" class="panel"></div></section><section><h2>Traffic control</h2><div id="traffic" class="panel"></div></section><section><h2>Run timeline</h2><div id="timeline" class="panel"></div></section><section><h2>Console diff</h2><div id="consolediff" class="panel"></div></section><section><h2>Datasets</h2><div id="datasets" class="panel"></div></section><section><h2>Consent banners</h2><div id="banners" class="panel"></div></section><section><h2>Accessibility tree</h2><div id="a11y" class="panel"></div></section><section><h2>Reader view</h2><div id="reader" class="panel"></div></section><section><h2>Detected shapes</h2><ol id="detections" class="audit maplist"></ol></section><section><h2>Watch stream</h2><ol id="stream" class="audit"></ol></section><section><h2>Snapshot diffs</h2><div id="diffs" class="panel"></div></section><section><h2>Derived selectors</h2><ol id="selectors" class="audit maplist"></ol></section><section><h2>Structured diagnostics</h2><ul id="diagnostics" class="audit"></ul></section><section><h2>Local audit</h2><ol id="audit" class="audit"></ol></section></main><script type="module" src="sidepanel.js"></script></body>
4
+ <body><main class="wide"><header><p class="eyebrow">REVIEW GATE</p><h1>Plan before action</h1><p>Every browser operation remains blocked until the user reviews and approves it here.</p></header><label for="objective">Objective</label><textarea id="objective" rows="4" placeholder="Describe a browser task to turn into a reviewable plan."></textarea><div class="actions"><button id="localplan">Create local observation plan</button><button id="remoteplan" class="secondary">Ask configured endpoint</button><button id="diagnostic" class="secondary">Capture local diagnostics</button></div><p id="status" role="status">Loading session state.</p><p id="capabilitiestext" role="status" class="muted">Optional capabilities unknown.</p><section><h2>Current plan</h2><progress id="planprogress" max="1" value="0"></progress><div id="plan" class="panel"></div></section><section><h2>Clickable map</h2><ol id="map" class="audit maplist"></ol></section><section><h2>Navigation trail</h2><ol id="trail" class="audit"></ol></section><section><h2>Navigation state</h2><div id="navigation" class="panel"></div></section><section><h2>Tabs and windows</h2><div id="tabswindows" class="panel"></div></section><section><h2>Forms and data</h2><div id="forms" class="panel"></div></section><section><h2>Files and downloads</h2><div id="files" class="panel"></div></section><section><h2>Capture gallery</h2><div id="captures" class="panel"></div></section><section><h2>Media</h2><div id="media" class="panel"></div></section><section><h2>Network calls</h2><div id="calls" class="panel"></div></section><section><h2>Network view</h2><div id="netview" class="panel"></div></section><section><h2>Traffic control</h2><div id="traffic" class="panel"></div></section><section><h2>Run timeline</h2><div id="timeline" class="panel"></div></section><section><h2>Debugger</h2><div id="debugger" class="panel"></div></section><section><h2>Profiling</h2><div id="profiling" class="panel"></div></section><section><h2>Console diff</h2><div id="consolediff" class="panel"></div></section><section><h2>Datasets</h2><div id="datasets" class="panel"></div></section><section><h2>Consent banners</h2><div id="banners" class="panel"></div></section><section><h2>Accessibility tree</h2><div id="a11y" class="panel"></div></section><section><h2>Reader view</h2><div id="reader" class="panel"></div></section><section><h2>Detected shapes</h2><ol id="detections" class="audit maplist"></ol></section><section><h2>Watch stream</h2><ol id="stream" class="audit"></ol></section><section><h2>Snapshot diffs</h2><div id="diffs" class="panel"></div></section><section><h2>Derived selectors</h2><ol id="selectors" class="audit maplist"></ol></section><section><h2>Structured diagnostics</h2><ul id="diagnostics" class="audit"></ul></section><section><h2>Local audit</h2><ol id="audit" class="audit"></ol></section></main><script type="module" src="sidepanel.js"></script></body>
5
5
  </html>
@@ -1,7 +1,7 @@
1
1
  // policy.ts
2
- 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"]);
3
- 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"]);
4
- 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"]);
2
+ 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", "heapshot", "profilecpu", "capturesourcemaps"]);
3
+ 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"]);
4
+ 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", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace"]);
5
5
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
6
6
 
7
7
  // extension/tabscommand.ts
@@ -69,6 +69,8 @@ var callsroot = document.querySelector("#calls");
69
69
  var trafficroot = document.querySelector("#traffic");
70
70
  var timelineroot = document.querySelector("#timeline");
71
71
  var consolediffroot = document.querySelector("#consolediff");
72
+ var debuggerroot = document.querySelector("#debugger");
73
+ var profilingroot = document.querySelector("#profiling");
72
74
  var netviewroot = document.querySelector("#netview");
73
75
  var statusnode = document.querySelector("#status");
74
76
  var progressnode = document.querySelector("#planprogress");
@@ -2220,6 +2222,131 @@ function renderconsolediff() {
2220
2222
  }
2221
2223
  consolediffroot.append(headline, list);
2222
2224
  }
2225
+ function renderdebugger(context) {
2226
+ if (!debuggerroot) return;
2227
+ debuggerroot.replaceChildren();
2228
+ const waiting = (context.debuggergrants ?? []).filter((grant) => grant.approved === void 0 && grant.revokedat === void 0);
2229
+ for (const grant of waiting) {
2230
+ const card = document.createElement("div");
2231
+ card.className = "consentcard";
2232
+ const prompt = document.createElement("p");
2233
+ prompt.textContent = `Debugger attach on ${grant.origin} waits for your consent with the domain allowlist ${grant.domains.join(", ")} shown.`;
2234
+ card.append(prompt, button("Approve debugger consent", () => request({ kind: "approvedebuggerconsent", id: grant.id }).then(() => status(`Debugger consent on ${grant.origin} approved for ${grant.domains.join(", ")}; run the attachcdp step again.`)).then(refresh)));
2235
+ debuggerroot.append(card);
2236
+ }
2237
+ const granted = (context.debuggergrants ?? []).filter((grant) => grant.approved === true && grant.revokedat === void 0);
2238
+ if (granted.length > 0) debuggerroot.append(button("Detach debugger now", () => request({ kind: "revokedebuggerconsent" }).then((value) => {
2239
+ const parsed = value;
2240
+ status(`Detached the debugger: ${parsed.revoked} consent record${parsed.revoked === 1 ? "" : "s"} revoked, every breakpoint and override reverted and the run paused for review.`);
2241
+ return refresh();
2242
+ })));
2243
+ const sessions = context.cdpsessions ?? [];
2244
+ const attached = sessions.filter((session) => session.detachedat === void 0);
2245
+ const sessionline = document.createElement("p");
2246
+ sessionline.className = "muted";
2247
+ sessionline.textContent = attached.length === 0 ? "No devtools session is attached; run the attachcdp step behind the reviewed debugger consent." : `${attached.length} attached devtools session${attached.length === 1 ? "" : "s"}${attached[0] !== void 0 ? ` of ${attached[0].origin} with the domains ${attached[0].domains.join(", ")} enabled through ${attached[0].debuggerversion}` : ""}.`;
2248
+ debuggerroot.append(sessionline);
2249
+ const lastpause = (context.pauses ?? [])[0];
2250
+ if (lastpause !== void 0 && context.cdpattached !== 0) {
2251
+ const banner = document.createElement("div");
2252
+ banner.className = "bannercard";
2253
+ const head = document.createElement("p");
2254
+ head.textContent = `Paused on ${lastpause.reason}${lastpause.hitbreakpoint !== void 0 ? ` at breakpoint ${lastpause.hitbreakpoint}` : ""}${lastpause.domsnapshotid !== void 0 ? ` with dom snapshot ${lastpause.domsnapshotid}` : ""}.`;
2255
+ banner.append(head);
2256
+ if (lastpause.framesexpired === true) {
2257
+ const expired = document.createElement("p");
2258
+ expired.textContent = "The call frames expired from the pause retention window; the pause reason and hit breakpoint survive.";
2259
+ banner.append(expired);
2260
+ } else {
2261
+ for (const frame of lastpause.callframes.slice(0, 6)) {
2262
+ const row = document.createElement("p");
2263
+ row.textContent = `${frame.functionname ?? "anonymous"} ${frame.url}:${frame.line}${frame.column !== void 0 ? `:${frame.column}` : ""}`;
2264
+ banner.append(row);
2265
+ }
2266
+ }
2267
+ debuggerroot.append(banner);
2268
+ }
2269
+ const commands = context.cdpcommands ?? [];
2270
+ if (commands.length > 0) {
2271
+ const head = document.createElement("h4");
2272
+ head.textContent = "Raw protocol commands";
2273
+ const list = document.createElement("ul");
2274
+ list.className = "audit";
2275
+ for (const command of commands.slice(0, 12)) {
2276
+ const item = document.createElement("li");
2277
+ const badge = document.createElement("span");
2278
+ badge.className = "protocolbadge";
2279
+ badge.textContent = "raw protocol";
2280
+ item.append(`${command.method} \xB7 ${command.duration} ms${command.errorclass !== void 0 ? ` \xB7 ${command.errorclass}` : ""} \xB7 session ${command.sessionid.slice(0, 8)}`, badge);
2281
+ list.append(item);
2282
+ }
2283
+ debuggerroot.append(head, list);
2284
+ }
2285
+ const breakpoints = (context.breakpoints ?? []).filter((spec) => spec.revertedat === void 0);
2286
+ if (breakpoints.length > 0) {
2287
+ const head = document.createElement("h4");
2288
+ head.textContent = "Breakpoints";
2289
+ const list = document.createElement("ul");
2290
+ list.className = "audit";
2291
+ for (const spec of breakpoints) {
2292
+ const item = document.createElement("li");
2293
+ item.textContent = `${spec.url}:${spec.line}${spec.column !== void 0 ? `:${spec.column}` : ""} \xB7 ${spec.hits} hit${spec.hits === 1 ? "" : "s"}${spec.condition !== void 0 ? ` \xB7 condition ${spec.condition}` : ""}`;
2294
+ list.append(item);
2295
+ }
2296
+ debuggerroot.append(head, list);
2297
+ }
2298
+ const watches = context.watchexpressions ?? [];
2299
+ if (watches.length > 0) {
2300
+ const head = document.createElement("h4");
2301
+ head.textContent = "Watch expressions";
2302
+ const list = document.createElement("ul");
2303
+ list.className = "audit";
2304
+ for (const watch of watches) {
2305
+ const item = document.createElement("li");
2306
+ const values = watch.values.slice(-4).map((value) => `${value.value} @${value.pauseid.slice(0, 6)}`).join(" \xB7 ");
2307
+ item.textContent = `${watch.expression} (${watch.scope} scope${watch.reviewed ? ", reviewed" : ""})${values ? `: ${values}` : ": no value captured yet"}`;
2308
+ list.append(item);
2309
+ }
2310
+ debuggerroot.append(head, list);
2311
+ }
2312
+ const overrides = context.scriptoverrides ?? [];
2313
+ if (overrides.length > 0) {
2314
+ const head = document.createElement("h4");
2315
+ head.textContent = "Script overrides";
2316
+ const list = document.createElement("ul");
2317
+ list.className = "audit";
2318
+ for (const spec of overrides) {
2319
+ const item = document.createElement("li");
2320
+ item.textContent = `${spec.urlpattern} \xB7 ${spec.hits} applied evaluation${spec.hits === 1 ? "" : "s"}${spec.reviewed ? " \xB7 reviewed fixture" : ""}${spec.revertedat !== void 0 ? " \xB7 reverted" : " \xB7 active"}`;
2321
+ if (spec.revertedat === void 0) item.append(button("Revert fixture", () => request({ kind: "revertcdpoverride", id: spec.id }).then(() => status(`Reverted the script override of ${spec.urlpattern}; later evaluations run the original source again.`)).then(refresh)));
2322
+ list.append(item);
2323
+ }
2324
+ debuggerroot.append(head, list);
2325
+ }
2326
+ const rules = context.cdpeventrules ?? [];
2327
+ if (rules.length > 0) {
2328
+ const head = document.createElement("h4");
2329
+ head.textContent = "Domain events beside the timeline";
2330
+ const list = document.createElement("ul");
2331
+ list.className = "audit";
2332
+ for (const rule of rules.slice(0, 10)) {
2333
+ const item = document.createElement("li");
2334
+ item.textContent = `${rule.domain}.${rule.event}${rule.match !== void 0 ? ` matching ${rule.match}` : ""} \xB7 ${rule.events} matched event${rule.events === 1 ? "" : "s"}${rule.closedat !== void 0 ? " \xB7 closed" : ""}`;
2335
+ list.append(item);
2336
+ }
2337
+ debuggerroot.append(head, list);
2338
+ }
2339
+ const settingsline = document.createElement("p");
2340
+ settingsline.className = "muted";
2341
+ settingsline.textContent = `Pause retention ${context.pauseretention ?? "keeps every capture"} \xB7 breakpoint ceiling ${context.breakpointceiling ?? "none"}.`;
2342
+ const retentioninput = document.createElement("input");
2343
+ retentioninput.placeholder = "pause retention";
2344
+ retentioninput.value = context.pauseretention !== void 0 ? String(context.pauseretention) : "";
2345
+ const ceilinginput = document.createElement("input");
2346
+ ceilinginput.placeholder = "breakpoint ceiling";
2347
+ ceilinginput.value = context.breakpointceiling !== void 0 ? String(context.breakpointceiling) : "";
2348
+ debuggerroot.append(settingsline, retentioninput, ceilinginput, button("Save debugger settings", () => Promise.all([request({ kind: "setpauseretention", retention: retentioninput.value === "" ? void 0 : Number(retentioninput.value) }), request({ kind: "setbreakpointceiling", ceiling: ceilinginput.value === "" ? void 0 : Number(ceilinginput.value) })]).then(() => status(`Debugger settings saved: pause retention ${retentioninput.value === "" ? "keeps every capture" : retentioninput.value} and breakpoint ceiling ${ceilinginput.value === "" ? "none" : ceilinginput.value}.`)).then(refresh)));
2349
+ }
2223
2350
  async function refresh() {
2224
2351
  const context = await request({ kind: "context" });
2225
2352
  renderplan(context.plan, context.progress, context.outcomes ?? [], context.retries ?? []);
@@ -2244,6 +2371,8 @@ async function refresh() {
2244
2371
  rendernetview(context);
2245
2372
  rendertraffic(context);
2246
2373
  rendertimeline(context);
2374
+ renderdebugger(context);
2375
+ renderprofiling(context);
2247
2376
  renderconsolediff();
2248
2377
  renderaudit(context.audit);
2249
2378
  rendercapabilities(context.capabilities);
@@ -2258,4 +2387,159 @@ localbutton?.addEventListener("click", () => create("proposelocal").catch((error
2258
2387
  remotebutton?.addEventListener("click", () => create("proposeremote").catch((error) => status(error instanceof Error ? error.message : String(error), true)));
2259
2388
  diagnosticbutton?.addEventListener("click", () => request({ kind: "diagnostic" }).then(() => refresh()).catch((error) => status(error instanceof Error ? error.message : String(error), true)));
2260
2389
  refresh().catch((error) => status(error instanceof Error ? error.message : String(error), true));
2390
+ function renderprofiling(context) {
2391
+ if (!profilingroot) return;
2392
+ profilingroot.replaceChildren();
2393
+ const report = context.profile;
2394
+ const waiting = (report?.consents ?? []).filter((consent) => consent.approved === void 0 && consent.revokedat === void 0);
2395
+ for (const consent of waiting) {
2396
+ const card = document.createElement("div");
2397
+ card.className = "consentcard";
2398
+ const prompt = document.createElement("p");
2399
+ prompt.textContent = `Source map capture on ${consent.origin} waits for your consent; the map files of the loaded same origin scripts are fetched and parsed locally.`;
2400
+ card.append(prompt, button("Approve source map capture", () => request({ kind: "approvesourcemapconsent", id: consent.id }).then(() => status(`Source map capture on ${consent.origin} approved; run the capturesourcemaps step again.`)).then(refresh)));
2401
+ profilingroot.append(card);
2402
+ }
2403
+ const granted = (report?.consents ?? []).filter((consent) => consent.approved === true && consent.revokedat === void 0);
2404
+ if (granted.length > 0) profilingroot.append(button("Revoke source map consent", () => request({ kind: "revokesourcemapconsent" }).then((value) => {
2405
+ const parsed = value;
2406
+ status(`Revoked ${parsed.revoked} source map consent record${parsed.revoked === 1 ? "" : "s"}; the next capture needs a new reviewed prompt.`);
2407
+ return refresh();
2408
+ })));
2409
+ const stateline = document.createElement("p");
2410
+ stateline.className = "muted";
2411
+ stateline.textContent = `${context.profileactive ?? 0} profiling instrument${(context.profileactive ?? 0) === 1 ? "" : "s"} active${(context.profiletargets ?? []).length > 0 ? ` with the targets ${(context.profiletargets ?? []).map((target) => `${target.kind} ${target.url} (${target.sessionid.slice(0, 10)})`).join(", ")} attached through flattened sub sessions` : ""}.`;
2412
+ profilingroot.append(stateline);
2413
+ const flows = report?.flows ?? [];
2414
+ if (flows.length > 0) {
2415
+ const head = document.createElement("h4");
2416
+ head.textContent = "Flow durations per step";
2417
+ profilingroot.append(head);
2418
+ const maxflow = flows.reduce((max, metric) => Math.max(max, metric.duration), 0);
2419
+ for (const metric of flows.slice(0, 12)) {
2420
+ const bar = document.createElement("div");
2421
+ bar.className = "taskbar";
2422
+ const label = document.createElement("p");
2423
+ label.className = "timeline";
2424
+ label.textContent = `${metric.name} \xB7 ${metric.duration} ms \xB7 steps ${metric.steps.join(", ")}`;
2425
+ const gauge = document.createElement("div");
2426
+ gauge.className = "taskgauge";
2427
+ const fill = document.createElement("div");
2428
+ fill.className = "taskfill";
2429
+ fill.style.width = maxflow > 0 ? `${Math.round(metric.duration / maxflow * 100)}%` : "0%";
2430
+ gauge.append(fill);
2431
+ bar.append(label, gauge);
2432
+ profilingroot.append(bar);
2433
+ }
2434
+ }
2435
+ const heaps = report?.heaps ?? [];
2436
+ const samples = report?.samples ?? [];
2437
+ const trend = (report?.trends ?? [])[0];
2438
+ if (samples.length > 0 || heaps.length > 0) {
2439
+ const head = document.createElement("h4");
2440
+ head.textContent = "Heap samples with the growth trend";
2441
+ profilingroot.append(head);
2442
+ const maxused = samples.reduce((max, sample) => Math.max(max, sample.usedbytes), 1);
2443
+ for (const sample of samples.slice(0, 12)) {
2444
+ const bar = document.createElement("div");
2445
+ bar.className = "taskbar";
2446
+ const label = document.createElement("p");
2447
+ label.className = "timeline";
2448
+ label.textContent = `${sample.usedbytes} of ${sample.limitbytes} bytes \xB7 step ${sample.stepid}`;
2449
+ const gauge = document.createElement("div");
2450
+ gauge.className = "taskgauge";
2451
+ const fill = document.createElement("div");
2452
+ fill.className = "taskfill";
2453
+ fill.style.width = `${Math.round(sample.usedbytes / maxused * 100)}%`;
2454
+ gauge.append(fill);
2455
+ bar.append(label, gauge);
2456
+ profilingroot.append(bar);
2457
+ }
2458
+ const trendline = document.createElement("p");
2459
+ trendline.className = "muted";
2460
+ trendline.textContent = trend !== void 0 ? `Trend slope ${trend.slope.toFixed(2)} bytes per millisecond over ${trend.samples} sample${trend.samples === 1 ? "" : "s"}${trend.flaggedsteps.length > 0 ? `; flagged steps ${trend.flaggedsteps.join(", ")}` : ""}.` : "No growth trend computed yet; trackmemory computes it from the samples beside every step.";
2461
+ profilingroot.append(trendline);
2462
+ if (heaps.length > 0) {
2463
+ const list = document.createElement("ul");
2464
+ list.className = "audit";
2465
+ for (const heap of heaps.slice(0, 6)) {
2466
+ const item = document.createElement("li");
2467
+ item.textContent = `snapshot ${heap.id.slice(0, 8)} \xB7 ${heap.bytesize} bytes \xB7 ${heap.nodecount} dom nodes${heap.bytesexpired === true ? " \xB7 heavy bytes expired" : ""}`;
2468
+ list.append(item);
2469
+ }
2470
+ profilingroot.append(list);
2471
+ }
2472
+ }
2473
+ const cpuprofiles = report?.profiles ?? [];
2474
+ if (cpuprofiles.length > 0) {
2475
+ const head = document.createElement("h4");
2476
+ head.textContent = "Cpu profiles with hot functions";
2477
+ const list = document.createElement("ul");
2478
+ list.className = "audit";
2479
+ for (const profile of cpuprofiles.slice(0, 6)) {
2480
+ const item = document.createElement("li");
2481
+ item.textContent = `profile ${profile.id.slice(0, 8)} \xB7 ${profile.duration} ms \xB7 ${profile.samplecount} sample${profile.samplecount === 1 ? "" : "s"} \xB7 hot ${profile.hotfunctions.slice(0, 4).join(", ") || "none"}${profile.samplesexpired === true ? " \xB7 heavy samples expired" : ""}`;
2482
+ list.append(item);
2483
+ }
2484
+ profilingroot.append(head, list);
2485
+ }
2486
+ const shifts = report?.shifts ?? [];
2487
+ if (shifts.length > 0) {
2488
+ const head = document.createElement("h4");
2489
+ head.textContent = "Layout shifts with scores and selectors";
2490
+ const list = document.createElement("ul");
2491
+ list.className = "audit";
2492
+ for (const shift of shifts.slice(0, 10)) {
2493
+ const item = document.createElement("li");
2494
+ item.textContent = `score ${shift.score.toFixed(4)} at ${Math.round(shift.starttime)} ms${shift.selectors.length > 0 ? ` \xB7 impacted ${shift.selectors.join(", ")}` : ""} \xB7 step ${shift.stepid}`;
2495
+ list.append(item);
2496
+ }
2497
+ profilingroot.append(head, list);
2498
+ }
2499
+ const traces = report?.traces ?? [];
2500
+ if (traces.length > 0) {
2501
+ const head = document.createElement("h4");
2502
+ head.textContent = "Traces with step annotations";
2503
+ profilingroot.append(head);
2504
+ const list = document.createElement("ul");
2505
+ list.className = "audit";
2506
+ for (const trace of traces.slice(0, 8)) {
2507
+ const item = document.createElement("li");
2508
+ item.textContent = `trace ${trace.id.slice(0, 8)} \xB7 ${trace.categories.join(", ")} \xB7 ${trace.events} event${trace.events === 1 ? "" : "s"} \xB7 ${trace.bytesize} bytes \xB7 ${trace.annotations.length} annotation${trace.annotations.length === 1 ? "" : "s"}${trace.bytesexpired === true ? " \xB7 heavy bytes expired" : ""}${trace.exportedat !== void 0 ? " \xB7 exported" : ""}`;
2509
+ item.append(button("Replay trace", () => request({ kind: "tracereplay", traceid: trace.id }).then((value) => {
2510
+ const replay = value;
2511
+ const grouped = Object.entries(replay.categories).map(([category, count]) => `${category} ${count}`).join(", ");
2512
+ const steps = [...new Set(replay.events.map((event) => event.stepid).filter((stepid) => stepid !== void 0))].join(", ");
2513
+ status(`Trace replay of ${trace.id.slice(0, 8)}: ${replay.events.length} event${replay.events.length === 1 ? "" : "s"} grouped by category (${grouped}) and by step (${steps || "none"}) with ${replay.annotations.length} annotation${replay.annotations.length === 1 ? "" : "s"}.`);
2514
+ return refresh();
2515
+ })));
2516
+ if (trace.bytesexpired !== true) item.append(button("Export trace", () => request({ kind: "exporttrace", traceid: trace.id }).then(() => status(`Exported the trace ${trace.id.slice(0, 8)} through the reviewed download flow with its ${trace.annotations.length} step annotation${trace.annotations.length === 1 ? "" : "s"}.`)).then(refresh)));
2517
+ list.append(item);
2518
+ }
2519
+ profilingroot.append(list);
2520
+ }
2521
+ const sourcemaps = report?.sourcemaps ?? [];
2522
+ if (sourcemaps.length > 0) {
2523
+ const head = document.createElement("h4");
2524
+ head.textContent = "Source maps";
2525
+ const list = document.createElement("ul");
2526
+ list.className = "audit";
2527
+ for (const ref of sourcemaps.slice(0, 10)) {
2528
+ const item = document.createElement("li");
2529
+ item.textContent = `${ref.scripturl} \u2192 ${ref.mapurl} \xB7 ${ref.parsed ? "parsed" : "unparsed"}`;
2530
+ list.append(item);
2531
+ }
2532
+ profilingroot.append(head, list);
2533
+ }
2534
+ const settingsline = document.createElement("p");
2535
+ settingsline.className = "muted";
2536
+ settingsline.textContent = `Profile retention ${context.profileretention ?? "keeps every heavy artifact"} \xB7 trace byte ceiling ${context.traceceiling ?? "none"}.`;
2537
+ const retentioninput = document.createElement("input");
2538
+ retentioninput.placeholder = "profile retention ms";
2539
+ retentioninput.value = context.profileretention !== void 0 ? String(context.profileretention) : "";
2540
+ const ceilinginput = document.createElement("input");
2541
+ ceilinginput.placeholder = "trace byte ceiling";
2542
+ ceilinginput.value = context.traceceiling !== void 0 ? String(context.traceceiling) : "";
2543
+ profilingroot.append(settingsline, retentioninput, ceilinginput, button("Save profiling settings", () => Promise.all([request({ kind: "setprofileretention", retention: retentioninput.value === "" ? void 0 : Number(retentioninput.value) }), request({ kind: "settraceceiling", ceiling: ceilinginput.value === "" ? void 0 : Number(ceilinginput.value) })]).then(() => status(`Profiling settings saved: profile retention ${retentioninput.value === "" ? "keeps every heavy artifact" : `${retentioninput.value} milliseconds`} and trace byte ceiling ${ceilinginput.value === "" ? "none" : `${ceilinginput.value} bytes`}.`)).then(refresh)));
2544
+ }
2261
2545
  //# sourceMappingURL=sidepanel.js.map