@wenathlan/extension 1.1.35 → 1.1.36
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/index.js +222 -5
- package/dist/index.js.map +2 -2
- package/dist/memory.d.ts +39 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/policy.d.ts +13 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +15 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/types.d.ts +128 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +883 -13
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +2 -2
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +23 -2
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +208 -1
- package/extension/dist/sidepanel.js.map +3 -3
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,22 @@
|
|
|
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"]);
|
|
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"]);
|
|
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"]);
|
|
5
|
+
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
6
|
+
|
|
7
|
+
// extension/tabscommand.ts
|
|
8
|
+
function switcherlist(tabs, recency, filter) {
|
|
9
|
+
const needle = filter.trim().toLowerCase();
|
|
10
|
+
const matches = needle ? tabs.filter((tab) => tab.title.toLowerCase().includes(needle) || tab.url.toLowerCase().includes(needle)) : [...tabs];
|
|
11
|
+
const lastrun = new Map(recency.map((entry) => [entry.tabid, entry.at]));
|
|
12
|
+
return [...matches].sort((left, right) => {
|
|
13
|
+
const leftat = lastrun.get(left.tabid) ?? -1;
|
|
14
|
+
const rightat = lastrun.get(right.tabid) ?? -1;
|
|
15
|
+
if (leftat !== rightat) return rightat - leftat;
|
|
16
|
+
return left.index - right.index;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
// extension/sidepanel.ts
|
|
2
21
|
var objective = document.querySelector("#objective");
|
|
3
22
|
var localbutton = document.querySelector("#localplan");
|
|
@@ -16,6 +35,7 @@ var bannersroot = document.querySelector("#banners");
|
|
|
16
35
|
var selectorsroot = document.querySelector("#selectors");
|
|
17
36
|
var trailroot = document.querySelector("#trail");
|
|
18
37
|
var navigationroot = document.querySelector("#navigation");
|
|
38
|
+
var tabswindowsroot = document.querySelector("#tabswindows");
|
|
19
39
|
var statusnode = document.querySelector("#status");
|
|
20
40
|
var progressnode = document.querySelector("#planprogress");
|
|
21
41
|
var capabilitiestext = document.querySelector("#capabilitiestext");
|
|
@@ -61,7 +81,8 @@ var topictags = [
|
|
|
61
81
|
{ topic: "observation", kinds: ["a11ytree", "readvisible", "readertree", "readoutline", "readselection", "readopengraph", "readlang", "detectlanguage", "listshadow", "listframes", "readscrollpos"] },
|
|
62
82
|
{ topic: "detection", kinds: ["detectlists", "detecttables", "detectinfinitescroll", "detectvirtual", "detectlazy", "detectsticky", "detectscrolllock", "countpages", "classifypage", "fingerprintsection"] },
|
|
63
83
|
{ topic: "watch", kinds: ["watchmutate", "watchbanner", "watchfocus", "waitquiet", "readjson", "diffsnapshots", "deriveselector"] },
|
|
64
|
-
{ topic: "navigation", kinds: ["openlink", "openprivate", "reloadcache", "stopnav", "waitload", "waiturl", "followlink", "spanav", "spawait", "rewritequery", "setfragment", "navlist", "navprofile", "detecthttp", "readredirects", "readfinalurl", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "trailaudit", "pausenav", "navintent", "navrate", "openclipboard", "checksafe", "batchopen"] }
|
|
84
|
+
{ topic: "navigation", kinds: ["openlink", "openprivate", "reloadcache", "stopnav", "waitload", "waiturl", "followlink", "spanav", "spawait", "rewritequery", "setfragment", "navlist", "navprofile", "detecthttp", "readredirects", "readfinalurl", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "trailaudit", "pausenav", "navintent", "navrate", "openclipboard", "checksafe", "batchopen"] },
|
|
85
|
+
{ topic: "tabs", kinds: ["querytabs", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "watchtab", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "savelayout", "restorelayout", "findclones", "searchtabs", "badgetab", "attachmeta", "listaudio", "reopenrun", "snapshotsession"] }
|
|
65
86
|
];
|
|
66
87
|
function steptopic(kind) {
|
|
67
88
|
return topictags.find((tag) => tag.kinds.includes(kind))?.topic;
|
|
@@ -579,6 +600,191 @@ function rendernavigation(context) {
|
|
|
579
600
|
navigationroot.append(list);
|
|
580
601
|
}
|
|
581
602
|
}
|
|
603
|
+
function rendertabswindows(context) {
|
|
604
|
+
if (!tabswindowsroot) return;
|
|
605
|
+
tabswindowsroot.replaceChildren();
|
|
606
|
+
const tabs = context.tabs ?? [];
|
|
607
|
+
const badges = context.badges ?? [];
|
|
608
|
+
const metas = context.tabmetas ?? [];
|
|
609
|
+
const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();
|
|
610
|
+
const gauge = context.tasktabgauge ?? { used: 0, ceiling: void 0, over: false };
|
|
611
|
+
const budget = document.createElement("p");
|
|
612
|
+
budget.className = gauge.over ? "bannercard" : "";
|
|
613
|
+
budget.textContent = `task tab budget: ${gauge.used} tab${gauge.used === 1 ? "" : "s"} with active tasks${gauge.ceiling !== void 0 ? ` of the user configured ceiling ${gauge.ceiling}` : " with no user ceiling configured"}${gauge.over ? " \u2014 over the reviewed budget" : ""}`;
|
|
614
|
+
tabswindowsroot.append(budget);
|
|
615
|
+
const ceilinginput = document.createElement("input");
|
|
616
|
+
ceilinginput.type = "number";
|
|
617
|
+
ceilinginput.min = "0";
|
|
618
|
+
ceilinginput.placeholder = gauge.ceiling !== void 0 ? String(gauge.ceiling) : "no ceiling";
|
|
619
|
+
ceilinginput.setAttribute("aria-label", "concurrent task tab ceiling");
|
|
620
|
+
const ceilingbutton = button("Save task tab ceiling", async () => {
|
|
621
|
+
await request({ kind: "settasktabceiling", ceiling: ceilinginput.value === "" ? void 0 : Number(ceilinginput.value) });
|
|
622
|
+
status(`Task tab ceiling saved as ${ceilinginput.value === "" ? "no ceiling" : ceilinginput.value}; the value stays a user choice.`);
|
|
623
|
+
await refresh();
|
|
624
|
+
});
|
|
625
|
+
tabswindowsroot.append(ceilinginput, " ", ceilingbutton);
|
|
626
|
+
const switcherheading = document.createElement("p");
|
|
627
|
+
switcherheading.textContent = "quick switcher (ordered by recency, filter by title or url):";
|
|
628
|
+
tabswindowsroot.append(switcherheading);
|
|
629
|
+
const filterinput = document.createElement("input");
|
|
630
|
+
filterinput.type = "search";
|
|
631
|
+
filterinput.placeholder = "filter open tabs";
|
|
632
|
+
filterinput.setAttribute("aria-label", "quick switcher filter");
|
|
633
|
+
const switchlist = document.createElement("ul");
|
|
634
|
+
const renderswitchlist = () => {
|
|
635
|
+
switchlist.replaceChildren();
|
|
636
|
+
const ordered = switcherlist(tabs, [], filterinput.value).slice(0, 10);
|
|
637
|
+
for (const tab of ordered) {
|
|
638
|
+
const item = document.createElement("li");
|
|
639
|
+
const jump = document.createElement("button");
|
|
640
|
+
jump.type = "button";
|
|
641
|
+
const badge = badges.find((entry) => entry.tabid === tab.tabid);
|
|
642
|
+
const meta = metas.find((entry) => entry.tabid === tab.tabid);
|
|
643
|
+
jump.textContent = `${tab.title || tab.url}${tab.pinned ? " \u{1F4CC}" : ""}${tab.audible || tab.muted ? ` ${tab.muted ? "\u{1F507}" : "\u{1F50A}"}` : ""}${badge ? ` [${badge.label}]` : ""}${meta && meta.labels.length > 0 ? ` (${meta.labels.join(", ")})` : ""}`;
|
|
644
|
+
jump.addEventListener("click", () => request({ kind: "jumptotab", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
645
|
+
item.append(jump);
|
|
646
|
+
switchlist.append(item);
|
|
647
|
+
}
|
|
648
|
+
if (ordered.length === 0) {
|
|
649
|
+
const empty = document.createElement("li");
|
|
650
|
+
empty.textContent = "no open tab matches the filter";
|
|
651
|
+
switchlist.append(empty);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
filterinput.addEventListener("input", renderswitchlist);
|
|
655
|
+
tabswindowsroot.append(filterinput, switchlist);
|
|
656
|
+
renderswitchlist();
|
|
657
|
+
const searchinput = document.createElement("input");
|
|
658
|
+
searchinput.type = "search";
|
|
659
|
+
searchinput.placeholder = "search across open tabs by title and url";
|
|
660
|
+
searchinput.setAttribute("aria-label", "searchtabs text");
|
|
661
|
+
const searchresults = document.createElement("ul");
|
|
662
|
+
const searchbutton = button("Run searchtabs", async () => {
|
|
663
|
+
const result = await request({ kind: "tabsearch", text: searchinput.value });
|
|
664
|
+
searchresults.replaceChildren();
|
|
665
|
+
for (const tab of result.matches.slice(0, 10)) {
|
|
666
|
+
const item = document.createElement("li");
|
|
667
|
+
const jump = document.createElement("button");
|
|
668
|
+
jump.type = "button";
|
|
669
|
+
jump.textContent = `${tab.title || tab.url} \xB7 ${tab.url}`;
|
|
670
|
+
jump.addEventListener("click", () => request({ kind: "jumptotab", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
671
|
+
item.append(jump);
|
|
672
|
+
searchresults.append(item);
|
|
673
|
+
}
|
|
674
|
+
status(`searchtabs matched ${result.matches.length} open tab${result.matches.length === 1 ? "" : "s"}.`);
|
|
675
|
+
});
|
|
676
|
+
tabswindowsroot.append(searchinput, " ", searchbutton, searchresults);
|
|
677
|
+
const clones = context.clones ?? [];
|
|
678
|
+
for (const clone of clones.slice(0, 3)) {
|
|
679
|
+
const warning = document.createElement("p");
|
|
680
|
+
warning.className = "bannercard";
|
|
681
|
+
warning.textContent = `duplicate tab warning: ${clone.tabids.length} open tabs share the url ${clone.url} (tabs ${clone.tabids.join(", ")})`;
|
|
682
|
+
tabswindowsroot.append(warning);
|
|
683
|
+
}
|
|
684
|
+
const groups = context.tabgroups ?? [];
|
|
685
|
+
if (groups.length > 0) {
|
|
686
|
+
const groupsheading = document.createElement("p");
|
|
687
|
+
groupsheading.textContent = "tab groups with colors and collapse states:";
|
|
688
|
+
tabswindowsroot.append(groupsheading);
|
|
689
|
+
const grouplist = document.createElement("ul");
|
|
690
|
+
for (const group of groups.slice(0, 6)) {
|
|
691
|
+
const item = document.createElement("li");
|
|
692
|
+
item.textContent = `${group.name} \xB7 ${group.color} \xB7 ${group.collapsed ? "collapsed" : "expanded"} \xB7 ${group.tabids.length} member tab${group.tabids.length === 1 ? "" : "s"}`;
|
|
693
|
+
grouplist.append(item);
|
|
694
|
+
}
|
|
695
|
+
tabswindowsroot.append(grouplist);
|
|
696
|
+
}
|
|
697
|
+
const windows = context.windows ?? [];
|
|
698
|
+
if (windows.length > 0) {
|
|
699
|
+
const windowsheading = document.createElement("p");
|
|
700
|
+
windowsheading.textContent = "windows with layouts and bounds:";
|
|
701
|
+
tabswindowsroot.append(windowsheading);
|
|
702
|
+
const windowlist = document.createElement("ul");
|
|
703
|
+
for (const item of windows.slice(0, 6)) {
|
|
704
|
+
const entry = document.createElement("li");
|
|
705
|
+
entry.textContent = `window ${item.windowid} \xB7 ${item.state} \xB7 bounds ${item.left}\xD7${item.top} ${item.width}\xD7${item.height}${item.incognito ? " \xB7 incognito, grants not inherited" : ""}${item.focused ? " \xB7 focused" : ""}`;
|
|
706
|
+
const closebutton = button("Close window", async () => {
|
|
707
|
+
const tasktabids = context.progress?.tasktabs ?? [];
|
|
708
|
+
const tabsoftask = (context.tabs ?? []).filter((tab) => tab.windowid === item.windowid && tasktabids.includes(tab.tabid));
|
|
709
|
+
const reviewed = tabsoftask.length > 1 ? window.confirm(`This window holds ${tabsoftask.length} task tabs. Close it anyway under explicit review?`) : true;
|
|
710
|
+
await request({ kind: "closewindow", windowid: item.windowid, reviewed });
|
|
711
|
+
status(`Closed window ${item.windowid}.`);
|
|
712
|
+
await refresh();
|
|
713
|
+
});
|
|
714
|
+
entry.append(" ", closebutton);
|
|
715
|
+
windowlist.append(entry);
|
|
716
|
+
}
|
|
717
|
+
tabswindowsroot.append(windowlist);
|
|
718
|
+
}
|
|
719
|
+
const layoutcontrols = document.createElement("p");
|
|
720
|
+
const layoutname = document.createElement("input");
|
|
721
|
+
layoutname.type = "text";
|
|
722
|
+
layoutname.placeholder = "layout name";
|
|
723
|
+
layoutname.setAttribute("aria-label", "layout name");
|
|
724
|
+
const savebutton = button("Save layout", async () => {
|
|
725
|
+
if (!active) {
|
|
726
|
+
status("Layout save stays inside an active session.", true);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
await request({ kind: "savelayout", name: layoutname.value });
|
|
730
|
+
status(`Saved the tab layout ${layoutname.value}.`);
|
|
731
|
+
await refresh();
|
|
732
|
+
});
|
|
733
|
+
const restorebutton = button("Restore layout", async () => {
|
|
734
|
+
if (!active) {
|
|
735
|
+
status("Layout restore stays inside an active session.", true);
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const result = await request({ kind: "restorelayout", name: layoutname.value });
|
|
739
|
+
status(`Restored the tab layout ${layoutname.value}: ${result.reopened} tab${result.reopened === 1 ? "" : "s"} reopened.`);
|
|
740
|
+
await refresh();
|
|
741
|
+
});
|
|
742
|
+
layoutcontrols.append(layoutname, " ", savebutton, " ", restorebutton);
|
|
743
|
+
tabswindowsroot.append(layoutcontrols);
|
|
744
|
+
const layouts = context.layouts ?? [];
|
|
745
|
+
if (layouts.length > 0) {
|
|
746
|
+
const layoutlist = document.createElement("ul");
|
|
747
|
+
for (const layout of layouts.slice(0, 4)) {
|
|
748
|
+
const item = document.createElement("li");
|
|
749
|
+
item.textContent = `${layout.name} \xB7 ${layout.tabs.length} tab${layout.tabs.length === 1 ? "" : "s"} \xB7 ${layout.groups.length} group${layout.groups.length === 1 ? "" : "s"} \xB7 ${layout.windows.length} window bound${layout.windows.length === 1 ? "" : "s"} \xB7 saved ${new Date(layout.savedat).toLocaleString()}`;
|
|
750
|
+
layoutlist.append(item);
|
|
751
|
+
}
|
|
752
|
+
tabswindowsroot.append(layoutlist);
|
|
753
|
+
}
|
|
754
|
+
const snapshots = context.snapshots ?? [];
|
|
755
|
+
if (snapshots.length > 0) {
|
|
756
|
+
const snapcard = document.createElement("div");
|
|
757
|
+
snapcard.className = "bannercard";
|
|
758
|
+
const snaptitle = document.createElement("p");
|
|
759
|
+
snaptitle.textContent = `session snapshot card: ${snapshots.length} snapshot${snapshots.length === 1 ? "" : "s"} stored`;
|
|
760
|
+
snapcard.append(snaptitle);
|
|
761
|
+
for (const snapshot of snapshots.slice(0, 3)) {
|
|
762
|
+
const row = document.createElement("p");
|
|
763
|
+
row.textContent = `${snapshot.layout.tabs.length} tabs \xB7 captured ${new Date(snapshot.capturedat).toLocaleString()}`;
|
|
764
|
+
const restore = button("Restore snapshot", async () => {
|
|
765
|
+
const result = await request({ kind: "restoresnapshot", id: snapshot.id });
|
|
766
|
+
status(`Restored the session snapshot: ${result.reopened} tab${result.reopened === 1 ? "" : "s"} reopened.`);
|
|
767
|
+
await refresh();
|
|
768
|
+
});
|
|
769
|
+
row.append(" ", restore);
|
|
770
|
+
snapcard.append(row);
|
|
771
|
+
}
|
|
772
|
+
tabswindowsroot.append(snapcard);
|
|
773
|
+
}
|
|
774
|
+
const controlcard = document.createElement("div");
|
|
775
|
+
controlcard.className = "bannercard";
|
|
776
|
+
const controlstate = context.controltab;
|
|
777
|
+
const completed = context.progress?.completedsteps.length ?? 0;
|
|
778
|
+
const total = context.plan?.steps.length ?? 0;
|
|
779
|
+
controlcard.textContent = `pinned control tab feed: ${controlstate?.enabled ? `open as tab ${controlstate.tabid} with the live task status ${completed} of ${total} reviewed steps executed` : "disabled"}${context.plan ? ` \xB7 ${context.plan.state}` : " \xB7 no plan"}`;
|
|
780
|
+
const controlbutton = button(controlstate?.enabled ? "Close pinned control tab" : "Open pinned control tab", async () => {
|
|
781
|
+
await request({ kind: "controltab", enabled: !controlstate?.enabled });
|
|
782
|
+
status(controlstate?.enabled ? "The pinned control tab was closed." : "The pinned control tab was opened with the live task feed.");
|
|
783
|
+
await refresh();
|
|
784
|
+
});
|
|
785
|
+
controlcard.append(" ", controlbutton);
|
|
786
|
+
tabswindowsroot.append(controlcard);
|
|
787
|
+
}
|
|
582
788
|
function rendercapabilities(report) {
|
|
583
789
|
if (!capabilitiestext) return;
|
|
584
790
|
if (!report) {
|
|
@@ -624,6 +830,7 @@ async function refresh() {
|
|
|
624
830
|
renderselectors(context.selectors ?? []);
|
|
625
831
|
rendertrail(context.trail?.trail ?? []);
|
|
626
832
|
rendernavigation(context);
|
|
833
|
+
rendertabswindows(context);
|
|
627
834
|
renderaudit(context.audit);
|
|
628
835
|
rendercapabilities(context.capabilities);
|
|
629
836
|
if (context.session?.pausedat) status("Session paused. Reviewed actions are blocked until resume.");
|