@wenathlan/extension 1.1.44 → 1.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +438 -4
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +39 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +23 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +31 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/runtimeline.d.ts +122 -0
- package/dist/runtimeline.d.ts.map +1 -0
- package/dist/types.d.ts +134 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +488 -7
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +205 -5
- package/extension/dist/pagebridge.js.map +4 -4
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +12 -1
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +152 -1
- package/extension/dist/sidepanel.js.map +2 -2
- package/extension/dist/style.css +4 -0
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -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>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>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
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
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"]);
|
|
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"]);
|
|
5
5
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
6
6
|
|
|
7
7
|
// extension/tabscommand.ts
|
|
@@ -67,11 +67,15 @@ var capturesroot = document.querySelector("#captures");
|
|
|
67
67
|
var mediaroot = document.querySelector("#media");
|
|
68
68
|
var callsroot = document.querySelector("#calls");
|
|
69
69
|
var trafficroot = document.querySelector("#traffic");
|
|
70
|
+
var timelineroot = document.querySelector("#timeline");
|
|
71
|
+
var consolediffroot = document.querySelector("#consolediff");
|
|
70
72
|
var netviewroot = document.querySelector("#netview");
|
|
71
73
|
var statusnode = document.querySelector("#status");
|
|
72
74
|
var progressnode = document.querySelector("#planprogress");
|
|
73
75
|
var capabilitiestext = document.querySelector("#capabilitiestext");
|
|
74
76
|
var previews = /* @__PURE__ */ new Map();
|
|
77
|
+
var timelinefilter = { level: "", source: "", stepid: "" };
|
|
78
|
+
var lastdiff;
|
|
75
79
|
function options(step) {
|
|
76
80
|
if (!step.options) return {};
|
|
77
81
|
try {
|
|
@@ -2071,6 +2075,151 @@ function renderdiagnostic(report) {
|
|
|
2071
2075
|
diagnosticroot.append(item);
|
|
2072
2076
|
}
|
|
2073
2077
|
}
|
|
2078
|
+
function rendertimeline(context) {
|
|
2079
|
+
if (!timelineroot) return;
|
|
2080
|
+
timelineroot.replaceChildren();
|
|
2081
|
+
const waiting = (context.consoleconsents ?? []).filter((consent) => consent.approved === void 0);
|
|
2082
|
+
for (const consent of waiting) {
|
|
2083
|
+
const card = document.createElement("div");
|
|
2084
|
+
card.className = "consentcard";
|
|
2085
|
+
const prompt = document.createElement("p");
|
|
2086
|
+
prompt.textContent = `Console capture consent: ${consent.prompt}`;
|
|
2087
|
+
card.append(prompt, button("Approve console capture", () => request({ kind: "approveconsoleconsent", id: consent.id }).then(() => status(`Console capture on ${consent.origin} approved; run the watchconsole step again.`)).then(refresh)));
|
|
2088
|
+
timelineroot.append(card);
|
|
2089
|
+
}
|
|
2090
|
+
const entries = context.timeline?.entries ?? [];
|
|
2091
|
+
const errors = context.timeline?.errors ?? [];
|
|
2092
|
+
const rejections = context.timeline?.rejections ?? [];
|
|
2093
|
+
const longtasks = context.timeline?.longtasks ?? [];
|
|
2094
|
+
if (entries.length === 0 && errors.length === 0 && rejections.length === 0 && longtasks.length === 0) {
|
|
2095
|
+
timelineroot.textContent = "Run watchconsole, watcherrors or watchtasks steps to fill the run timeline.";
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
const levels = ["error", "warn", "info", "log", "debug", "trace"];
|
|
2099
|
+
const sources = ["console", "error", "rejection", "resource", "longtask", "network"];
|
|
2100
|
+
const filters = document.createElement("div");
|
|
2101
|
+
filters.className = "actions";
|
|
2102
|
+
for (const level of levels) filters.append(button(timelinefilter.level === level ? `level ${level} \u2713` : `level ${level}`, async () => {
|
|
2103
|
+
timelinefilter.level = timelinefilter.level === level ? "" : level;
|
|
2104
|
+
await refresh();
|
|
2105
|
+
}));
|
|
2106
|
+
for (const source of sources) filters.append(button(timelinefilter.source === source ? `source ${source} \u2713` : `source ${source}`, async () => {
|
|
2107
|
+
timelinefilter.source = timelinefilter.source === source ? "" : source;
|
|
2108
|
+
await refresh();
|
|
2109
|
+
}));
|
|
2110
|
+
timelineroot.append(filters);
|
|
2111
|
+
const stepids = [...new Set(entries.map((entry) => entry.stepid))];
|
|
2112
|
+
if (stepids.length > 1) {
|
|
2113
|
+
const select = document.createElement("select");
|
|
2114
|
+
select.style.width = "100%";
|
|
2115
|
+
const any = document.createElement("option");
|
|
2116
|
+
any.value = "";
|
|
2117
|
+
any.textContent = "every step";
|
|
2118
|
+
select.append(any);
|
|
2119
|
+
for (const stepid of stepids) {
|
|
2120
|
+
const option = document.createElement("option");
|
|
2121
|
+
option.value = stepid;
|
|
2122
|
+
option.textContent = `step ${stepid}`;
|
|
2123
|
+
if (timelinefilter.stepid === stepid) option.selected = true;
|
|
2124
|
+
select.append(option);
|
|
2125
|
+
}
|
|
2126
|
+
select.addEventListener("change", () => {
|
|
2127
|
+
timelinefilter.stepid = select.value;
|
|
2128
|
+
void refresh();
|
|
2129
|
+
});
|
|
2130
|
+
timelineroot.append(select);
|
|
2131
|
+
}
|
|
2132
|
+
const shown = entries.filter((entry) => (timelinefilter.level === "" || entry.level === timelinefilter.level) && (timelinefilter.source === "" || entry.source === timelinefilter.source) && (timelinefilter.stepid === "" || entry.stepid === timelinefilter.stepid)).slice().reverse().slice(0, 60);
|
|
2133
|
+
const list = document.createElement("ul");
|
|
2134
|
+
list.className = "audit";
|
|
2135
|
+
for (const entry of shown) {
|
|
2136
|
+
const item = document.createElement("li");
|
|
2137
|
+
item.className = "timelinerow";
|
|
2138
|
+
item.dataset.level = entry.level;
|
|
2139
|
+
const head = document.createElement("p");
|
|
2140
|
+
head.className = "timeline";
|
|
2141
|
+
head.textContent = `${new Date(entry.time).toLocaleTimeString()} \xB7 ${entry.level} \xB7 ${entry.source} \xB7 step ${entry.stepid}${entry.repeat !== void 0 && entry.repeat > 1 ? ` \xB7 collapsed \xD7${entry.repeat}` : ""}`;
|
|
2142
|
+
const message = document.createElement("p");
|
|
2143
|
+
message.textContent = entry.message;
|
|
2144
|
+
item.append(head, message);
|
|
2145
|
+
if (entry.level === "error" && (entry.source === "error" || entry.source === "rejection")) {
|
|
2146
|
+
const record = entry.source === "error" ? errors.find((candidate) => candidate.stepid === entry.stepid && candidate.message === entry.message) : rejections.find((candidate) => candidate.stepid === entry.stepid && candidate.reason === entry.message);
|
|
2147
|
+
const frames = record && "frames" in record ? record.frames : [];
|
|
2148
|
+
if (frames.length > 0) {
|
|
2149
|
+
const expand = document.createElement("details");
|
|
2150
|
+
const summary = document.createElement("summary");
|
|
2151
|
+
summary.textContent = `${frames.length} stack frame${frames.length === 1 ? "" : "s"}`;
|
|
2152
|
+
const pre = document.createElement("pre");
|
|
2153
|
+
pre.textContent = frames.map((frame) => `at ${frame.functionname ?? "<anonymous>"} (${frame.url}:${frame.line}${frame.column !== void 0 ? `:${frame.column}` : ""})`).join("\n");
|
|
2154
|
+
expand.append(summary, pre);
|
|
2155
|
+
item.append(expand);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
list.append(item);
|
|
2159
|
+
}
|
|
2160
|
+
timelineroot.append(list);
|
|
2161
|
+
const maxtask = longtasks.reduce((max, task) => Math.max(max, task.duration), 0);
|
|
2162
|
+
for (const task of longtasks.slice(0, 12)) {
|
|
2163
|
+
const bar = document.createElement("div");
|
|
2164
|
+
bar.className = "taskbar";
|
|
2165
|
+
const label = document.createElement("p");
|
|
2166
|
+
label.className = "timeline";
|
|
2167
|
+
label.textContent = `long task \xB7 ${task.duration} ms${task.attributions.length > 0 ? ` \xB7 ${task.attributions.join(", ")}` : ""} \xB7 step ${task.stepid}`;
|
|
2168
|
+
const gauge = document.createElement("div");
|
|
2169
|
+
gauge.className = "taskgauge";
|
|
2170
|
+
const fill = document.createElement("div");
|
|
2171
|
+
fill.className = "taskfill";
|
|
2172
|
+
fill.style.width = maxtask > 0 ? `${Math.round(task.duration / maxtask * 100)}%` : "0%";
|
|
2173
|
+
gauge.append(fill);
|
|
2174
|
+
bar.append(label, gauge);
|
|
2175
|
+
timelineroot.append(bar);
|
|
2176
|
+
}
|
|
2177
|
+
const counts = context.timeline?.levelcounts ?? {};
|
|
2178
|
+
const summaryline = document.createElement("p");
|
|
2179
|
+
summaryline.className = "muted";
|
|
2180
|
+
const expired = (context.levelsummaries ?? []).reduce((total, item) => total + Object.values(item.counts).reduce((sum, count) => sum + count, 0), 0);
|
|
2181
|
+
summaryline.textContent = `${entries.length} live entr${entries.length === 1 ? "y" : "ies"} (${levels.map((level) => `${counts[level] ?? 0} ${level}`).join(" \xB7 ")})${expired > 0 ? ` \xB7 ${expired} expired into level summaries` : ""}${(context.rotationtargets ?? []).length > 0 ? ` \xB7 ${(context.rotationtargets ?? []).reduce((total, target) => total + target.entries, 0)} rotated to overflow stores` : ""}.`;
|
|
2182
|
+
const retentioninput = document.createElement("input");
|
|
2183
|
+
retentioninput.type = "number";
|
|
2184
|
+
retentioninput.min = "0";
|
|
2185
|
+
retentioninput.placeholder = "timeline retention";
|
|
2186
|
+
retentioninput.value = context.timelineretention !== void 0 ? String(context.timelineretention) : "";
|
|
2187
|
+
timelineroot.append(summaryline, retentioninput, button("Save timeline retention", () => request({ kind: "settimelineretention", retention: retentioninput.value === "" ? void 0 : Number(retentioninput.value) }).then(() => status(`Timeline retention saved as ${retentioninput.value === "" ? "keep every entry" : retentioninput.value} entries; level count summaries always survive.`)).then(refresh)));
|
|
2188
|
+
}
|
|
2189
|
+
function renderconsolediff() {
|
|
2190
|
+
if (!consolediffroot) return;
|
|
2191
|
+
consolediffroot.replaceChildren();
|
|
2192
|
+
const baseinput = document.createElement("input");
|
|
2193
|
+
baseinput.placeholder = "base run id";
|
|
2194
|
+
const targetinput = document.createElement("input");
|
|
2195
|
+
targetinput.placeholder = "target run id";
|
|
2196
|
+
consolediffroot.append(baseinput, targetinput, button("Compare console output", () => request({ kind: "consolediff", base: baseinput.value, target: targetinput.value }).then((value) => {
|
|
2197
|
+
const parsed = value;
|
|
2198
|
+
if (!parsed) throw new Error("The console diff returned no result.");
|
|
2199
|
+
lastdiff = parsed.diff;
|
|
2200
|
+
status(`Diffed runs ${parsed.diff.base} and ${parsed.diff.target}: ${parsed.diff.added} added, ${parsed.diff.removed} removed and ${parsed.diff.repeated} repeated line${parsed.diff.added + parsed.diff.removed + parsed.diff.repeated === 1 ? "" : "s"}.`);
|
|
2201
|
+
renderconsolediff();
|
|
2202
|
+
})));
|
|
2203
|
+
if (!lastdiff) {
|
|
2204
|
+
const hint = document.createElement("p");
|
|
2205
|
+
hint.className = "muted";
|
|
2206
|
+
hint.textContent = "Compare the console output of two runs to see added, removed and repeated lines.";
|
|
2207
|
+
consolediffroot.append(hint);
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
const headline = document.createElement("p");
|
|
2211
|
+
headline.className = "muted";
|
|
2212
|
+
headline.textContent = `Run ${lastdiff.base} became run ${lastdiff.target}: ${lastdiff.added} added, ${lastdiff.removed} removed and ${lastdiff.repeated} repeated.`;
|
|
2213
|
+
const list = document.createElement("ul");
|
|
2214
|
+
list.className = "audit";
|
|
2215
|
+
for (const line of lastdiff.lines.slice(0, 80)) {
|
|
2216
|
+
const item = document.createElement("li");
|
|
2217
|
+
item.className = `diffrow ${line.kind}`;
|
|
2218
|
+
item.textContent = `${line.kind}${line.count !== void 0 ? ` \xD7${line.count}` : ""}: ${line.text}`;
|
|
2219
|
+
list.append(item);
|
|
2220
|
+
}
|
|
2221
|
+
consolediffroot.append(headline, list);
|
|
2222
|
+
}
|
|
2074
2223
|
async function refresh() {
|
|
2075
2224
|
const context = await request({ kind: "context" });
|
|
2076
2225
|
renderplan(context.plan, context.progress, context.outcomes ?? [], context.retries ?? []);
|
|
@@ -2094,6 +2243,8 @@ async function refresh() {
|
|
|
2094
2243
|
rendercalls(context);
|
|
2095
2244
|
rendernetview(context);
|
|
2096
2245
|
rendertraffic(context);
|
|
2246
|
+
rendertimeline(context);
|
|
2247
|
+
renderconsolediff();
|
|
2097
2248
|
renderaudit(context.audit);
|
|
2098
2249
|
rendercapabilities(context.capabilities);
|
|
2099
2250
|
if (context.session?.pausedat) status("Session paused. Reviewed actions are blocked until resume.");
|