@wenathlan/extension 1.1.50 → 1.1.52

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>Debugger</h2><div id="debugger" class="panel"></div></section><section><h2>Profiling</h2><div id="profiling" class="panel"></div></section><section><h2>Emulation</h2><div id="emulation" class="panel"></div></section><section><h2>Sessions</h2><div id="sessions" class="panel"></div></section><section><h2>Workflows</h2><div id="workflows" 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>Emulation</h2><div id="emulation" class="panel"></div></section><section><h2>Sessions</h2><div id="sessions" class="panel"></div></section><section><h2>Workflows</h2><div id="workflows" class="panel"></div></section><section><h2>Triggers</h2><div id="triggers" 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", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow"]);
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", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars"]);
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", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
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", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
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", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch"]);
5
5
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
6
6
 
7
7
  // extension/tabscommand.ts
@@ -75,6 +75,8 @@ var emulationroot = document.querySelector("#emulation");
75
75
  var netviewroot = document.querySelector("#netview");
76
76
  var sessionsroot = document.querySelector("#sessions");
77
77
  var workflowsroot = document.querySelector("#workflows");
78
+ var triggersroot = document.querySelector("#triggers");
79
+ var triggerview = { manual: void 0, history: void 0 };
78
80
  var sessionsview = { term: "", window: "all", diffselection: [], restorereview: void 0, importreview: void 0 };
79
81
  var workflowview = { review: void 0, selected: "" };
80
82
  var statusnode = document.querySelector("#status");
@@ -2539,6 +2541,7 @@ async function refresh() {
2539
2541
  renderemulation(context);
2540
2542
  rendersessions(context);
2541
2543
  renderworkflows(context);
2544
+ rendertriggers(context);
2542
2545
  renderconsolediff();
2543
2546
  renderaudit(context.audit);
2544
2547
  rendercapabilities(context.capabilities);
@@ -2918,6 +2921,90 @@ function renderrestorereview(record) {
2918
2921
  }));
2919
2922
  sessionsroot.append(review);
2920
2923
  }
2924
+ function controlreviewtext(control) {
2925
+ if (control === void 0) return "";
2926
+ if (control.kind === "condition") return ` \xB7 condition ${control.expression ?? "expression"}`;
2927
+ if (control.kind === "branch") return ` \xB7 paths ${(control.paths ?? []).join(", ")} \xB7 else ${control.elsepath ?? "else"} when no path matches`;
2928
+ if (control.kind === "loop") return ` \xB7 loops ${control.list ?? "list"} binding ${control.item ?? "item"} and ${control.index ?? "index"} per iteration \xB7 safety bound ${control.bound ?? 1e3}`;
2929
+ if (control.kind === "repeatuntil") return ` \xB7 repeats until convergence \xB7 safety bound ${control.bound ?? 1e3}`;
2930
+ if (control.kind === "whileloop") return ` \xB7 while the condition holds \xB7 safety bound ${control.bound ?? "reviewed"}`;
2931
+ if (control.kind === "foreach") return ` \xB7 foreach ${control.selector ?? "selector"} binding ${control.item ?? "item"} and ${control.index ?? "index"} per element`;
2932
+ if (control.kind === "parallel") return ` \xB7 branches ${(control.branches ?? []).join(", ")} \xB7 join ${control.strategy ?? "last"} \xB7 on failure ${control.onfail ?? "continue"}`;
2933
+ return ` \xB7 try with catch${control.rerun === true ? " and rerun" : ""}${control.attempts !== void 0 ? ` \xB7 ${control.attempts} attempt${control.attempts === 1 ? "" : "s"} of ${control.backoff ?? "fixed"} backoff` : ""}${control.stepms !== void 0 ? ` \xB7 step budget ${control.stepms} ms` : ""}${control.runms !== void 0 ? ` \xB7 run budget ${control.runms} ms` : ""}`;
2934
+ }
2935
+ function rendercontroldecision(entry) {
2936
+ const block = document.createElement("details");
2937
+ block.className = "sessiongroup";
2938
+ const control = entry.details?.control;
2939
+ const summary = document.createElement("summary");
2940
+ summary.textContent = `control flow \xB7 ${control?.kind ?? "decision"} \xB7 ${entry.summary}`;
2941
+ block.append(summary);
2942
+ if (control?.branch !== void 0) {
2943
+ const line = document.createElement("p");
2944
+ line.textContent = `Chose the path ${control.branch.path}: ${control.branch.reason}`;
2945
+ line.dataset.class = "added";
2946
+ line.dataset.branch = control.branch.path;
2947
+ block.append(line);
2948
+ }
2949
+ if (control?.loops !== void 0 && control.loops.length > 0) {
2950
+ const group = document.createElement("details");
2951
+ group.className = "sessiongroup";
2952
+ const groupsummary = document.createElement("summary");
2953
+ groupsummary.textContent = `Loop iterations (${control.loops.length})`;
2954
+ group.append(groupsummary);
2955
+ for (const counter of control.loops) {
2956
+ const line = document.createElement("p");
2957
+ line.textContent = `${counter.path} \xB7 ${counter.ok ? "completed" : "failed"}`;
2958
+ line.dataset.class = counter.ok ? "added" : "changed";
2959
+ group.append(line);
2960
+ }
2961
+ block.append(group);
2962
+ }
2963
+ if (control?.retries !== void 0 && control.retries.length > 0) {
2964
+ for (const attempt of control.retries) {
2965
+ const line = document.createElement("p");
2966
+ line.textContent = `Retry attempt ${attempt.attempt} after a ${attempt.delay} ms backoff countdown for the ${attempt.errorclass} error class.`;
2967
+ line.dataset.class = "changed";
2968
+ block.append(line);
2969
+ }
2970
+ }
2971
+ if (control?.timeouts !== void 0 && control.timeouts.length > 0) {
2972
+ for (const abort of control.timeouts) {
2973
+ const line = document.createElement("p");
2974
+ line.textContent = `Timeout abort: the ${abort.scope} exceeded its reviewed budget of ${abort.budget} milliseconds.`;
2975
+ line.dataset.class = "changed";
2976
+ line.dataset.timeout = "true";
2977
+ block.append(line);
2978
+ }
2979
+ }
2980
+ if (control?.branches !== void 0 && control.branches.length > 0) {
2981
+ const lanes = document.createElement("details");
2982
+ lanes.className = "sessiongroup";
2983
+ const lannessummary = document.createElement("summary");
2984
+ lannessummary.textContent = `Parallel branch lanes (${control.branches.length})`;
2985
+ lanes.append(lannessummary);
2986
+ for (const outcome of control.branches) {
2987
+ const lane = document.createElement("p");
2988
+ lane.textContent = `lane ${outcome.branchid} \xB7 ${outcome.cancelled === true ? "cancelled" : outcome.ok ? "completed" : "failed"} \xB7 ${outcome.summary}`;
2989
+ lane.dataset.class = outcome.ok && outcome.cancelled !== true ? "added" : "changed";
2990
+ lanes.append(lane);
2991
+ }
2992
+ block.append(lanes);
2993
+ }
2994
+ if (control?.join !== void 0) {
2995
+ const line = document.createElement("p");
2996
+ line.textContent = `Join under the ${control.join.strategy} strategy merged ${control.join.merged.join(", ") || "no variable"}${control.join.conflicts.length > 0 ? ` with the conflicts ${control.join.conflicts.join(", ")}` : " with no conflict"}.`;
2997
+ line.dataset.class = control.join.conflicts.length > 0 ? "changed" : "added";
2998
+ block.append(line);
2999
+ }
3000
+ if (control?.catch !== void 0) {
3001
+ const line = document.createElement("p");
3002
+ line.textContent = `The catch handler ran after the ${control.catch.errorclass} failure${control.catch.rerun ? " and reran the fragile body" : ""}.`;
3003
+ line.dataset.class = "changed";
3004
+ block.append(line);
3005
+ }
3006
+ return block;
3007
+ }
2921
3008
  function renderworkflows(context) {
2922
3009
  if (!workflowsroot) return;
2923
3010
  workflowsroot.replaceChildren();
@@ -2995,8 +3082,30 @@ function renderworkflows(context) {
2995
3082
  const list = document.createElement("ol");
2996
3083
  for (const step of workflowview.review.steps) {
2997
3084
  const line = document.createElement("li");
2998
- line.textContent = `${step.label} (${step.kind}${step.block !== void 0 ? ` \xB7 block ${step.block}` : ""}${step.target !== void 0 ? ` \xB7 ${step.target}` : ""}${step.expression !== void 0 ? ` \xB7 expression ${step.expression.operator} into ${step.expression.result}` : ""}${step.extract !== void 0 && step.extract.groups.length > 0 ? ` \xB7 extracts ${step.extract.groups.join(", ")}` : ""}${Array.isArray(step.bindings) && step.bindings.length > 0 ? ` \xB7 ${step.bindings.length} binding${step.bindings.length === 1 ? "" : "s"}` : ""}`;
3085
+ line.textContent = `${step.label} (${step.kind}${step.block !== void 0 ? ` \xB7 block ${step.block}` : ""}${step.target !== void 0 ? ` \xB7 ${step.target}` : ""}${step.expression !== void 0 ? ` \xB7 expression ${step.expression.operator} into ${step.expression.result}` : ""}${step.extract !== void 0 && step.extract.groups.length > 0 ? ` \xB7 extracts ${step.extract.groups.join(", ")}` : ""}${Array.isArray(step.bindings) && step.bindings.length > 0 ? ` \xB7 ${step.bindings.length} binding${step.bindings.length === 1 ? "" : "s"}` : ""}${controlreviewtext(step.control)}`;
2999
3086
  list.append(line);
3087
+ if (step.control !== void 0 && (step.control.kind === "loop" || step.control.kind === "repeatuntil")) {
3088
+ const boundrow = document.createElement("div");
3089
+ boundrow.className = "actions";
3090
+ const boundlabel = document.createElement("label");
3091
+ boundlabel.textContent = `Safety bound of ${step.label}: `;
3092
+ const boundinput = document.createElement("input");
3093
+ boundinput.type = "number";
3094
+ boundinput.min = "1";
3095
+ boundinput.value = String(step.control.bound ?? 1e3);
3096
+ boundlabel.append(boundinput);
3097
+ boundrow.append(boundlabel, " ", button("Apply bound before a run", async () => {
3098
+ const bound = Number(boundinput.value);
3099
+ if (!Number.isInteger(bound) || bound < 1) {
3100
+ status("The loop safety bound must be a positive integer with no code ceiling.", true);
3101
+ return;
3102
+ }
3103
+ const result = await request({ kind: "setloopbound", workflowid: workflowview.review?.workflowid, stepid: step.id, bound });
3104
+ status(`Loop bound applied: the workflow was recomposed as version ${result.version} and the older version survives for the audit trail.`);
3105
+ await refresh();
3106
+ }));
3107
+ list.append(boundrow);
3108
+ }
3000
3109
  }
3001
3110
  review.append(list);
3002
3111
  review.append(button("Close workflow review", async () => {
@@ -3059,6 +3168,7 @@ function renderworkflows(context) {
3059
3168
  line.textContent = `${entry.state} \xB7 ${entry.label} \xB7 ${entry.duration} ms${entry.produced !== void 0 && entry.produced.length > 0 ? ` \xB7 produced ${entry.produced.join(", ")}` : ""}${entry.consumed !== void 0 && entry.consumed.length > 0 ? ` \xB7 consumed ${entry.consumed.join(", ")}` : ""} \xB7 ${entry.summary}`;
3060
3169
  line.dataset.class = entry.state === "failed" || entry.state === "refused" ? "changed" : "added";
3061
3170
  runlog.append(line);
3171
+ if (entry.details !== void 0 && entry.details.control !== void 0) runlog.append(rendercontroldecision(entry));
3062
3172
  }
3063
3173
  timeline.append(runlog);
3064
3174
  workflowsroot.append(timeline);
@@ -3092,4 +3202,159 @@ function renderworkflows(context) {
3092
3202
  }
3093
3203
  }
3094
3204
  }
3205
+ function rendertriggers(context) {
3206
+ if (!triggersroot) return;
3207
+ triggersroot.replaceChildren();
3208
+ const rules = context.trigger?.rules ?? [];
3209
+ const queued = context.trigger?.queued ?? 0;
3210
+ const workflows = context.workflow?.workflows ?? [];
3211
+ const title = document.createElement("p");
3212
+ title.textContent = `${rules.length} armed rule${rules.length === 1 ? "" : "s"} across ${new Set(rules.map((rule) => rule.workflowid)).size} workflow${new Set(rules.map((rule) => rule.workflowid)).size === 1 ? "" : "s"} \xB7 ${queued} queued fire${queued === 1 ? "" : "s"}${context.session?.pausedat !== void 0 ? " held while the session is paused" : ""}.`;
3213
+ triggersroot.append(title);
3214
+ const byworkflow = /* @__PURE__ */ new Map();
3215
+ for (const rule of rules) {
3216
+ const group = byworkflow.get(rule.workflowid) ?? [];
3217
+ group.push(rule);
3218
+ byworkflow.set(rule.workflowid, group);
3219
+ }
3220
+ for (const [workflowid, group] of byworkflow) {
3221
+ const workflowname = group[0]?.workflowname ?? workflowid;
3222
+ const box = document.createElement("details");
3223
+ box.className = "sessiongroup";
3224
+ box.open = true;
3225
+ const summary = document.createElement("summary");
3226
+ summary.textContent = `${workflowname} \xB7 ${group.length} rule${group.length === 1 ? "" : "s"}`;
3227
+ box.append(summary);
3228
+ for (const rule of group) {
3229
+ const row = document.createElement("div");
3230
+ row.className = "sessionrow";
3231
+ const headline = document.createElement("p");
3232
+ const badge = document.createElement("span");
3233
+ badge.className = "sessionbadge";
3234
+ badge.dataset.restored = "false";
3235
+ badge.textContent = rule.enabled ? rule.paused === true ? "paused" : "enabled" : "disabled";
3236
+ const match = rule.summary.pattern !== void 0 ? String(rule.summary.pattern) : rule.summary.origins !== void 0 ? rule.summary.origins.join(", ") : rule.summary.cron !== void 0 ? `${String(rule.summary.cron)}${rule.summary.timezone !== void 0 ? ` (${String(rule.summary.timezone)})` : ""}` : rule.summary.period !== void 0 ? `every ${String(rule.summary.period)} ms${rule.summary.jitter !== void 0 ? ` \xB1 ${String(rule.summary.jitter)} ms` : ""}` : rule.summary.title !== void 0 ? String(rule.summary.title) : rule.summary.command !== void 0 ? String(rule.summary.command) : rule.summary.events !== void 0 ? rule.summary.events.join(", ") : rule.kind === "urllist" ? `${rule.summary.urls?.length ?? 0} urls` : rule.kind === "webhook" ? `webhook with ${String(rule.summary.fields ?? 0)} schema fields` : "toolbar button";
3237
+ headline.append(`${rule.label} \xB7 ${rule.kind} \xB7 ${match} \xB7 cooldown ${rule.cooldown} ms \xB7 ${rule.fires} fire${rule.fires === 1 ? "" : "s"}, ${rule.launches} launch${rule.launches === 1 ? "" : "es"}, ${rule.suppressions} suppressed${rule.nextfireat !== void 0 ? ` \xB7 next fire ${new Date(rule.nextfireat).toISOString()}` : ""}`, badge);
3238
+ row.append(headline);
3239
+ const actions = document.createElement("div");
3240
+ actions.className = "actions";
3241
+ actions.append(button(rule.enabled ? "Disable" : "Enable", async () => {
3242
+ await request({ kind: "toggletrigger", ruleid: rule.id, enabled: !rule.enabled });
3243
+ status(`The ${rule.kind} rule is now ${rule.enabled ? "disabled" : "enabled"}.`);
3244
+ await refresh();
3245
+ }));
3246
+ actions.append(" ", button("Fire history", async () => {
3247
+ const result = await request({ kind: "triggerhistory", ruleid: rule.id });
3248
+ triggerview.history = result.fires;
3249
+ status(`Fire history: ${result.fires.length} fire record${result.fires.length === 1 ? "" : "s"} of the ${rule.kind} rule.`);
3250
+ await refresh();
3251
+ }));
3252
+ actions.append(" ", button("Fire manually", async () => {
3253
+ const result = await request({ kind: "firetrigger", ruleid: rule.id });
3254
+ status(result.fired ? `The ${rule.kind} rule fired${result.queued === true ? " and queued for the busy run" : ""}.` : `The ${rule.kind} rule suppressed the fire: ${result.suppressed ?? "review gate"}.`);
3255
+ await refresh();
3256
+ }));
3257
+ if (rule.kind === "webhook") actions.append(" ", button("Rotate secret", async () => {
3258
+ const result = await request({ kind: "rotatetriggersecret", ruleid: rule.id });
3259
+ status(`The webhook secret rotated to ${result.secret}; it was shown once and never leaves the store.`);
3260
+ await refresh();
3261
+ }));
3262
+ if (workflows.length > 1) actions.append(" ", button("Duplicate to second workflow", async () => {
3263
+ const target = workflows.find((record) => record.id !== rule.workflowid);
3264
+ if (!target) {
3265
+ status("No second composed workflow exists to duplicate the rule to.", true);
3266
+ return;
3267
+ }
3268
+ await request({ kind: "duplicatetrigger", ruleid: rule.id, workflowid: target.id });
3269
+ status(`Duplicated the ${rule.kind} rule to ${target.name}.`);
3270
+ await refresh();
3271
+ }));
3272
+ row.append(actions);
3273
+ box.append(row);
3274
+ }
3275
+ const workflowactions = document.createElement("div");
3276
+ workflowactions.className = "actions";
3277
+ workflowactions.append(button("Create visit rule from current page", async () => {
3278
+ await request({ kind: "createvisitrule", workflowid });
3279
+ status(`Armed a visit rule of the current page origin for ${workflowname}.`);
3280
+ await refresh();
3281
+ }));
3282
+ workflowactions.append(" ", button("Manual run preview", async () => {
3283
+ const result = await request({ kind: "manualrun", workflowid });
3284
+ triggerview.manual = { ...result.manualrun, at: Date.now() };
3285
+ status(`Manual run preview: ${result.manualrun.preview.length} steps of ${workflowname}; nothing runs before the confirmation.`);
3286
+ await refresh();
3287
+ }));
3288
+ box.append(workflowactions);
3289
+ triggersroot.append(box);
3290
+ }
3291
+ if (rules.length === 0) {
3292
+ const empty = document.createElement("p");
3293
+ empty.textContent = "No armed trigger rule yet; arm a reviewed rule of any family or create a visit rule from the current page.";
3294
+ triggersroot.append(empty);
3295
+ }
3296
+ if (triggerview.history !== void 0) {
3297
+ const history = document.createElement("details");
3298
+ history.className = "sessiongroup";
3299
+ const summary = document.createElement("summary");
3300
+ summary.textContent = `Fire history (${triggerview.history.length} records)`;
3301
+ history.append(summary);
3302
+ for (const fire of triggerview.history.slice(0, 25)) {
3303
+ const line = document.createElement("p");
3304
+ line.textContent = `${new Date(fire.at).toISOString()} \xB7 ${fire.cause}${fire.url !== void 0 ? ` \xB7 ${fire.url}` : ""}${fire.title !== void 0 ? ` \xB7 ${fire.title}` : ""}`;
3305
+ history.append(line);
3306
+ }
3307
+ triggersroot.append(history);
3308
+ }
3309
+ if (triggerview.manual !== void 0) {
3310
+ const preview = document.createElement("div");
3311
+ preview.className = "sessionrow";
3312
+ const headline = document.createElement("p");
3313
+ headline.textContent = `Manual run step preview: ${triggerview.manual.preview.length} expanded step${triggerview.manual.preview.length === 1 ? "" : "s"}; approve or cancel before anything runs.`;
3314
+ preview.append(headline);
3315
+ for (const step of triggerview.manual.preview) {
3316
+ const line = document.createElement("p");
3317
+ line.textContent = `${step.stepid} \xB7 ${step.kind} \xB7 ${step.label}${step.block !== void 0 ? ` \xB7 block ${step.block}` : ""}${step.control !== void 0 ? ` \xB7 ${Object.entries(step.control).map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(", ") : String(value)}`).join(" \xB7 ")}` : ""}`;
3318
+ preview.append(line);
3319
+ }
3320
+ const actions = document.createElement("div");
3321
+ actions.className = "actions";
3322
+ actions.append(button("Approve manual run", async () => {
3323
+ const result = await request({ kind: "confirmmanualrun", previewid: triggerview.manual?.id, confirmed: true });
3324
+ status(`Manual run approved and launched${result.runid !== void 0 ? ` as run ${result.runid}` : ""}; the run ended ${result.state ?? "running"}.`);
3325
+ triggerview.manual = void 0;
3326
+ await refresh();
3327
+ }));
3328
+ actions.append(" ", button("Cancel manual run", async () => {
3329
+ await request({ kind: "confirmmanualrun", previewid: triggerview.manual?.id, confirmed: false });
3330
+ status("Manual run cancelled after the step preview; nothing ran.");
3331
+ triggerview.manual = void 0;
3332
+ await refresh();
3333
+ }));
3334
+ preview.append(actions);
3335
+ triggersroot.append(preview);
3336
+ }
3337
+ const settings = document.createElement("details");
3338
+ settings.className = "sessiongroup";
3339
+ const settingsummary = document.createElement("summary");
3340
+ settingsummary.textContent = "Trigger settings";
3341
+ settings.append(settingsummary);
3342
+ const retention = document.createElement("p");
3343
+ retention.textContent = `Fire record retention: ${context.triggerretention === void 0 ? "keep every fire record" : `${context.triggerretention} record${context.triggerretention === 1 ? "" : "s"}`}; the rule counters always survive and no code ceiling applies.`;
3344
+ settings.append(retention);
3345
+ const retentionactions = document.createElement("div");
3346
+ retentionactions.className = "actions";
3347
+ retentionactions.append(button("Keep every fire record", async () => {
3348
+ await request({ kind: "settriggerretention" });
3349
+ status("Trigger fire retention keeps every record.");
3350
+ await refresh();
3351
+ }));
3352
+ retentionactions.append(" ", button("Keep last 100 fire records", async () => {
3353
+ await request({ kind: "settriggerretention", retention: 100 });
3354
+ status("Trigger fire retention keeps the last 100 records.");
3355
+ await refresh();
3356
+ }));
3357
+ settings.append(retentionactions);
3358
+ triggersroot.append(settings);
3359
+ }
3095
3360
  //# sourceMappingURL=sidepanel.js.map