@wenathlan/extension 1.1.53 → 1.1.55
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 +6 -5
- package/dist/approvalgate.d.ts +39 -0
- package/dist/approvalgate.d.ts.map +1 -0
- package/dist/clientauth.d.ts +114 -0
- package/dist/clientauth.d.ts.map +1 -0
- package/dist/httpstream.d.ts +92 -0
- package/dist/httpstream.d.ts.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5408 -4608
- package/dist/index.js.map +4 -4
- package/dist/mcpserver.d.ts +180 -0
- package/dist/mcpserver.d.ts.map +1 -0
- package/dist/memory.d.ts +63 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +43 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +99 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/toolcatalog.d.ts +31 -0
- package/dist/toolcatalog.d.ts.map +1 -0
- package/dist/types.d.ts +311 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +1026 -4
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +1 -1
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +13 -1
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +297 -1
- package/extension/dist/sidepanel.js.map +3 -3
- 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>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>Workflow editor</h2><div id="workfloweditor" 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>
|
|
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>Workflow editor</h2><div id="workfloweditor" class="panel"></div></section><section><h2>Triggers</h2><div id="triggers" class="panel"></div></section><section><h2>Agent protocol</h2><div id="agentprotocol" 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>
|
|
@@ -74,7 +74,7 @@ function regexruleof(value) {
|
|
|
74
74
|
// policy.ts
|
|
75
75
|
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"]);
|
|
76
76
|
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"]);
|
|
77
|
-
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"]);
|
|
77
|
+
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", "listruns", "condition", "branch"]);
|
|
78
78
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
79
79
|
|
|
80
80
|
// workfloweditor.ts
|
|
@@ -392,6 +392,7 @@ var sessionsroot = document.querySelector("#sessions");
|
|
|
392
392
|
var workflowsroot = document.querySelector("#workflows");
|
|
393
393
|
var workfloweditorroot = document.querySelector("#workfloweditor");
|
|
394
394
|
var triggersroot = document.querySelector("#triggers");
|
|
395
|
+
var agentprotocolroot = document.querySelector("#agentprotocol");
|
|
395
396
|
var triggerview = { manual: void 0, history: void 0 };
|
|
396
397
|
var sessionsview = { term: "", window: "all", diffselection: [], restorereview: void 0, importreview: void 0 };
|
|
397
398
|
var workflowview = { review: void 0, selected: "" };
|
|
@@ -2874,6 +2875,7 @@ async function refresh() {
|
|
|
2874
2875
|
renderworkflows(context);
|
|
2875
2876
|
renderworkfloweditor(context);
|
|
2876
2877
|
rendertriggers(context);
|
|
2878
|
+
renderagentprotocol(context);
|
|
2877
2879
|
renderconsolediff();
|
|
2878
2880
|
renderaudit(context.audit);
|
|
2879
2881
|
rendercapabilities(context.capabilities);
|
|
@@ -4640,4 +4642,298 @@ function rendertriggers(context) {
|
|
|
4640
4642
|
settings.append(retentionactions);
|
|
4641
4643
|
triggersroot.append(settings);
|
|
4642
4644
|
}
|
|
4645
|
+
function renderagentprotocol(context) {
|
|
4646
|
+
if (!agentprotocolroot) return;
|
|
4647
|
+
agentprotocolroot.replaceChildren();
|
|
4648
|
+
const mcp = context.mcp;
|
|
4649
|
+
if (!mcp) {
|
|
4650
|
+
const empty = document.createElement("p");
|
|
4651
|
+
empty.textContent = "The agent protocol state is unknown.";
|
|
4652
|
+
agentprotocolroot.append(empty);
|
|
4653
|
+
return;
|
|
4654
|
+
}
|
|
4655
|
+
const running = mcp.state === "running";
|
|
4656
|
+
const head = document.createElement("p");
|
|
4657
|
+
head.textContent = `Server ${mcp.state} \xB7 ${mcp.bind}:${mcp.port}${mcp.localhost ? " (localhost bind)" : " (remote bind behind the explicit review)"} \xB7 transports ${mcp.config.transports.join(" and ")} \xB7 ${mcp.catalog.tools.length} tools \xB7 ${mcp.clients.length} connected client${mcp.clients.length === 1 ? "" : "s"}.`;
|
|
4658
|
+
agentprotocolroot.append(head);
|
|
4659
|
+
const controls = document.createElement("div");
|
|
4660
|
+
controls.className = "actions";
|
|
4661
|
+
controls.append(button(running ? "Stop server" : "Start server", async () => {
|
|
4662
|
+
await request({ kind: running ? "mcpserverstop" : "mcpserverstart" });
|
|
4663
|
+
status(running ? "The mcp server stopped; no tool call passes the gates." : "The mcp server started on the localhost bind; every client waits for the pairing approval.");
|
|
4664
|
+
await refresh();
|
|
4665
|
+
}));
|
|
4666
|
+
const bindinput = document.createElement("input");
|
|
4667
|
+
bindinput.placeholder = "bind address (empty keeps localhost)";
|
|
4668
|
+
bindinput.value = mcp.config.bind ?? "";
|
|
4669
|
+
const portinput = document.createElement("input");
|
|
4670
|
+
portinput.placeholder = "port";
|
|
4671
|
+
portinput.value = String(mcp.config.port);
|
|
4672
|
+
controls.append(" ", bindinput, " ", portinput, " ", button("Save config", async () => {
|
|
4673
|
+
await request({ kind: "mcpserverconfig", bind: bindinput.value, port: Number(portinput.value), ...bindinput.value.trim() !== "" && bindinput.value.trim() !== "127.0.0.1" && bindinput.value.trim() !== "localhost" && bindinput.value.trim() !== "::1" ? { remote: true } : {} });
|
|
4674
|
+
status(`Saved the mcp server config for ${bindinput.value.trim() === "" ? "127.0.0.1" : bindinput.value.trim()}:${portinput.value}.`);
|
|
4675
|
+
await refresh();
|
|
4676
|
+
}));
|
|
4677
|
+
agentprotocolroot.append(controls);
|
|
4678
|
+
if (mcp.bridge !== void 0) {
|
|
4679
|
+
const bridge = document.createElement("p");
|
|
4680
|
+
bridge.textContent = `Stdio bridge ${mcp.bridge.connected ? "connected" : "disconnected"} on the ${mcp.bridge.host} host \xB7 ${mcp.bridge.restarts} restart${mcp.bridge.restarts === 1 ? "" : "s"} \xB7 ${mcp.bridge.received} inbound and ${mcp.bridge.sent} outbound frame${mcp.bridge.sent === 1 ? "" : "s"}${mcp.launches.length > 0 ? ` \xB7 last launch pid ${mcp.launches[0]?.pid ?? "unknown"}` : " \xB7 no host launch reported yet"}.`;
|
|
4681
|
+
agentprotocolroot.append(bridge);
|
|
4682
|
+
const bridgeactions = document.createElement("div");
|
|
4683
|
+
bridgeactions.className = "actions";
|
|
4684
|
+
bridgeactions.append(button("Restart bridge", async () => {
|
|
4685
|
+
await request({ kind: "mcpbridge", action: "restart" });
|
|
4686
|
+
status("The stdio bridge restart ran; the browser exposes the native messaging host only under a native messaging permission.");
|
|
4687
|
+
await refresh();
|
|
4688
|
+
}));
|
|
4689
|
+
agentprotocolroot.append(bridgeactions);
|
|
4690
|
+
}
|
|
4691
|
+
const clientsbox = document.createElement("details");
|
|
4692
|
+
clientsbox.className = "sessiongroup";
|
|
4693
|
+
clientsbox.open = true;
|
|
4694
|
+
const clientsummary = document.createElement("summary");
|
|
4695
|
+
clientsummary.textContent = `Connected clients (${mcp.clients.length})`;
|
|
4696
|
+
clientsbox.append(clientsummary);
|
|
4697
|
+
for (const client of mcp.clients) {
|
|
4698
|
+
const row = document.createElement("div");
|
|
4699
|
+
row.className = "sessionrow";
|
|
4700
|
+
const headline = document.createElement("p");
|
|
4701
|
+
const badge = document.createElement("span");
|
|
4702
|
+
badge.className = "sessionbadge";
|
|
4703
|
+
badge.dataset.restored = "false";
|
|
4704
|
+
badge.textContent = client.paired ? "paired" : "waiting for approval";
|
|
4705
|
+
headline.append(`${client.id} \xB7 ${client.transport}${client.fingerprint !== void 0 ? ` \xB7 ${client.fingerprint.slice(0, 12)}` : ""}${client.capabilities !== void 0 ? ` \xB7 protocol ${client.capabilities.protocolversion} \xB7 tool floor ${client.toolfloor ?? client.capabilities.toolversion} \xB7 ${client.capabilities.tools} tools` : " \xB7 not negotiated yet"}`, badge);
|
|
4706
|
+
row.append(headline);
|
|
4707
|
+
const actions = document.createElement("div");
|
|
4708
|
+
actions.className = "actions";
|
|
4709
|
+
if (!client.paired) {
|
|
4710
|
+
actions.append(button("Approve pairing", async () => {
|
|
4711
|
+
await request({ kind: "mcpclientdecision", clientid: client.id, approved: true });
|
|
4712
|
+
status(`Approved the pairing of the client ${client.id}; its tool calls now pass the same consent gates.`);
|
|
4713
|
+
await refresh();
|
|
4714
|
+
}));
|
|
4715
|
+
actions.append(" ", button("Refuse pairing", async () => {
|
|
4716
|
+
await request({ kind: "mcpclientdecision", clientid: client.id, approved: false });
|
|
4717
|
+
status(`Refused and disconnected the client ${client.id}.`);
|
|
4718
|
+
await refresh();
|
|
4719
|
+
}));
|
|
4720
|
+
}
|
|
4721
|
+
actions.append(button("Disconnect", async () => {
|
|
4722
|
+
await request({ kind: "mcpclientdisconnect", clientid: client.id });
|
|
4723
|
+
status(`Disconnected the client ${client.id}; its record stays for the audit trail.`);
|
|
4724
|
+
await refresh();
|
|
4725
|
+
}));
|
|
4726
|
+
const clienttokens = mcp.tokens.filter((token) => token.clientid === client.id && token.revokedat === void 0);
|
|
4727
|
+
for (const token of clienttokens) {
|
|
4728
|
+
const tokenline = document.createElement("p");
|
|
4729
|
+
const remaining = Math.max(0, Math.round((token.expiresat - Date.now()) / 1e3));
|
|
4730
|
+
tokenline.textContent = `Session token ${token.id.slice(0, 8)} \xB7 scopes ${token.scopes.join(", ") || "none"} \xB7 expires in ${Math.floor(remaining / 60)}m ${remaining % 60}s${token.revokedat !== void 0 ? " \xB7 revoked" : ""}.`;
|
|
4731
|
+
row.append(tokenline);
|
|
4732
|
+
}
|
|
4733
|
+
actions.append(" ", button("Revoke client", async () => {
|
|
4734
|
+
await request({ kind: "mcprevokeclient", clientid: client.id });
|
|
4735
|
+
status(`Revoked the client ${client.id}; its tokens stopped verifying at once.`);
|
|
4736
|
+
await refresh();
|
|
4737
|
+
}));
|
|
4738
|
+
row.append(actions);
|
|
4739
|
+
clientsbox.append(row);
|
|
4740
|
+
}
|
|
4741
|
+
if (mcp.clients.length === 0) {
|
|
4742
|
+
const empty = document.createElement("p");
|
|
4743
|
+
empty.textContent = "No connected client yet; a paired client speaks json rpc frames over the stdio bridge or an http post envelope.";
|
|
4744
|
+
clientsbox.append(empty);
|
|
4745
|
+
}
|
|
4746
|
+
agentprotocolroot.append(clientsbox);
|
|
4747
|
+
const approvalsbox = document.createElement("details");
|
|
4748
|
+
approvalsbox.className = "sessiongroup";
|
|
4749
|
+
approvalsbox.open = true;
|
|
4750
|
+
const approvalssummary = document.createElement("summary");
|
|
4751
|
+
const pendingapprovals = mcp.approvals.filter((request2) => request2.state === "pending");
|
|
4752
|
+
approvalssummary.textContent = `Approval gates (${pendingapprovals.length} pending, ${mcp.approvals.length - pendingapprovals.length} resolved)`;
|
|
4753
|
+
approvalsbox.append(approvalssummary);
|
|
4754
|
+
for (const gate of mcp.approvals.slice(0, 10)) {
|
|
4755
|
+
const card = document.createElement("div");
|
|
4756
|
+
card.className = "sessionrow";
|
|
4757
|
+
const identity = mcp.identities.find((entry) => entry.fingerprint === mcp.clients.find((client) => client.id === gate.clientid)?.fingerprint);
|
|
4758
|
+
const headline = document.createElement("p");
|
|
4759
|
+
const secrets = gate.secretfields ?? [];
|
|
4760
|
+
const shown = {};
|
|
4761
|
+
for (const [name, value] of Object.entries(gate.params)) shown[name] = secrets.includes(name) ? "[redacted]" : value;
|
|
4762
|
+
headline.textContent = `${gate.state === "pending" ? "PENDING" : gate.state.toUpperCase()} \xB7 ${identity?.displayname ?? gate.clientid} calls ${gate.tool} \xB7 ${gate.reason} Arguments: ${JSON.stringify(shown)}${gate.timeoutat !== void 0 ? ` \xB7 refuses by default at ${new Date(gate.timeoutat).toISOString()}` : ""}.`;
|
|
4763
|
+
card.append(headline);
|
|
4764
|
+
if (gate.state === "pending") {
|
|
4765
|
+
const actions = document.createElement("div");
|
|
4766
|
+
actions.className = "actions";
|
|
4767
|
+
actions.append(button("Approve", async () => {
|
|
4768
|
+
await request({ kind: "mcpapprovaldecision", approvalid: gate.id, approved: true });
|
|
4769
|
+
status(`Approved the ${gate.tool} call of the client ${gate.clientid}; the gate executed the held call.`);
|
|
4770
|
+
await refresh();
|
|
4771
|
+
}));
|
|
4772
|
+
actions.append(" ", button("Refuse", async () => {
|
|
4773
|
+
await request({ kind: "mcpapprovaldecision", approvalid: gate.id, approved: false });
|
|
4774
|
+
status(`Refused the ${gate.tool} call of the client ${gate.clientid}; the pending call never executes.`);
|
|
4775
|
+
await refresh();
|
|
4776
|
+
}));
|
|
4777
|
+
card.append(actions);
|
|
4778
|
+
}
|
|
4779
|
+
approvalsbox.append(card);
|
|
4780
|
+
}
|
|
4781
|
+
if (mcp.approvals.length === 0) {
|
|
4782
|
+
const empty = document.createElement("p");
|
|
4783
|
+
empty.textContent = "No approval gate yet; every sensitive call a remote client raises lands here with its full arguments before anything executes.";
|
|
4784
|
+
approvalsbox.append(empty);
|
|
4785
|
+
}
|
|
4786
|
+
agentprotocolroot.append(approvalsbox);
|
|
4787
|
+
const remotebox = document.createElement("details");
|
|
4788
|
+
remotebox.className = "sessiongroup";
|
|
4789
|
+
const remotesummary = document.createElement("summary");
|
|
4790
|
+
remotesummary.textContent = `Remote transport (${mcp.remote.channelsopen} live channel${mcp.remote.channelsopen === 1 ? "" : "s"}, ${mcp.remote.channelsdead} closed)`;
|
|
4791
|
+
remotebox.append(remotesummary);
|
|
4792
|
+
const remoteline = document.createElement("p");
|
|
4793
|
+
remoteline.textContent = `Endpoint ${mcp.remote.endpoint} \xB7 tls ${mcp.remote.tls.mode}${mcp.remote.tls.certificaterequired ? " (certificate required)" : ""}${mcp.remote.tls.verified ? " and verified" : " and unverified"} \xB7 ${mcp.remote.paired} of ${mcp.remote.clients} client${mcp.remote.clients === 1 ? "" : "s"} paired \xB7 ${mcp.remote.tokenslive} live token${mcp.remote.tokenslive === 1 ? "" : "s"}.`;
|
|
4794
|
+
remotebox.append(remoteline);
|
|
4795
|
+
for (const channel of mcp.channels.slice(0, 10)) {
|
|
4796
|
+
const line = document.createElement("p");
|
|
4797
|
+
const beatage = Math.max(0, Math.round((Date.now() - channel.lastbeatat) / 1e3));
|
|
4798
|
+
line.textContent = `Stream channel ${channel.id.slice(0, 12)} of ${channel.clientid} \xB7 ${channel.closedat === void 0 ? `heartbeat ${beatage}s ago` : `closed at ${new Date(channel.closedat).toISOString()}`}.`;
|
|
4799
|
+
remotebox.append(line);
|
|
4800
|
+
}
|
|
4801
|
+
for (const shake of mcp.handshakes.slice(0, 5)) {
|
|
4802
|
+
const line = document.createElement("p");
|
|
4803
|
+
line.textContent = `Auth handshake ${shake.method} of ${shake.clientid} \xB7 ${shake.outcome}${shake.outcome === "refused" ? " (consentrefused error, no pairing state leaked)" : ""} \xB7 ${new Date(shake.at).toISOString()}.`;
|
|
4804
|
+
remotebox.append(line);
|
|
4805
|
+
}
|
|
4806
|
+
const pairingline = document.createElement("p");
|
|
4807
|
+
pairingline.textContent = mcp.pairing.length > 0 ? `Pairing code ${mcp.pairing[0]?.code} for ${mcp.pairing[0]?.scopes.join(", ") || "no"} namespaces \xB7 expires at ${new Date(mcp.pairing[0]?.expiresat ?? Date.now()).toISOString()} \xB7 single use.` : "No pairing code pending; issue one while a session is live to pair a remote client.";
|
|
4808
|
+
remotebox.append(pairingline);
|
|
4809
|
+
const pairingactions = document.createElement("div");
|
|
4810
|
+
pairingactions.className = "actions";
|
|
4811
|
+
pairingactions.append(button("Issue pairing code", async () => {
|
|
4812
|
+
await request({ kind: "mcppairing", scopes: ["browser", "workflow", "memory", "system"] });
|
|
4813
|
+
status("Issued one single use pairing code; copy it to the remote client before its window closes.");
|
|
4814
|
+
await refresh();
|
|
4815
|
+
}));
|
|
4816
|
+
pairingactions.append(" ", button("Copy pairing code", async () => {
|
|
4817
|
+
const code = mcp.pairing[0]?.code ?? "";
|
|
4818
|
+
if (code === "") {
|
|
4819
|
+
status("No pending pairing code to copy.", true);
|
|
4820
|
+
return;
|
|
4821
|
+
}
|
|
4822
|
+
await navigator.clipboard.writeText(code).then(() => status(`Copied the pairing code ${code} to the clipboard.`)).catch(() => status(`Pairing code: ${code} (the clipboard permission was refused).`, true));
|
|
4823
|
+
}));
|
|
4824
|
+
remotebox.append(pairingactions);
|
|
4825
|
+
const tlsheadline = document.createElement("p");
|
|
4826
|
+
tlsheadline.textContent = "Tls certificate options of the remote transport: the mode and the reviewed sha-256 fingerprint stay user choices with no hardcoded certificate.";
|
|
4827
|
+
remotebox.append(tlsheadline);
|
|
4828
|
+
const tlsactions = document.createElement("div");
|
|
4829
|
+
tlsactions.className = "actions";
|
|
4830
|
+
const endpointinput = document.createElement("input");
|
|
4831
|
+
endpointinput.placeholder = "remote endpoint url";
|
|
4832
|
+
endpointinput.value = mcp.config.remoteaccess?.endpoint ?? "";
|
|
4833
|
+
const tlsmodeinput = document.createElement("input");
|
|
4834
|
+
tlsmodeinput.placeholder = "tls mode: off, on or required";
|
|
4835
|
+
tlsmodeinput.value = mcp.config.remoteaccess?.tls.mode ?? "off";
|
|
4836
|
+
const certinput = document.createElement("input");
|
|
4837
|
+
certinput.placeholder = "certificate sha-256 fingerprint";
|
|
4838
|
+
certinput.value = mcp.config.httpstream?.tls.certificatefingerprint ?? "";
|
|
4839
|
+
const maxclientsinput = document.createElement("input");
|
|
4840
|
+
maxclientsinput.placeholder = "max clients (empty: unbounded)";
|
|
4841
|
+
maxclientsinput.value = mcp.config.remoteaccess?.maxclients !== void 0 ? String(mcp.config.remoteaccess.maxclients) : "";
|
|
4842
|
+
const timeoutinput = document.createElement("input");
|
|
4843
|
+
timeoutinput.placeholder = "approval window ms";
|
|
4844
|
+
timeoutinput.value = mcp.config.remoteaccess?.approvaltimeout !== void 0 ? String(mcp.config.remoteaccess.approvaltimeout.windowms) : "";
|
|
4845
|
+
tlsactions.append(endpointinput, " ", tlsmodeinput, " ", certinput, " ", maxclientsinput, " ", timeoutinput, " ", button("Save remote config", async () => {
|
|
4846
|
+
await request({ kind: "mcpremoteconfig", endpoint: endpointinput.value, tlsmode: tlsmodeinput.value, ...certinput.value.trim() !== "" ? { certificatefingerprint: certinput.value } : {}, ...maxclientsinput.value.trim() !== "" ? { maxclients: Number(maxclientsinput.value) } : {}, ...timeoutinput.value.trim() !== "" ? { approvaltimeoutms: Number(timeoutinput.value) } : {}, reviewed: true });
|
|
4847
|
+
status(`Saved the remote transport config for ${endpointinput.value} with the ${tlsmodeinput.value} tls mode.`);
|
|
4848
|
+
await refresh();
|
|
4849
|
+
}));
|
|
4850
|
+
remotebox.append(tlsactions);
|
|
4851
|
+
agentprotocolroot.append(remotebox);
|
|
4852
|
+
const allowlistbox = document.createElement("details");
|
|
4853
|
+
allowlistbox.className = "sessiongroup";
|
|
4854
|
+
const allowlistsummary = document.createElement("summary");
|
|
4855
|
+
allowlistsummary.textContent = `Client allowlist (${mcp.allowlist.length} entr${mcp.allowlist.length === 1 ? "y" : "ies"})`;
|
|
4856
|
+
allowlistbox.append(allowlistsummary);
|
|
4857
|
+
for (const entry of mcp.allowlist) {
|
|
4858
|
+
const line = document.createElement("p");
|
|
4859
|
+
line.textContent = `${entry.displayname} \xB7 ${entry.fingerprint.slice(0, 12)} \xB7 namespaces ${entry.namespaces.join(", ") || "none"} \xB7 granted ${new Date(entry.grantedat).toISOString()} \xB7 ${entry.history.length} grant change${entry.history.length === 1 ? "" : "s"}.`;
|
|
4860
|
+
allowlistbox.append(line);
|
|
4861
|
+
const actions = document.createElement("div");
|
|
4862
|
+
actions.className = "actions";
|
|
4863
|
+
actions.append(button(`Rescope to browser+memory`, async () => {
|
|
4864
|
+
await request({ kind: "mcpallowlist", fingerprint: entry.fingerprint, displayname: entry.displayname, namespaces: ["browser", "memory"] });
|
|
4865
|
+
status(`Rescoped the allowlist entry ${entry.displayname} to the browser and memory namespaces.`);
|
|
4866
|
+
await refresh();
|
|
4867
|
+
}));
|
|
4868
|
+
actions.append(" ", button("Refuse entry", async () => {
|
|
4869
|
+
await request({ kind: "mcpallowlist", fingerprint: entry.fingerprint, remove: true });
|
|
4870
|
+
status(`Refused the allowlist entry ${entry.displayname}; its fingerprint stops passing the check.`);
|
|
4871
|
+
await refresh();
|
|
4872
|
+
}));
|
|
4873
|
+
allowlistbox.append(actions);
|
|
4874
|
+
}
|
|
4875
|
+
const allowactions = document.createElement("div");
|
|
4876
|
+
allowactions.className = "actions";
|
|
4877
|
+
const fingerprintinput = document.createElement("input");
|
|
4878
|
+
fingerprintinput.placeholder = "client fingerprint";
|
|
4879
|
+
const displayinput = document.createElement("input");
|
|
4880
|
+
displayinput.placeholder = "display name";
|
|
4881
|
+
const scopesinput = document.createElement("input");
|
|
4882
|
+
scopesinput.placeholder = "namespaces: browser,workflow,memory,system";
|
|
4883
|
+
allowactions.append(fingerprintinput, " ", displayinput, " ", scopesinput, " ", button("Allow client", async () => {
|
|
4884
|
+
const namespaces = scopesinput.value.split(",").map((scope) => scope.trim()).filter((scope) => scope !== "");
|
|
4885
|
+
await request({ kind: "mcpallowlist", fingerprint: fingerprintinput.value, ...displayinput.value.trim() !== "" ? { displayname: displayinput.value } : {}, namespaces });
|
|
4886
|
+
status(`Allowed the client ${displayinput.value || fingerprintinput.value} the ${namespaces.join(", ") || "no"} namespaces.`);
|
|
4887
|
+
await refresh();
|
|
4888
|
+
}));
|
|
4889
|
+
allowlistbox.append(allowactions);
|
|
4890
|
+
if (mcp.allowlist.length === 0) {
|
|
4891
|
+
const empty = document.createElement("p");
|
|
4892
|
+
empty.textContent = "No allowlist entry yet; a remote client pairs through the one time code or the user allows a known fingerprint with its namespace scopes.";
|
|
4893
|
+
allowlistbox.append(empty);
|
|
4894
|
+
}
|
|
4895
|
+
agentprotocolroot.append(allowlistbox);
|
|
4896
|
+
const catalogbox = document.createElement("details");
|
|
4897
|
+
catalogbox.className = "sessiongroup";
|
|
4898
|
+
const catalogsummary = document.createElement("summary");
|
|
4899
|
+
catalogsummary.textContent = `Tool catalog (${mcp.catalog.tools.length} tools by namespace)`;
|
|
4900
|
+
catalogbox.append(catalogsummary);
|
|
4901
|
+
const bynamespace = /* @__PURE__ */ new Map();
|
|
4902
|
+
for (const tool of mcp.catalog.tools) {
|
|
4903
|
+
const namespace = tool.name.split(".")[0] ?? "browser";
|
|
4904
|
+
const group = bynamespace.get(namespace) ?? [];
|
|
4905
|
+
group.push(tool);
|
|
4906
|
+
bynamespace.set(namespace, group);
|
|
4907
|
+
}
|
|
4908
|
+
for (const [namespace, tools] of bynamespace) {
|
|
4909
|
+
const domain = document.createElement("details");
|
|
4910
|
+
domain.className = "sessiongroup";
|
|
4911
|
+
const domainsummary = document.createElement("summary");
|
|
4912
|
+
domainsummary.textContent = `${namespace} (${tools.length} tools)`;
|
|
4913
|
+
domain.append(domainsummary);
|
|
4914
|
+
for (const tool of tools) {
|
|
4915
|
+
const line = document.createElement("p");
|
|
4916
|
+
line.textContent = `${tool.name} v${tool.version} \xB7 ${tool.risk} \xB7 ${tool.description.split(".")[0] ?? tool.description}${tool.consentmeta !== void 0 ? ` \xB7 ${tool.consentmeta.riskclass} \xB7 approval gate ${tool.consentmeta.approvalrequired ? "required" : "off"} \xB7 ${tool.consentmeta.originscope} scope \xB7 review: ${tool.consentmeta.review}` : ""}`;
|
|
4917
|
+
domain.append(line);
|
|
4918
|
+
}
|
|
4919
|
+
catalogbox.append(domain);
|
|
4920
|
+
}
|
|
4921
|
+
agentprotocolroot.append(catalogbox);
|
|
4922
|
+
const callsbox = document.createElement("details");
|
|
4923
|
+
callsbox.className = "sessiongroup";
|
|
4924
|
+
const callssummary = document.createElement("summary");
|
|
4925
|
+
callssummary.textContent = `Recent tool calls (${mcp.calls.length})`;
|
|
4926
|
+
callsbox.append(callssummary);
|
|
4927
|
+
for (const call of mcp.calls.slice(0, 25)) {
|
|
4928
|
+
const line = document.createElement("p");
|
|
4929
|
+
line.textContent = `${new Date(call.at).toISOString()} \xB7 ${call.clientid} \xB7 ${call.tool} \xB7 ${call.origin} \xB7 ${call.ok ? "ran behind the gates" : `refused${call.code !== void 0 ? ` (${call.code})` : ""}`}`;
|
|
4930
|
+
callsbox.append(line);
|
|
4931
|
+
}
|
|
4932
|
+
if (mcp.calls.length === 0) {
|
|
4933
|
+
const empty = document.createElement("p");
|
|
4934
|
+
empty.textContent = "No tool call yet; every call records the client, tool and outcome without payloads.";
|
|
4935
|
+
callsbox.append(empty);
|
|
4936
|
+
}
|
|
4937
|
+
agentprotocolroot.append(callsbox);
|
|
4938
|
+
}
|
|
4643
4939
|
//# sourceMappingURL=sidepanel.js.map
|