@wenathlan/extension 1.1.63 → 1.1.64
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 +4 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +404 -1
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +28 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/planreview.d.ts +87 -0
- package/dist/planreview.d.ts.map +1 -0
- package/dist/policy.d.ts +47 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +135 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/surfaces.d.ts +59 -0
- package/dist/surfaces.d.ts.map +1 -0
- package/dist/types.d.ts +181 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +669 -2
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/dashboardpage.html +13 -0
- package/extension/dist/dashboardpage.js +129 -0
- package/extension/dist/dashboardpage.js.map +7 -0
- package/extension/dist/manifest.json +5 -2
- package/extension/dist/offscreen.js +1 -0
- package/extension/dist/offscreen.js.map +2 -2
- package/extension/dist/optionspage.html +14 -0
- package/extension/dist/optionspage.js +118 -0
- package/extension/dist/optionspage.js.map +7 -0
- package/extension/dist/pagebridge.js.map +1 -1
- package/extension/dist/popup.html +4 -1
- package/extension/dist/popup.js +167 -0
- package/extension/dist/popup.js.map +3 -3
- package/extension/dist/sidepanel.html +7 -2
- package/extension/dist/sidepanel.js +279 -0
- package/extension/dist/sidepanel.js.map +2 -2
- package/extension/manifest.json +5 -2
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Devthink dashboard</title><link rel="stylesheet" href="style.css"></head>
|
|
4
|
+
<body><main class="wide"><header><p class="eyebrow">DASHBOARD</p><h1>Full page view</h1><p>Every session, run, note and transparency view of the profile workspace in one page.</p></header>
|
|
5
|
+
<nav class="actions"><button id="openpanel" class="secondary">Open review panel</button><button id="openoptions" class="secondary">Open options</button><button id="openpopuphint" class="secondary" hidden>Return to popup</button></nav>
|
|
6
|
+
<p id="status" role="status">Loading the dashboard view.</p>
|
|
7
|
+
<section><h2>Sessions and runs</h2><div id="sessiongrid" class="panel"></div></section>
|
|
8
|
+
<section><h2>History search</h2><div class="actions"><input id="historyquery" placeholder="Search sessions, notes and summaries" aria-label="History search"><button id="historyrun" class="secondary">Search</button></div><ol id="historyhits" class="audit"></ol></section>
|
|
9
|
+
<section><h2>Site notes</h2><div id="sitenotes" class="panel"></div></section>
|
|
10
|
+
<section><h2>Transparency views</h2><div id="transparency" class="panel"></div></section>
|
|
11
|
+
<section><h2>Onboarding</h2><div id="onboarding" class="panel"></div></section>
|
|
12
|
+
</main><script type="module" src="dashboardpage.js"></script></body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// extension/dashboardpage.ts
|
|
2
|
+
var statusnode = document.querySelector("#status");
|
|
3
|
+
var sessiongridroot = document.querySelector("#sessiongrid");
|
|
4
|
+
var historyhitsroot = document.querySelector("#historyhits");
|
|
5
|
+
var sitenotesroot = document.querySelector("#sitenotes");
|
|
6
|
+
var transparencyroot = document.querySelector("#transparency");
|
|
7
|
+
var onboardingroot = document.querySelector("#onboarding");
|
|
8
|
+
var historyinput = document.querySelector("#historyquery");
|
|
9
|
+
function status(message, error = false) {
|
|
10
|
+
if (statusnode) {
|
|
11
|
+
statusnode.textContent = message;
|
|
12
|
+
statusnode.dataset.state = error ? "error" : "ready";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function request(message) {
|
|
16
|
+
const response = await chrome.runtime.sendMessage(message);
|
|
17
|
+
if (!response.ok) throw new Error(response.error);
|
|
18
|
+
return response.value;
|
|
19
|
+
}
|
|
20
|
+
function button(label, action) {
|
|
21
|
+
const element = document.createElement("button");
|
|
22
|
+
element.type = "button";
|
|
23
|
+
element.className = "secondary";
|
|
24
|
+
element.textContent = label;
|
|
25
|
+
element.addEventListener("click", () => action().catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
26
|
+
return element;
|
|
27
|
+
}
|
|
28
|
+
function rendersessiongrid(view) {
|
|
29
|
+
if (!sessiongridroot) return;
|
|
30
|
+
sessiongridroot.replaceChildren();
|
|
31
|
+
if (view.grid.length === 0) {
|
|
32
|
+
sessiongridroot.textContent = "No session exists yet; start the first run from the popup taskinput.";
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const list = document.createElement("ol");
|
|
36
|
+
list.className = "audit";
|
|
37
|
+
for (const row of view.grid) {
|
|
38
|
+
const item = document.createElement("li");
|
|
39
|
+
item.textContent = `${row.state} ${row.runid} \u2014 ${row.origins.join(", ")} \u2014 ${row.completed}/${row.steps} steps \u2014 ${row.outcome} \u2014 ${row.lock}${row.sealhash !== void 0 ? ` \u2014 sealed ${row.sealhash.slice(0, 12)}` : ""}`;
|
|
40
|
+
for (const action of row.actions) item.append(" ", button(action === "cancelrun" ? "Cancel run" : action === "resume" ? "Resume" : "Reopen", async () => {
|
|
41
|
+
await request({ kind: "sessions", grid: action === "cancelrun" ? { open: { runid: row.runid } } : action === "resume" ? { resume: { runid: row.runid } } : { reopen: { runid: row.runid } } });
|
|
42
|
+
if (action === "cancelrun") await request({ kind: "surface", bus: { action: { surface: "dashboardpage", command: "cancelrun" } } });
|
|
43
|
+
status(`The ${action} action of the run ${row.runid} routed through the command bus.`);
|
|
44
|
+
await render();
|
|
45
|
+
}));
|
|
46
|
+
list.append(item);
|
|
47
|
+
}
|
|
48
|
+
sessiongridroot.append(list);
|
|
49
|
+
}
|
|
50
|
+
async function renderhistorysearch(text) {
|
|
51
|
+
if (!historyhitsroot) return;
|
|
52
|
+
try {
|
|
53
|
+
const result = await request({ kind: "sessions", search: { query: { text } } });
|
|
54
|
+
historyhitsroot.replaceChildren();
|
|
55
|
+
if (result.hits.length === 0) {
|
|
56
|
+
historyhitsroot.append(Object.assign(document.createElement("li"), { textContent: "No history matches yet." }));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
for (const hit of result.hits) {
|
|
60
|
+
const item = document.createElement("li");
|
|
61
|
+
item.textContent = `${hit.source} \u2014 ${hit.title}${hit.origin !== void 0 ? ` (${hit.origin})` : ""}: ${hit.excerpt}${hit.highlights.length > 0 ? ` [${hit.highlights.join(", ")}]` : ""}`;
|
|
62
|
+
historyhitsroot.append(item);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
historyhitsroot.textContent = error instanceof Error ? error.message : String(error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function rendersitenotes(view) {
|
|
69
|
+
if (!sitenotesroot) return;
|
|
70
|
+
if (view.notes.length === 0) {
|
|
71
|
+
sitenotesroot.textContent = "No site note exists yet; write the first note from the sidepanel.";
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
sitenotesroot.replaceChildren();
|
|
75
|
+
const list = document.createElement("ul");
|
|
76
|
+
list.className = "audit";
|
|
77
|
+
for (const note of view.notes) list.append(Object.assign(document.createElement("li"), { textContent: `${note.title} (${note.origin}, by ${note.author}${note.sensitive ? ", sealed at rest" : ""}): ${note.body}` }));
|
|
78
|
+
sitenotesroot.append(list);
|
|
79
|
+
}
|
|
80
|
+
function rendertransparency(view) {
|
|
81
|
+
if (!transparencyroot) return;
|
|
82
|
+
transparencyroot.replaceChildren();
|
|
83
|
+
const grants = document.createElement("p");
|
|
84
|
+
grants.textContent = `Grants: ${view.grants.length} grant row${view.grants.length === 1 ? "" : "s"}${view.grants.length > 0 ? ` (${view.grants.slice(0, 5).map((grant) => `${grant.origin} \u2014 ${grant.scope} \u2014 ${grant.boundary}`).join(" \xB7 ")})` : ""}.`;
|
|
85
|
+
const windows = document.createElement("p");
|
|
86
|
+
windows.textContent = `Consent windows: ${view.windows.length} recorded window${view.windows.length === 1 ? "" : "s"}.`;
|
|
87
|
+
const permdiffs = document.createElement("p");
|
|
88
|
+
permdiffs.textContent = `Permdiffs: ${view.permdiffs.length} record${view.permdiffs.length === 1 ? "" : "s"}${view.permdiffs.length > 0 ? ` (latest ${view.permdiffs[0]?.fromversion} \u2192 ${view.permdiffs[0]?.toversion})` : ""}.`;
|
|
89
|
+
const safedefaults = document.createElement("p");
|
|
90
|
+
safedefaults.textContent = `Safedefaults applications: ${view.safedefaults.length} origin${view.safedefaults.length === 1 ? "" : "s"} under the reads only posture.`;
|
|
91
|
+
transparencyroot.append(grants, windows, permdiffs, safedefaults);
|
|
92
|
+
}
|
|
93
|
+
function renderonboarding(onboarding) {
|
|
94
|
+
if (!onboardingroot) return;
|
|
95
|
+
onboardingroot.replaceChildren();
|
|
96
|
+
const state = document.createElement("p");
|
|
97
|
+
state.textContent = onboarding.done ? "The onboarding walkthrough is done; replay it on demand from the optionspage." : `The onboarding walkthrough stands at ${onboarding.stepscompleted.length} completed step${onboarding.stepscompleted.length === 1 ? "" : "s"}.`;
|
|
98
|
+
onboardingroot.append(state);
|
|
99
|
+
}
|
|
100
|
+
async function render() {
|
|
101
|
+
const view = await request({ kind: "surface", dashboard: { view: true } });
|
|
102
|
+
rendersessiongrid(view.sessionview);
|
|
103
|
+
rendersitenotes(view.sessionview);
|
|
104
|
+
rendertransparency(view.transparency);
|
|
105
|
+
renderonboarding(view.onboarding);
|
|
106
|
+
status(`Dashboard view live: ${view.sessionview.grid.length} run${view.sessionview.grid.length === 1 ? "" : "s"}, ${view.sessionview.notes.length} note${view.sessionview.notes.length === 1 ? "" : "s"} and ${view.transparency.grants.length} grant row${view.transparency.grants.length === 1 ? "" : "s"}.`);
|
|
107
|
+
}
|
|
108
|
+
document.querySelector("#openpanel")?.addEventListener("click", () => {
|
|
109
|
+
void chrome.sidePanel.open({ windowId: chrome.windows.WINDOW_ID_CURRENT }).catch(() => {
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
document.querySelector("#openoptions")?.addEventListener("click", () => {
|
|
113
|
+
void chrome.tabs.create({ url: chrome.runtime.getURL("optionspage.html") });
|
|
114
|
+
});
|
|
115
|
+
document.querySelector("#historyrun")?.addEventListener("click", () => {
|
|
116
|
+
void renderhistorysearch(historyinput?.value ?? "").catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
117
|
+
});
|
|
118
|
+
historyinput?.addEventListener("keydown", (event) => {
|
|
119
|
+
if (event.key === "Enter") document.querySelector("#historyrun")?.click();
|
|
120
|
+
});
|
|
121
|
+
var surfacechannel = typeof BroadcastChannel === "function" ? new BroadcastChannel("devthinksurfaces") : void 0;
|
|
122
|
+
surfacechannel?.addEventListener("message", () => {
|
|
123
|
+
void render().catch(() => {
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
void render().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
127
|
+
void renderhistorysearch("").catch(() => {
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=dashboardpage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../dashboardpage.ts"],
|
|
4
|
+
"sourcesContent": ["export {};\n\n/**\n * Dashboardpage runtime of the 1.1.64 family.\n * The dashboardpage opens in a new tab from the popup and the sidepanel and aggregates the sessions, the runs, the notes and the transparency views of the profile workspace; it renders the sessiongrid and the historysearch of the 1.1.63 session interface beside the transparency report of the 1.1.62 family and the onboarding state, and it subscribes to session and run updates through the single broadcast channel so the view stays live without a reload.\n */\n\ntype sessionview = {\n grid: Array<{ sessionid: string; runid: string; origins: string[]; state: string; outcome: string; steps: number; completed: number; lock: string; tabid?: number; sealhash?: string; updatedat: number; actions: string[] }>;\n notes: Array<{ id: string; origin: string; title: string; body: string; author: string; sensitive: boolean; updatedat: number }>;\n summaries: Array<{ runid: string; origins: string[]; kinds: string[]; steps: number; provenance: string; distilledat: number }>;\n};\ntype transparencyview = {\n grants: Array<{ origin: string; scope: string; boundary: string; grantedat: number }>;\n windows: Array<{ id: string; origin: string; state: string; boundary: string; startedat: number; expiresat: number }>;\n permdiffs: Array<{ fromversion: string; toversion: string; added: string[]; removed: string[]; computedat: number }>;\n safedefaults: Array<{ origin: string; firstseenat: number }>;\n};\ntype dashboardview = { sessionview: sessionview; transparency: transparencyview; onboarding: { stepscompleted: string[]; done: boolean }; environments?: { offscreengranted: boolean; parseoffload: boolean; workers?: number }; security?: { posture?: string } };\n\nconst statusnode = document.querySelector<HTMLElement>(\"#status\");\nconst sessiongridroot = document.querySelector<HTMLElement>(\"#sessiongrid\");\nconst historyhitsroot = document.querySelector<HTMLElement>(\"#historyhits\");\nconst sitenotesroot = document.querySelector<HTMLElement>(\"#sitenotes\");\nconst transparencyroot = document.querySelector<HTMLElement>(\"#transparency\");\nconst onboardingroot = document.querySelector<HTMLElement>(\"#onboarding\");\nconst historyinput = document.querySelector<HTMLInputElement>(\"#historyquery\");\n\nfunction status(message: string, error = false): void { if (statusnode) { statusnode.textContent = message; statusnode.dataset.state = error ? \"error\" : \"ready\"; } }\nasync function request(message: unknown): Promise<unknown> { const response = await chrome.runtime.sendMessage(message) as { ok: boolean; value?: unknown; error?: string }; if (!response.ok) throw new Error(response.error); return response.value; }\nfunction button(label: string, action: () => Promise<void>): HTMLButtonElement { const element = document.createElement(\"button\"); element.type = \"button\"; element.className = \"secondary\"; element.textContent = label; element.addEventListener(\"click\", () => action().catch(error => status(error instanceof Error ? error.message : String(error), true))); return element; }\n\n/** Renders the sessiongrid rows of the 1.1.63 session interface with their resume, cancelrun and reopen actions as deep links. */\nfunction rendersessiongrid(view: sessionview): void {\n if (!sessiongridroot) return;\n sessiongridroot.replaceChildren();\n if (view.grid.length === 0) { sessiongridroot.textContent = \"No session exists yet; start the first run from the popup taskinput.\"; return; }\n const list = document.createElement(\"ol\");\n list.className = \"audit\";\n for (const row of view.grid) {\n const item = document.createElement(\"li\");\n item.textContent = `${row.state} ${row.runid} \u2014 ${row.origins.join(\", \")} \u2014 ${row.completed}/${row.steps} steps \u2014 ${row.outcome} \u2014 ${row.lock}${row.sealhash !== undefined ? ` \u2014 sealed ${row.sealhash.slice(0, 12)}` : \"\"}`;\n for (const action of row.actions) item.append(\" \", button(action === \"cancelrun\" ? \"Cancel run\" : action === \"resume\" ? \"Resume\" : \"Reopen\", async () => {\n await request({ kind: \"sessions\", grid: action === \"cancelrun\" ? { open: { runid: row.runid } } : action === \"resume\" ? { resume: { runid: row.runid } } : { reopen: { runid: row.runid } } });\n if (action === \"cancelrun\") await request({ kind: \"surface\", bus: { action: { surface: \"dashboardpage\", command: \"cancelrun\" } } });\n status(`The ${action} action of the run ${row.runid} routed through the command bus.`);\n await render();\n }));\n list.append(item);\n }\n sessiongridroot.append(list);\n}\n\n/** Renders the historysearch corpus of the 1.1.63 session interface with the matched terms highlighted. */\nasync function renderhistorysearch(text: string): Promise<void> {\n if (!historyhitsroot) return;\n try {\n const result = await request({ kind: \"sessions\", search: { query: { text } } }) as { hits: Array<{ source: string; title: string; excerpt: string; highlights: string[]; origin?: string; at: number }> };\n historyhitsroot.replaceChildren();\n if (result.hits.length === 0) { historyhitsroot.append(Object.assign(document.createElement(\"li\"), { textContent: \"No history matches yet.\" })); return; }\n for (const hit of result.hits) {\n const item = document.createElement(\"li\");\n item.textContent = `${hit.source} \u2014 ${hit.title}${hit.origin !== undefined ? ` (${hit.origin})` : \"\"}: ${hit.excerpt}${hit.highlights.length > 0 ? ` [${hit.highlights.join(\", \")}]` : \"\"}`;\n historyhitsroot.append(item);\n }\n } catch (error) { historyhitsroot.textContent = error instanceof Error ? error.message : String(error); }\n}\n\n/** Renders the site notes of the session interface with their author provenance. */\nfunction rendersitenotes(view: sessionview): void {\n if (!sitenotesroot) return;\n if (view.notes.length === 0) { sitenotesroot.textContent = \"No site note exists yet; write the first note from the sidepanel.\"; return; }\n sitenotesroot.replaceChildren();\n const list = document.createElement(\"ul\");\n list.className = \"audit\";\n for (const note of view.notes) list.append(Object.assign(document.createElement(\"li\"), { textContent: `${note.title} (${note.origin}, by ${note.author}${note.sensitive ? \", sealed at rest\" : \"\"}): ${note.body}` }));\n sitenotesroot.append(list);\n}\n\n/** Renders the transparency views of the 1.1.62 family: the grants with their boundaries, the window history, the permdiffs and the safedefaults applications. */\nfunction rendertransparency(view: transparencyview): void {\n if (!transparencyroot) return;\n transparencyroot.replaceChildren();\n const grants = document.createElement(\"p\");\n grants.textContent = `Grants: ${view.grants.length} grant row${view.grants.length === 1 ? \"\" : \"s\"}${view.grants.length > 0 ? ` (${view.grants.slice(0, 5).map(grant => `${grant.origin} \u2014 ${grant.scope} \u2014 ${grant.boundary}`).join(\" \u00B7 \")})` : \"\"}.`;\n const windows = document.createElement(\"p\");\n windows.textContent = `Consent windows: ${view.windows.length} recorded window${view.windows.length === 1 ? \"\" : \"s\"}.`;\n const permdiffs = document.createElement(\"p\");\n permdiffs.textContent = `Permdiffs: ${view.permdiffs.length} record${view.permdiffs.length === 1 ? \"\" : \"s\"}${view.permdiffs.length > 0 ? ` (latest ${view.permdiffs[0]?.fromversion} \u2192 ${view.permdiffs[0]?.toversion})` : \"\"}.`;\n const safedefaults = document.createElement(\"p\");\n safedefaults.textContent = `Safedefaults applications: ${view.safedefaults.length} origin${view.safedefaults.length === 1 ? \"\" : \"s\"} under the reads only posture.`;\n transparencyroot.append(grants, windows, permdiffs, safedefaults);\n}\n\n/** Renders the onboarding state with its replay offer on demand. */\nfunction renderonboarding(onboarding: { stepscompleted: string[]; done: boolean }): void {\n if (!onboardingroot) return;\n onboardingroot.replaceChildren();\n const state = document.createElement(\"p\");\n state.textContent = onboarding.done ? \"The onboarding walkthrough is done; replay it on demand from the optionspage.\" : `The onboarding walkthrough stands at ${onboarding.stepscompleted.length} completed step${onboarding.stepscompleted.length === 1 ? \"\" : \"s\"}.`;\n onboardingroot.append(state);\n}\n\n/** Loads the aggregated dashboard view: the sessionview of 1.1.63, the transparency report of 1.1.62 and the onboarding state. */\nasync function render(): Promise<void> {\n const view = await request({ kind: \"surface\", dashboard: { view: true } }) as dashboardview;\n rendersessiongrid(view.sessionview);\n rendersitenotes(view.sessionview);\n rendertransparency(view.transparency);\n renderonboarding(view.onboarding);\n status(`Dashboard view live: ${view.sessionview.grid.length} run${view.sessionview.grid.length === 1 ? \"\" : \"s\"}, ${view.sessionview.notes.length} note${view.sessionview.notes.length === 1 ? \"\" : \"s\"} and ${view.transparency.grants.length} grant row${view.transparency.grants.length === 1 ? \"\" : \"s\"}.`);\n}\n\ndocument.querySelector<HTMLButtonElement>(\"#openpanel\")?.addEventListener(\"click\", () => { void chrome.sidePanel.open({ windowId: chrome.windows.WINDOW_ID_CURRENT }).catch(() => { /* the panel opens beside the dashboard tab */ }); });\ndocument.querySelector<HTMLButtonElement>(\"#openoptions\")?.addEventListener(\"click\", () => { void chrome.tabs.create({ url: chrome.runtime.getURL(\"optionspage.html\") }); });\ndocument.querySelector<HTMLButtonElement>(\"#historyrun\")?.addEventListener(\"click\", () => { void renderhistorysearch(historyinput?.value ?? \"\").catch(error => status(error instanceof Error ? error.message : String(error), true)); });\nhistoryinput?.addEventListener(\"keydown\", event => { if (event.key === \"Enter\") document.querySelector<HTMLButtonElement>(\"#historyrun\")?.click(); });\n\n/** The dashboardpage subscribes to session and run updates through the single broadcast channel. */\nconst surfacechannel: BroadcastChannel | undefined = typeof BroadcastChannel === \"function\" ? new BroadcastChannel(\"devthinksurfaces\") : undefined;\nsurfacechannel?.addEventListener(\"message\", () => { void render().catch(() => { /* a failing refresh keeps the last rendered dashboard */ }); });\n\nvoid render().catch(error => status(error instanceof Error ? error.message : String(error), true));\nvoid renderhistorysearch(\"\").catch(() => { /* an empty first search shows the empty state */ });\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOEjO8Z0PDgQyfvawGcaO2j+o0GLCFTLNj7TkYC/Avo9l2NenMRq7gp90Nfd7E9MViv/OMcCKSYZ5unv12QPRtv31C+a5UQWDFAOP/cH5mwMd6hsayElrSoW8ta+FwFqmr9dIFkn7cQEU3YhZr4Gcbs+ycUHOxVgDA4NBKB0rQ6e9VW5LvTw0isRYUrqM+M72vKxHk9zUIYYn/LGPvottKBYi2GLr0PHSeC2UE+Shmq7vcFIXj6hDjvD4kLJ5sKoUllEcZ1TPuBcnHUQ9ndKA5iktXDQOIJCUJmi7a0YJ2PGg7fvpYfT9k0ai/qZ+pIoRfoOEwE01bPoDn7NjeYnNQIDAQAB",
|
|
4
4
|
"name": "Devthink",
|
|
5
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.64",
|
|
6
6
|
"description": "A consent-first bridge for reviewed browser-agent tasks.",
|
|
7
7
|
"permissions": [
|
|
8
8
|
"activeTab",
|
|
@@ -44,8 +44,11 @@
|
|
|
44
44
|
"side_panel": {
|
|
45
45
|
"default_path": "sidepanel.html"
|
|
46
46
|
},
|
|
47
|
+
"chrome_url_overrides": {
|
|
48
|
+
"newtab": "dashboardpage.html"
|
|
49
|
+
},
|
|
47
50
|
"options_ui": {
|
|
48
|
-
"page": "
|
|
51
|
+
"page": "optionspage.html",
|
|
49
52
|
"open_in_tab": true
|
|
50
53
|
}
|
|
51
54
|
}
|
|
@@ -7,6 +7,7 @@ self.onmessage = event => {
|
|
|
7
7
|
if (task === "jsonpayload") { JSON.parse(payload); result = payload; }
|
|
8
8
|
else if (task === "htmlsnapshot" || task === "readertree" || task === "readoutline" || task === "classifypage") { const doc = new DOMParser().parseFromString(payload, "text/html"); result = (doc.body && doc.body.textContent ? doc.body.textContent : payload).trim(); }
|
|
9
9
|
else if (task === "tablerows" || task === "a11ytree" || task === "complexselector" || task === "stitchshots") { result = payload; }
|
|
10
|
+
else if (task === "diffpreview") { const states = JSON.parse(payload); if (!states || typeof states !== "object" || typeof states.before !== "object" || typeof states.after !== "object") throw new Error("malformed diff states"); result = payload; }
|
|
10
11
|
else result = payload;
|
|
11
12
|
self.postMessage({ id, ok: true, result, summary: "The offscreen worker finished the " + task + " parse." });
|
|
12
13
|
} catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../offscreen.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Offscreen document runtime of the 1.1.60 family.\n * The offscreen document hosts the worker pool that parses heavy payloads away from the page and the sandbox frame iframe that renders untrusted markup without extension privileges; the background spawns this document on first use through the offscreen api only after the user grants the optional offscreen capability, and every parse task still rides a reviewed step of an approved plan.\n */\n\ntype parserequest = { kind: \"offscreen\"; action: \"parse\"; request: { id: string; runid: string; stepid: string; task: string; payload: string; transferables: string[] } };\ntype summaryrequest = { kind: \"offscreen\"; action: \"summary\"; request: { id: string; runid: string; stepid: string; task: string; payload: string; transferables: string[] } };\ntype renderrequest = { kind: \"offscreen\"; action: \"sandboxrender\"; render: { id: string; nonce: string; markup: string; sourceorigin: string; stepid: string } };\ntype poolrequest = { kind: \"offscreen\"; action: \"pool\" };\n\n/** The worker sources of the parse families: pure functions that shape html, json, table, a11y tree, selector and stitch payloads without touching any page. */\nconst workersource = `\nself.onmessage = event => {\n const { id, task, payload } = event.data || {};\n try {\n let result = \"\";\n if (task === \"jsonpayload\") { JSON.parse(payload); result = payload; }\n else if (task === \"htmlsnapshot\" || task === \"readertree\" || task === \"readoutline\" || task === \"classifypage\") { const doc = new DOMParser().parseFromString(payload, \"text/html\"); result = (doc.body && doc.body.textContent ? doc.body.textContent : payload).trim(); }\n else if (task === \"tablerows\" || task === \"a11ytree\" || task === \"complexselector\" || task === \"stitchshots\") { result = payload; }\n else result = payload;\n self.postMessage({ id, ok: true, result, summary: \"The offscreen worker finished the \" + task + \" parse.\" });\n } catch (error) {\n self.postMessage({ id, ok: false, result: \"\", summary: \"The offscreen worker refused the \" + task + \" parse: \" + (error && error.message ? error.message : \"malformed payload\") });\n }\n};\n`;\n\nconst pool = new Set<Worker>();\nlet sandboxframe: HTMLIFrameElement | undefined;\nlet renderseq = 0;\nconst pendingrenders = new Map<string, (value: { ok: boolean; text: string; summary: string }) => void>();\n\nfunction ensureworker(): Worker {\n for (const worker of pool) return worker;\n const worker = new Worker(URL.createObjectURL(new Blob([workersource], { type: \"text/javascript\" })), { type: \"classic\" });\n pool.add(worker);\n return worker;\n}\n\nfunction ensuresandboxframe(): HTMLIFrameElement {\n if (sandboxframe) return sandboxframe;\n const frame = document.createElement(\"iframe\");\n frame.src = \"sandbox.html\";\n frame.style.display = \"none\";\n frame.setAttribute(\"aria-hidden\", \"true\");\n document.body.append(frame);\n sandboxframe = frame;\n return frame;\n}\n\nwindow.addEventListener(\"message\", event => {\n const data = event.data as { channel?: string; type?: string; nonce?: string; ok?: boolean; text?: string; summary?: string };\n if (data?.channel !== \"devthinksandbox\" || data.type !== \"renderresult\" || data.nonce === undefined) return;\n const resolver = pendingrenders.get(data.nonce);\n if (!resolver) return;\n pendingrenders.delete(data.nonce);\n resolver({ ok: data.ok !== false, text: data.text ?? \"\", summary: data.summary ?? \"The sandbox frame returned its render result.\" });\n});\n\nfunction runparse(request: parserequest[\"request\"]): Promise<{ ok: boolean; result: string; summary: string }> {\n return new Promise(resolve => {\n const worker = ensureworker();\n const timeout = window.setTimeout(() => resolve({ ok: false, result: \"\", summary: `The offscreen worker never answered the ${request.task} parse of the step ${request.stepid}.` }), 30000);\n worker.onmessage = event => {\n const answer = event.data as { id?: string; ok?: boolean; result?: string; summary?: string };\n if (answer.id !== request.id) return;\n window.clearTimeout(timeout);\n resolve({ ok: answer.ok !== false, result: answer.result ?? \"\", summary: answer.summary ?? \"The offscreen worker answered.\" });\n };\n worker.postMessage({ id: request.id, task: request.task, payload: request.payload });\n });\n}\n\nfunction runrender(render: renderrequest[\"render\"]): Promise<{ ok: boolean; text: string; summary: string }> {\n return new Promise(resolve => {\n const frame = ensuresandboxframe();\n renderseq += 1;\n const nonce = render.nonce;\n pendingrenders.set(nonce, resolve);\n window.setTimeout(() => {\n if (pendingrenders.delete(nonce)) resolve({ ok: false, text: \"\", summary: `The sandbox frame never answered the render of the step ${render.stepid}.` });\n }, 15000);\n frame.contentWindow?.postMessage({ channel: \"devthinksandbox\", type: \"render\", nonce, markup: render.markup }, \"*\");\n void renderseq;\n });\n}\n\nchrome.runtime.onMessage.addListener((message: parserequest | summaryrequest | renderrequest | poolrequest, _sender, sendresponse) => {\n if (!message || (message as { kind?: string }).kind !== \"offscreen\") return false;\n if (message.action === \"parse\") {\n void runparse(message.request).then(answer => sendresponse({ ok: answer.ok, result: answer.result, summary: answer.summary }));\n return true;\n }\n if (message.action === \"summary\") {\n void runparse(message.request).then(answer => sendresponse({ ok: answer.ok, summary: `The offscreen worker verified the ${message.request.task} distillation of the run ${message.request.runid}: ${answer.summary}` }));\n return true;\n }\n if (message.action === \"sandboxrender\") {\n void runrender(message.render).then(answer => sendresponse({ ok: answer.ok, text: answer.text, summary: answer.summary }));\n return true;\n }\n if (message.action === \"pool\") {\n sendresponse({ workers: pool.size });\n return true;\n }\n return false;\n});\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * Offscreen document runtime of the 1.1.60 family.\n * The offscreen document hosts the worker pool that parses heavy payloads away from the page and the sandbox frame iframe that renders untrusted markup without extension privileges; the background spawns this document on first use through the offscreen api only after the user grants the optional offscreen capability, and every parse task still rides a reviewed step of an approved plan. The 1.1.64 family adds the diffpreview task: the offscreen worker parses the large before and after states of one write class step so the diff generation offloads from the service worker while the comparison itself stays a pure reviewed computation.\n */\n\ntype parserequest = { kind: \"offscreen\"; action: \"parse\"; request: { id: string; runid: string; stepid: string; task: string; payload: string; transferables: string[] } };\ntype summaryrequest = { kind: \"offscreen\"; action: \"summary\"; request: { id: string; runid: string; stepid: string; task: string; payload: string; transferables: string[] } };\ntype diffrequest = { kind: \"offscreen\"; action: \"parse\"; request: { id: string; runid: string; stepid: string; task: \"diffpreview\"; payload: string; transferables: string[] } };\ntype renderrequest = { kind: \"offscreen\"; action: \"sandboxrender\"; render: { id: string; nonce: string; markup: string; sourceorigin: string; stepid: string } };\ntype poolrequest = { kind: \"offscreen\"; action: \"pool\" };\n\n/** The worker sources of the parse families: pure functions that shape html, json, table, a11y tree, selector and stitch payloads without touching any page. */\nconst workersource = `\nself.onmessage = event => {\n const { id, task, payload } = event.data || {};\n try {\n let result = \"\";\n if (task === \"jsonpayload\") { JSON.parse(payload); result = payload; }\n else if (task === \"htmlsnapshot\" || task === \"readertree\" || task === \"readoutline\" || task === \"classifypage\") { const doc = new DOMParser().parseFromString(payload, \"text/html\"); result = (doc.body && doc.body.textContent ? doc.body.textContent : payload).trim(); }\n else if (task === \"tablerows\" || task === \"a11ytree\" || task === \"complexselector\" || task === \"stitchshots\") { result = payload; }\n else if (task === \"diffpreview\") { const states = JSON.parse(payload); if (!states || typeof states !== \"object\" || typeof states.before !== \"object\" || typeof states.after !== \"object\") throw new Error(\"malformed diff states\"); result = payload; }\n else result = payload;\n self.postMessage({ id, ok: true, result, summary: \"The offscreen worker finished the \" + task + \" parse.\" });\n } catch (error) {\n self.postMessage({ id, ok: false, result: \"\", summary: \"The offscreen worker refused the \" + task + \" parse: \" + (error && error.message ? error.message : \"malformed payload\") });\n }\n};\n`;\n\nconst pool = new Set<Worker>();\nlet sandboxframe: HTMLIFrameElement | undefined;\nlet renderseq = 0;\nconst pendingrenders = new Map<string, (value: { ok: boolean; text: string; summary: string }) => void>();\n\nfunction ensureworker(): Worker {\n for (const worker of pool) return worker;\n const worker = new Worker(URL.createObjectURL(new Blob([workersource], { type: \"text/javascript\" })), { type: \"classic\" });\n pool.add(worker);\n return worker;\n}\n\nfunction ensuresandboxframe(): HTMLIFrameElement {\n if (sandboxframe) return sandboxframe;\n const frame = document.createElement(\"iframe\");\n frame.src = \"sandbox.html\";\n frame.style.display = \"none\";\n frame.setAttribute(\"aria-hidden\", \"true\");\n document.body.append(frame);\n sandboxframe = frame;\n return frame;\n}\n\nwindow.addEventListener(\"message\", event => {\n const data = event.data as { channel?: string; type?: string; nonce?: string; ok?: boolean; text?: string; summary?: string };\n if (data?.channel !== \"devthinksandbox\" || data.type !== \"renderresult\" || data.nonce === undefined) return;\n const resolver = pendingrenders.get(data.nonce);\n if (!resolver) return;\n pendingrenders.delete(data.nonce);\n resolver({ ok: data.ok !== false, text: data.text ?? \"\", summary: data.summary ?? \"The sandbox frame returned its render result.\" });\n});\n\nfunction runparse(request: parserequest[\"request\"]): Promise<{ ok: boolean; result: string; summary: string }> {\n return new Promise(resolve => {\n const worker = ensureworker();\n const timeout = window.setTimeout(() => resolve({ ok: false, result: \"\", summary: `The offscreen worker never answered the ${request.task} parse of the step ${request.stepid}.` }), 30000);\n worker.onmessage = event => {\n const answer = event.data as { id?: string; ok?: boolean; result?: string; summary?: string };\n if (answer.id !== request.id) return;\n window.clearTimeout(timeout);\n resolve({ ok: answer.ok !== false, result: answer.result ?? \"\", summary: answer.summary ?? \"The offscreen worker answered.\" });\n };\n worker.postMessage({ id: request.id, task: request.task, payload: request.payload });\n });\n}\n\nfunction runrender(render: renderrequest[\"render\"]): Promise<{ ok: boolean; text: string; summary: string }> {\n return new Promise(resolve => {\n const frame = ensuresandboxframe();\n renderseq += 1;\n const nonce = render.nonce;\n pendingrenders.set(nonce, resolve);\n window.setTimeout(() => {\n if (pendingrenders.delete(nonce)) resolve({ ok: false, text: \"\", summary: `The sandbox frame never answered the render of the step ${render.stepid}.` });\n }, 15000);\n frame.contentWindow?.postMessage({ channel: \"devthinksandbox\", type: \"render\", nonce, markup: render.markup }, \"*\");\n void renderseq;\n });\n}\n\nchrome.runtime.onMessage.addListener((message: parserequest | summaryrequest | diffrequest | renderrequest | poolrequest, _sender, sendresponse) => {\n if (!message || (message as { kind?: string }).kind !== \"offscreen\") return false;\n if (message.action === \"parse\") {\n void runparse(message.request).then(answer => sendresponse({ ok: answer.ok, result: answer.result, summary: answer.summary }));\n return true;\n }\n if (message.action === \"summary\") {\n void runparse(message.request).then(answer => sendresponse({ ok: answer.ok, summary: `The offscreen worker verified the ${message.request.task} distillation of the run ${message.request.runid}: ${answer.summary}` }));\n return true;\n }\n if (message.action === \"sandboxrender\") {\n void runrender(message.render).then(answer => sendresponse({ ok: answer.ok, text: answer.text, summary: answer.summary }));\n return true;\n }\n if (message.action === \"pool\") {\n sendresponse({ workers: pool.size });\n return true;\n }\n return false;\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["worker"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Devthink options</title><link rel="stylesheet" href="style.css"></head>
|
|
4
|
+
<body><main class="wide"><header><p class="eyebrow">OPTIONS</p><h1>Every setting in one place</h1><p>Every write takes effect without reloading the extension.</p></header>
|
|
5
|
+
<p id="status" role="status">Loading the surface options.</p>
|
|
6
|
+
<section><h2>Onboarding</h2><div id="onboarding" class="panel"></div><div class="actions"><button id="replayonboarding" class="secondary">Replay onboarding</button></div></section>
|
|
7
|
+
<section><h2>Command palette</h2><div class="panel"><label for="paletterecents">Recent commands window</label><input id="paletterecents" type="number" min="0" placeholder="no window"><label for="paletteshortcut">Keyboard shortcut</label><input id="paletteshortcut" type="text" placeholder="ctrl+."><button id="palettesettings">Save palette options</button></div></section>
|
|
8
|
+
<section><h2>Log stream</h2><div class="panel"><label for="logstreambuffer">Live buffer bound</label><input id="logstreambuffer" type="number" min="1" placeholder="no bound (full history stays in memory)"><button id="logstreamsettings">Save logstream options</button></div></section>
|
|
9
|
+
<section><h2>Task input</h2><div class="panel"><label for="taskinputretention">History retention (ms)</label><input id="taskinputretention" type="number" min="1" placeholder="keep every entry"><button id="taskinputsettings">Save taskinput options</button></div></section>
|
|
10
|
+
<section><h2>Diff preview</h2><div class="panel"><label for="diffpreviewbytes">Offscreen offload byte ceiling</label><input id="diffpreviewbytes" type="number" min="1" placeholder="keep every diff inline"><button id="diffsettings">Save diffpreview options</button></div></section>
|
|
11
|
+
<section><h2>Session interface options</h2><div class="panel"><label for="recallwindow">Recall window (ms)</label><input id="recallwindow" type="number" min="1" placeholder="keep every entry"><label for="noteretention">Note retention (ms)</label><input id="noteretention" type="number" min="1" placeholder="keep every note"><label for="summarywindow">Summary window (steps)</label><input id="summarywindow" type="number" min="0" placeholder="keep every step"><button id="sessionsettings">Save session options</button></div></section>
|
|
12
|
+
<section><h2>Transparency and consent options</h2><iframe src="transparencypage.html" title="Transparency, consent and security options" style="width:100%;min-height:24rem;border:0"></iframe></section>
|
|
13
|
+
</main><script type="module" src="optionspage.js"></script></body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// extension/optionspage.ts
|
|
2
|
+
var statusnode = document.querySelector("#status");
|
|
3
|
+
var onboardingroot = document.querySelector("#onboarding");
|
|
4
|
+
var paletterecentsinput = document.querySelector("#paletterecents");
|
|
5
|
+
var paletteshortcutinput = document.querySelector("#paletteshortcut");
|
|
6
|
+
var logstreambufferinput = document.querySelector("#logstreambuffer");
|
|
7
|
+
var taskinputretentioninput = document.querySelector("#taskinputretention");
|
|
8
|
+
var diffpreviewbytesinput = document.querySelector("#diffpreviewbytes");
|
|
9
|
+
var recallwindowinput = document.querySelector("#recallwindow");
|
|
10
|
+
var noteretentioninput = document.querySelector("#noteretention");
|
|
11
|
+
var summarywindowinput = document.querySelector("#summarywindow");
|
|
12
|
+
function status(message, error = false) {
|
|
13
|
+
if (statusnode) {
|
|
14
|
+
statusnode.textContent = message;
|
|
15
|
+
statusnode.dataset.state = error ? "error" : "ready";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function request(message) {
|
|
19
|
+
const response = await chrome.runtime.sendMessage(message);
|
|
20
|
+
if (!response.ok) throw new Error(response.error);
|
|
21
|
+
return response.value;
|
|
22
|
+
}
|
|
23
|
+
async function load() {
|
|
24
|
+
try {
|
|
25
|
+
const context = await request({ kind: "context" });
|
|
26
|
+
const preferences = context.surfacepreferences ?? {};
|
|
27
|
+
const session = context.sessionpreferences ?? {};
|
|
28
|
+
if (preferences.paletterecents !== void 0 && paletterecentsinput) paletterecentsinput.value = String(preferences.paletterecents);
|
|
29
|
+
if (preferences.paletteshortcut !== void 0 && paletteshortcutinput) paletteshortcutinput.value = preferences.paletteshortcut;
|
|
30
|
+
if (preferences.logstreambuffer !== void 0 && logstreambufferinput) logstreambufferinput.value = String(preferences.logstreambuffer);
|
|
31
|
+
if (preferences.taskinputretention !== void 0 && taskinputretentioninput) taskinputretentioninput.value = String(preferences.taskinputretention);
|
|
32
|
+
if (preferences.diffpreviewbytes !== void 0 && diffpreviewbytesinput) diffpreviewbytesinput.value = String(preferences.diffpreviewbytes);
|
|
33
|
+
if (session.recallwindow !== void 0 && recallwindowinput) recallwindowinput.value = String(session.recallwindow);
|
|
34
|
+
if (session.noteretention !== void 0 && noteretentioninput) noteretentioninput.value = String(session.noteretention);
|
|
35
|
+
if (session.summarywindow !== void 0 && summarywindowinput) summarywindowinput.value = String(session.summarywindow);
|
|
36
|
+
status("The surface options loaded; every write takes effect without reloading the extension.");
|
|
37
|
+
} catch (error) {
|
|
38
|
+
status(error instanceof Error ? error.message : String(error), true);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function savepalette() {
|
|
42
|
+
const paletterecents = paletterecentsinput?.value.trim() ?? "";
|
|
43
|
+
const paletteshortcut = paletteshortcutinput?.value.trim() ?? "";
|
|
44
|
+
await request({ kind: "surface", settings: { ...paletterecents !== "" ? { paletterecents: Number(paletterecents) } : {}, ...paletteshortcut !== "" ? { paletteshortcut } : {} } });
|
|
45
|
+
status(`The palette options saved${paletterecents !== "" ? ` with the recent window of ${paletterecents}` : ""}${paletteshortcut !== "" ? ` and the shortcut ${paletteshortcut}` : ""}.`);
|
|
46
|
+
}
|
|
47
|
+
async function savelogstream() {
|
|
48
|
+
const bound = logstreambufferinput?.value.trim() ?? "";
|
|
49
|
+
await request({ kind: "surface", settings: { ...bound !== "" ? { logstreambuffer: Number(bound) } : {} } });
|
|
50
|
+
status(bound === "" ? "No bound configured; the live window keeps every event." : `The logstream live buffer bound of ${bound} saved; the full history stays in memory.`);
|
|
51
|
+
}
|
|
52
|
+
async function savetaskinput() {
|
|
53
|
+
const retention = taskinputretentioninput?.value.trim() ?? "";
|
|
54
|
+
await request({ kind: "surface", settings: { ...retention !== "" ? { taskinputretention: Number(retention) } : {} } });
|
|
55
|
+
status(retention === "" ? "No retention configured; the taskinput history keeps every entry." : `The taskinput history retention of ${retention} milliseconds saved.`);
|
|
56
|
+
}
|
|
57
|
+
async function savediff() {
|
|
58
|
+
const bytes = diffpreviewbytesinput?.value.trim() ?? "";
|
|
59
|
+
await request({ kind: "surface", settings: { ...bytes !== "" ? { diffpreviewbytes: Number(bytes) } : {} } });
|
|
60
|
+
status(bytes === "" ? "No ceiling configured; every diff stays inline." : `The diffpreview offload ceiling of ${bytes} bytes saved.`);
|
|
61
|
+
}
|
|
62
|
+
async function savesession() {
|
|
63
|
+
const recallwindow = recallwindowinput?.value.trim() ?? "";
|
|
64
|
+
const noteretention = noteretentioninput?.value.trim() ?? "";
|
|
65
|
+
const summarywindow = summarywindowinput?.value.trim() ?? "";
|
|
66
|
+
await request({ kind: "sessions", settings: { ...recallwindow !== "" ? { recallwindow: Number(recallwindow) } : {}, ...noteretention !== "" ? { noteretention: Number(noteretention) } : {}, ...summarywindow !== "" ? { summarywindow: Number(summarywindow) } : {} } });
|
|
67
|
+
status("The session interface options saved; the recall window, the note retention and the summary window take effect at once.");
|
|
68
|
+
}
|
|
69
|
+
async function renderonboarding() {
|
|
70
|
+
if (!onboardingroot) return;
|
|
71
|
+
try {
|
|
72
|
+
const result = await request({ kind: "surface", onboarding: {} });
|
|
73
|
+
onboardingroot.replaceChildren();
|
|
74
|
+
const state = result.state;
|
|
75
|
+
const line = document.createElement("p");
|
|
76
|
+
line.textContent = state === void 0 ? "The onboarding walkthrough never ran; it starts on the next popup open." : state.done ? `The walkthrough is done (${state.stepscompleted.length} steps); the replay restarts it on demand and writes no second consent event.` : `The walkthrough stands at ${state.stepscompleted.length} of ${result.steps.length} steps.`;
|
|
77
|
+
onboardingroot.append(line);
|
|
78
|
+
const list = document.createElement("ol");
|
|
79
|
+
list.className = "audit";
|
|
80
|
+
for (const step of result.steps) list.append(Object.assign(document.createElement("li"), { textContent: `${step.title} (${step.surface}): ${step.body}${state?.stepscompleted.includes(step.id) ? " \u2014 done" : ""}` }));
|
|
81
|
+
onboardingroot.append(list);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
onboardingroot.textContent = error instanceof Error ? error.message : String(error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
document.querySelector("#replayonboarding")?.addEventListener("click", () => {
|
|
87
|
+
void (async () => {
|
|
88
|
+
await request({ kind: "surface", onboarding: { replay: true } });
|
|
89
|
+
status("The onboarding walkthrough replays; it opens on the next popup open.");
|
|
90
|
+
await renderonboarding();
|
|
91
|
+
})().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
92
|
+
});
|
|
93
|
+
document.querySelector("#palettesettings")?.addEventListener("click", () => {
|
|
94
|
+
void savepalette().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
95
|
+
});
|
|
96
|
+
document.querySelector("#logstreamsettings")?.addEventListener("click", () => {
|
|
97
|
+
void savelogstream().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
98
|
+
});
|
|
99
|
+
document.querySelector("#taskinputsettings")?.addEventListener("click", () => {
|
|
100
|
+
void savetaskinput().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
101
|
+
});
|
|
102
|
+
document.querySelector("#diffsettings")?.addEventListener("click", () => {
|
|
103
|
+
void savediff().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
104
|
+
});
|
|
105
|
+
document.querySelector("#sessionsettings")?.addEventListener("click", () => {
|
|
106
|
+
void savesession().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
107
|
+
});
|
|
108
|
+
var surfacechannel = typeof BroadcastChannel === "function" ? new BroadcastChannel("devthinksurfaces") : void 0;
|
|
109
|
+
surfacechannel?.addEventListener("message", (event) => {
|
|
110
|
+
const frame = event.data;
|
|
111
|
+
if (frame?.channel === "settings") {
|
|
112
|
+
void load().catch(() => {
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
void load();
|
|
117
|
+
void renderonboarding();
|
|
118
|
+
//# sourceMappingURL=optionspage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../optionspage.ts"],
|
|
4
|
+
"sourcesContent": ["export {};\n\n/**\n * Optionspage runtime of the 1.1.64 family.\n * The optionspage gathers every setting into one page with sections: the onboarding replay, the commandpalette recent window and shortcut, the logstream live buffer bound, the taskinput history retention, the diffpreview offscreen offload ceiling and the session interface options of the 1.1.63 family, while the transparency, consent and security sections of the earlier releases import through the embedded transparencypage; every write takes effect without reloading the extension because the background reads its settings live on each decision.\n */\n\nconst statusnode = document.querySelector<HTMLElement>(\"#status\");\nconst onboardingroot = document.querySelector<HTMLElement>(\"#onboarding\");\nconst paletterecentsinput = document.querySelector<HTMLInputElement>(\"#paletterecents\");\nconst paletteshortcutinput = document.querySelector<HTMLInputElement>(\"#paletteshortcut\");\nconst logstreambufferinput = document.querySelector<HTMLInputElement>(\"#logstreambuffer\");\nconst taskinputretentioninput = document.querySelector<HTMLInputElement>(\"#taskinputretention\");\nconst diffpreviewbytesinput = document.querySelector<HTMLInputElement>(\"#diffpreviewbytes\");\nconst recallwindowinput = document.querySelector<HTMLInputElement>(\"#recallwindow\");\nconst noteretentioninput = document.querySelector<HTMLInputElement>(\"#noteretention\");\nconst summarywindowinput = document.querySelector<HTMLInputElement>(\"#summarywindow\");\n\nfunction status(message: string, error = false): void { if (statusnode) { statusnode.textContent = message; statusnode.dataset.state = error ? \"error\" : \"ready\"; } }\nasync function request(message: unknown): Promise<unknown> { const response = await chrome.runtime.sendMessage(message) as { ok: boolean; value?: unknown; error?: string }; if (!response.ok) throw new Error(response.error); return response.value; }\n\ntype surfacecontext = { sessionpreferences?: { recallwindow?: number; noteretention?: number; summarywindow?: number }; surfacepreferences?: { paletterecents?: number; paletteshortcut?: string; logstreambuffer?: number; taskinputretention?: number; diffpreviewbytes?: number } };\n\n/** Loads the stored surface options into the inputs; an absent value keeps the placeholder that names the documented default. */\nasync function load(): Promise<void> {\n try {\n const context = await request({ kind: \"context\" }) as surfacecontext;\n const preferences = context.surfacepreferences ?? {};\n const session = context.sessionpreferences ?? {};\n if (preferences.paletterecents !== undefined && paletterecentsinput) paletterecentsinput.value = String(preferences.paletterecents);\n if (preferences.paletteshortcut !== undefined && paletteshortcutinput) paletteshortcutinput.value = preferences.paletteshortcut;\n if (preferences.logstreambuffer !== undefined && logstreambufferinput) logstreambufferinput.value = String(preferences.logstreambuffer);\n if (preferences.taskinputretention !== undefined && taskinputretentioninput) taskinputretentioninput.value = String(preferences.taskinputretention);\n if (preferences.diffpreviewbytes !== undefined && diffpreviewbytesinput) diffpreviewbytesinput.value = String(preferences.diffpreviewbytes);\n if (session.recallwindow !== undefined && recallwindowinput) recallwindowinput.value = String(session.recallwindow);\n if (session.noteretention !== undefined && noteretentioninput) noteretentioninput.value = String(session.noteretention);\n if (session.summarywindow !== undefined && summarywindowinput) summarywindowinput.value = String(session.summarywindow);\n status(\"The surface options loaded; every write takes effect without reloading the extension.\");\n } catch (error) { status(error instanceof Error ? error.message : String(error), true); }\n}\n\n/** Writes the commandpalette options; the recent window and the shortcut stay user choices with no engine defaults forced. */\nasync function savepalette(): Promise<void> {\n const paletterecents = paletterecentsinput?.value.trim() ?? \"\";\n const paletteshortcut = paletteshortcutinput?.value.trim() ?? \"\";\n await request({ kind: \"surface\", settings: { ...(paletterecents !== \"\" ? { paletterecents: Number(paletterecents) } : {}), ...(paletteshortcut !== \"\" ? { paletteshortcut } : {}) } });\n status(`The palette options saved${paletterecents !== \"\" ? ` with the recent window of ${paletterecents}` : \"\"}${paletteshortcut !== \"\" ? ` and the shortcut ${paletteshortcut}` : \"\"}.`);\n}\n\n/** Writes the logstream live buffer bound; the full history stays in memory whatever the bound. */\nasync function savelogstream(): Promise<void> {\n const bound = logstreambufferinput?.value.trim() ?? \"\";\n await request({ kind: \"surface\", settings: { ...(bound !== \"\" ? { logstreambuffer: Number(bound) } : {}) } });\n status(bound === \"\" ? \"No bound configured; the live window keeps every event.\" : `The logstream live buffer bound of ${bound} saved; the full history stays in memory.`);\n}\n\n/** Writes the taskinput history retention. */\nasync function savetaskinput(): Promise<void> {\n const retention = taskinputretentioninput?.value.trim() ?? \"\";\n await request({ kind: \"surface\", settings: { ...(retention !== \"\" ? { taskinputretention: Number(retention) } : {}) } });\n status(retention === \"\" ? \"No retention configured; the taskinput history keeps every entry.\" : `The taskinput history retention of ${retention} milliseconds saved.`);\n}\n\n/** Writes the diffpreview offscreen offload byte ceiling. */\nasync function savediff(): Promise<void> {\n const bytes = diffpreviewbytesinput?.value.trim() ?? \"\";\n await request({ kind: \"surface\", settings: { ...(bytes !== \"\" ? { diffpreviewbytes: Number(bytes) } : {}) } });\n status(bytes === \"\" ? \"No ceiling configured; every diff stays inline.\" : `The diffpreview offload ceiling of ${bytes} bytes saved.`);\n}\n\n/** Writes the session interface options of the 1.1.63 family through the sessions settings seam. */\nasync function savesession(): Promise<void> {\n const recallwindow = recallwindowinput?.value.trim() ?? \"\";\n const noteretention = noteretentioninput?.value.trim() ?? \"\";\n const summarywindow = summarywindowinput?.value.trim() ?? \"\";\n await request({ kind: \"sessions\", settings: { ...(recallwindow !== \"\" ? { recallwindow: Number(recallwindow) } : {}), ...(noteretention !== \"\" ? { noteretention: Number(noteretention) } : {}), ...(summarywindow !== \"\" ? { summarywindow: Number(summarywindow) } : {}) } });\n status(\"The session interface options saved; the recall window, the note retention and the summary window take effect at once.\");\n}\n\n/** Renders the onboarding state and replays the walkthrough on demand. */\nasync function renderonboarding(): Promise<void> {\n if (!onboardingroot) return;\n try {\n const result = await request({ kind: \"surface\", onboarding: {} }) as { steps: Array<{ id: string; title: string; body: string; surface: string }>; state?: { stepscompleted: string[]; done: boolean } };\n onboardingroot.replaceChildren();\n const state = result.state;\n const line = document.createElement(\"p\");\n line.textContent = state === undefined ? \"The onboarding walkthrough never ran; it starts on the next popup open.\" : state.done ? `The walkthrough is done (${state.stepscompleted.length} steps); the replay restarts it on demand and writes no second consent event.` : `The walkthrough stands at ${state.stepscompleted.length} of ${result.steps.length} steps.`;\n onboardingroot.append(line);\n const list = document.createElement(\"ol\");\n list.className = \"audit\";\n for (const step of result.steps) list.append(Object.assign(document.createElement(\"li\"), { textContent: `${step.title} (${step.surface}): ${step.body}${state?.stepscompleted.includes(step.id) ? \" \u2014 done\" : \"\"}` }));\n onboardingroot.append(list);\n } catch (error) { onboardingroot.textContent = error instanceof Error ? error.message : String(error); }\n}\n\ndocument.querySelector<HTMLButtonElement>(\"#replayonboarding\")?.addEventListener(\"click\", () => { void (async () => { await request({ kind: \"surface\", onboarding: { replay: true } }); status(\"The onboarding walkthrough replays; it opens on the next popup open.\"); await renderonboarding(); })().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\ndocument.querySelector<HTMLButtonElement>(\"#palettesettings\")?.addEventListener(\"click\", () => { void savepalette().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\ndocument.querySelector<HTMLButtonElement>(\"#logstreamsettings\")?.addEventListener(\"click\", () => { void savelogstream().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\ndocument.querySelector<HTMLButtonElement>(\"#taskinputsettings\")?.addEventListener(\"click\", () => { void savetaskinput().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\ndocument.querySelector<HTMLButtonElement>(\"#diffsettings\")?.addEventListener(\"click\", () => { void savediff().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\ndocument.querySelector<HTMLButtonElement>(\"#sessionsettings\")?.addEventListener(\"click\", () => { void savesession().catch(error => status(error instanceof Error ? error.message : String(error), true)); });\n\n/** The optionspage sees settings changes through the single broadcast channel so two open pages never drift. */\nconst surfacechannel: BroadcastChannel | undefined = typeof BroadcastChannel === \"function\" ? new BroadcastChannel(\"devthinksurfaces\") : undefined;\nsurfacechannel?.addEventListener(\"message\", (event: MessageEvent) => { const frame = event.data as { channel?: string }; if (frame?.channel === \"settings\") { void load().catch(() => { /* a failing reload keeps the last loaded options */ }); } });\n\nvoid load();\nvoid renderonboarding();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|