@wenathlan/extension 1.1.11
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/LICENSE +674 -0
- package/README.md +84 -0
- package/dist/cli.js +25 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +7 -0
- package/dist/memory.d.ts +23 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/policy.d.ts +19 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/protocol.d.ts +6 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/extension/dist/background.js +297 -0
- package/extension/dist/background.js.map +7 -0
- package/extension/dist/manifest.json +26 -0
- package/extension/dist/pagebridge.js +65 -0
- package/extension/dist/pagebridge.js.map +7 -0
- package/extension/dist/popup.html +5 -0
- package/extension/dist/popup.js +67 -0
- package/extension/dist/popup.js.map +7 -0
- package/extension/dist/sidepanel.html +5 -0
- package/extension/dist/sidepanel.js +99 -0
- package/extension/dist/sidepanel.js.map +7 -0
- package/extension/dist/style.css +9 -0
- package/extension/manifest.json +26 -0
- package/package.json +62 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// extension/sidepanel.ts
|
|
2
|
+
var objective = document.querySelector("#objective");
|
|
3
|
+
var localbutton = document.querySelector("#localplan");
|
|
4
|
+
var remotebutton = document.querySelector("#remoteplan");
|
|
5
|
+
var diagnosticbutton = document.querySelector("#diagnostic");
|
|
6
|
+
var planroot = document.querySelector("#plan");
|
|
7
|
+
var auditroot = document.querySelector("#audit");
|
|
8
|
+
var diagnosticroot = document.querySelector("#diagnostics");
|
|
9
|
+
var statusnode = document.querySelector("#status");
|
|
10
|
+
function status(message, error = false) {
|
|
11
|
+
if (statusnode) {
|
|
12
|
+
statusnode.textContent = message;
|
|
13
|
+
statusnode.dataset.state = error ? "error" : "ready";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function request(message) {
|
|
17
|
+
const response = await chrome.runtime.sendMessage(message);
|
|
18
|
+
if (!response.ok) throw new Error(response.error);
|
|
19
|
+
return response.value;
|
|
20
|
+
}
|
|
21
|
+
function button(label, action, disabled = false) {
|
|
22
|
+
const element = document.createElement("button");
|
|
23
|
+
element.type = "button";
|
|
24
|
+
element.textContent = label;
|
|
25
|
+
element.disabled = disabled;
|
|
26
|
+
element.addEventListener("click", () => action().catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
27
|
+
return element;
|
|
28
|
+
}
|
|
29
|
+
function renderplan(plan) {
|
|
30
|
+
if (!planroot) return;
|
|
31
|
+
planroot.replaceChildren();
|
|
32
|
+
if (!plan) {
|
|
33
|
+
planroot.textContent = "Start a session, then request a local or endpoint plan. No task runs before review.";
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const title = document.createElement("h2");
|
|
37
|
+
title.textContent = `${plan.state}: ${plan.objective}`;
|
|
38
|
+
planroot.append(title);
|
|
39
|
+
const list = document.createElement("ol");
|
|
40
|
+
for (const step of plan.steps) {
|
|
41
|
+
const item = document.createElement("li");
|
|
42
|
+
item.textContent = `${step.risk} \u2014 ${step.summary}`;
|
|
43
|
+
if (plan.state === "approved") item.append(" ", button("Run this reviewed step", async () => {
|
|
44
|
+
const result = await request({ kind: "execute", stepid: step.id });
|
|
45
|
+
status(result.summary);
|
|
46
|
+
await refresh();
|
|
47
|
+
}));
|
|
48
|
+
list.append(item);
|
|
49
|
+
}
|
|
50
|
+
planroot.append(list);
|
|
51
|
+
if (plan.state === "pending") {
|
|
52
|
+
planroot.append(button("Approve reviewed plan", async () => {
|
|
53
|
+
await request({ kind: "approve" });
|
|
54
|
+
await refresh();
|
|
55
|
+
}), button("Reject plan", async () => {
|
|
56
|
+
await request({ kind: "reject" });
|
|
57
|
+
await refresh();
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function renderaudit(events) {
|
|
62
|
+
if (!auditroot) return;
|
|
63
|
+
auditroot.replaceChildren();
|
|
64
|
+
for (const event of events.slice(0, 12)) {
|
|
65
|
+
const item = document.createElement("li");
|
|
66
|
+
item.textContent = `${new Date(event.at).toLocaleTimeString()} \xB7 ${event.kind} \xB7 ${event.summary}`;
|
|
67
|
+
auditroot.append(item);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function renderdiagnostic(report) {
|
|
71
|
+
if (!diagnosticroot) return;
|
|
72
|
+
diagnosticroot.replaceChildren();
|
|
73
|
+
if (!report) {
|
|
74
|
+
diagnosticroot.textContent = "Run a local diagnostic after starting a session to record bridge and page-shape health.";
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const values = [`origin: ${report.origin}`, `title: ${report.title || "untitled"}`, `interactive elements: ${report.interactivecount}`, `forms: ${report.formcount}`, `page text length: ${report.textlength}`, `bridge available: ${report.bridgeavailable ? "yes" : "no"}`];
|
|
78
|
+
for (const value of values) {
|
|
79
|
+
const item = document.createElement("li");
|
|
80
|
+
item.textContent = value;
|
|
81
|
+
diagnosticroot.append(item);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function refresh() {
|
|
85
|
+
const context = await request({ kind: "context" });
|
|
86
|
+
renderplan(context.plan);
|
|
87
|
+
renderdiagnostic(context.diagnostic);
|
|
88
|
+
renderaudit(context.audit);
|
|
89
|
+
status(context.session ? "Active session is visible. The extension is waiting for review." : "No active browser session.");
|
|
90
|
+
}
|
|
91
|
+
async function create(kind) {
|
|
92
|
+
await request({ kind, objective: objective?.value ?? "" });
|
|
93
|
+
await refresh();
|
|
94
|
+
}
|
|
95
|
+
localbutton?.addEventListener("click", () => create("proposelocal").catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
96
|
+
remotebutton?.addEventListener("click", () => create("proposeremote").catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
97
|
+
diagnosticbutton?.addEventListener("click", () => request({ kind: "diagnostic" }).then(() => refresh()).catch((error) => status(error instanceof Error ? error.message : String(error), true)));
|
|
98
|
+
refresh().catch((error) => status(error instanceof Error ? error.message : String(error), true));
|
|
99
|
+
//# sourceMappingURL=sidepanel.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../sidepanel.ts"],
|
|
4
|
+
"sourcesContent": ["import type { agentplan, auditevent, diagnosticreport } from \"../types.js\";\n\nconst objective = document.querySelector<HTMLTextAreaElement>(\"#objective\");\nconst localbutton = document.querySelector<HTMLButtonElement>(\"#localplan\");\nconst remotebutton = document.querySelector<HTMLButtonElement>(\"#remoteplan\");\nconst diagnosticbutton = document.querySelector<HTMLButtonElement>(\"#diagnostic\");\nconst planroot = document.querySelector<HTMLElement>(\"#plan\");\nconst auditroot = document.querySelector<HTMLElement>(\"#audit\");\nconst diagnosticroot = document.querySelector<HTMLElement>(\"#diagnostics\");\nconst statusnode = document.querySelector<HTMLElement>(\"#status\");\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>, disabled = false): HTMLButtonElement { const element = document.createElement(\"button\"); element.type = \"button\"; element.textContent = label; element.disabled = disabled; element.addEventListener(\"click\", () => action().catch(error => status(error instanceof Error ? error.message : String(error), true))); return element; }\nfunction renderplan(plan?: agentplan): void {\n if (!planroot) return;\n planroot.replaceChildren();\n if (!plan) { planroot.textContent = \"Start a session, then request a local or endpoint plan. No task runs before review.\"; return; }\n const title = document.createElement(\"h2\"); title.textContent = `${plan.state}: ${plan.objective}`; planroot.append(title);\n const list = document.createElement(\"ol\");\n for (const step of plan.steps) { const item = document.createElement(\"li\"); item.textContent = `${step.risk} \u2014 ${step.summary}`; if (plan.state === \"approved\") item.append(\" \", button(\"Run this reviewed step\", async () => { const result = await request({ kind: \"execute\", stepid: step.id }) as { summary: string }; status(result.summary); await refresh(); })); list.append(item); }\n planroot.append(list);\n if (plan.state === \"pending\") { planroot.append(button(\"Approve reviewed plan\", async () => { await request({ kind: \"approve\" }); await refresh(); }), button(\"Reject plan\", async () => { await request({ kind: \"reject\" }); await refresh(); })); }\n}\nfunction renderaudit(events: auditevent[]): void { if (!auditroot) return; auditroot.replaceChildren(); for (const event of events.slice(0, 12)) { const item = document.createElement(\"li\"); item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 ${event.kind} \u00B7 ${event.summary}`; auditroot.append(item); } }\nfunction renderdiagnostic(report?: diagnosticreport): void { if (!diagnosticroot) return; diagnosticroot.replaceChildren(); if (!report) { diagnosticroot.textContent = \"Run a local diagnostic after starting a session to record bridge and page-shape health.\"; return; } const values = [`origin: ${report.origin}`, `title: ${report.title || \"untitled\"}`, `interactive elements: ${report.interactivecount}`, `forms: ${report.formcount}`, `page text length: ${report.textlength}`, `bridge available: ${report.bridgeavailable ? \"yes\" : \"no\"}`]; for (const value of values) { const item = document.createElement(\"li\"); item.textContent = value; diagnosticroot.append(item); } }\nasync function refresh(): Promise<void> { const context = await request({ kind: \"context\" }) as { plan?: agentplan; diagnostic?: diagnosticreport; audit: auditevent[]; session?: { id: string } }; renderplan(context.plan); renderdiagnostic(context.diagnostic); renderaudit(context.audit); status(context.session ? \"Active session is visible. The extension is waiting for review.\" : \"No active browser session.\"); }\nasync function create(kind: \"proposelocal\" | \"proposeremote\"): Promise<void> { await request({ kind, objective: objective?.value ?? \"\" }); await refresh(); }\nlocalbutton?.addEventListener(\"click\", () => create(\"proposelocal\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\nremotebutton?.addEventListener(\"click\", () => create(\"proposeremote\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\ndiagnosticbutton?.addEventListener(\"click\", () => request({ kind: \"diagnostic\" }).then(() => refresh()).catch(error => status(error instanceof Error ? error.message : String(error), true)));\nrefresh().catch(error => status(error instanceof Error ? error.message : String(error), true));\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
:root { color-scheme: dark; --base: #090d16; --panel: #11192a; --line: #26334b; --text: #eff6ff; --muted: #9aa8bd; --accent: #74e8c1; --danger: #ff7b8e; font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
|
|
2
|
+
* { box-sizing: border-box; }
|
|
3
|
+
body { margin: 0; background: radial-gradient(circle at top right, #193b4c 0, transparent 35%), var(--base); color: var(--text); min-width: 360px; }
|
|
4
|
+
main { padding: 20px; max-width: 460px; margin: auto; } main.wide { max-width: 680px; }
|
|
5
|
+
header { border-bottom: 1px solid var(--line); margin-bottom: 18px; } h1 { margin: 3px 0 8px; font-size: 25px; letter-spacing: -0.04em; } h2 { font-size: 15px; margin: 0 0 10px; } p { color: var(--muted); line-height: 1.5; } .eyebrow { color: var(--accent); font-size: 11px; font-weight: 800; letter-spacing: 0.14em; margin: 0; }
|
|
6
|
+
label { display: block; font-size: 12px; color: var(--muted); margin: 14px 0 6px; } input, textarea { width: 100%; color: var(--text); background: #0c1321; border: 1px solid var(--line); border-radius: 10px; padding: 11px; font: inherit; } textarea { resize: vertical; }
|
|
7
|
+
button { min-height: 40px; margin-top: 10px; border: 1px solid transparent; border-radius: 9px; padding: 0 12px; color: #06120f; background: var(--accent); font-weight: 750; cursor: pointer; } button:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid #8fb9ff; outline-offset: 2px; } button:disabled { cursor: not-allowed; opacity: .5; } button.secondary { background: transparent; color: var(--text); border-color: var(--line); } button.danger { background: transparent; color: var(--danger); border-color: color-mix(in srgb, var(--danger) 50%, transparent); }
|
|
8
|
+
.actions { display: flex; flex-wrap: wrap; gap: 8px; } .actions button { flex: 1 1 135px; } #status { min-height: 44px; border-left: 3px solid var(--accent); padding-left: 10px; font-size: 13px; } #status[data-state="error"] { border-color: var(--danger); color: #ffc2cc; }
|
|
9
|
+
section { margin-top: 20px; } .panel, .audit { margin: 0; border: 1px solid var(--line); background: color-mix(in srgb, var(--panel) 88%, transparent); border-radius: 12px; padding: 14px; } ol { padding-left: 24px; } li { color: var(--muted); line-height: 1.5; margin-bottom: 11px; } li button { margin-left: 7px; min-height: 32px; font-size: 12px; } .audit { list-style: none; padding-left: 14px; }
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "Devthink",
|
|
4
|
+
"version": "1.1.11",
|
|
5
|
+
"description": "A consent-first bridge for reviewed browser-agent tasks.",
|
|
6
|
+
"permissions": [
|
|
7
|
+
"activeTab",
|
|
8
|
+
"storage",
|
|
9
|
+
"scripting",
|
|
10
|
+
"sidePanel"
|
|
11
|
+
],
|
|
12
|
+
"optional_host_permissions": [
|
|
13
|
+
"https://*/*"
|
|
14
|
+
],
|
|
15
|
+
"background": {
|
|
16
|
+
"service_worker": "background.js",
|
|
17
|
+
"type": "module"
|
|
18
|
+
},
|
|
19
|
+
"action": {
|
|
20
|
+
"default_title": "Devthink",
|
|
21
|
+
"default_popup": "popup.html"
|
|
22
|
+
},
|
|
23
|
+
"side_panel": {
|
|
24
|
+
"default_path": "sidepanel.html"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wenathlan/extension",
|
|
3
|
+
"version": "1.1.11",
|
|
4
|
+
"description": "Consent-first browser agent bridge and Manifest V3 extension.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "GPL-3.0-only",
|
|
7
|
+
"author": "Nathlan Bros <263045985+wenathlan@users.noreply.github.com>",
|
|
8
|
+
"homepage": "https://github.com/wenathlan/extension#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/wenathlan/extension.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/wenathlan/extension/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"browser-extension",
|
|
18
|
+
"agent",
|
|
19
|
+
"automation",
|
|
20
|
+
"consent",
|
|
21
|
+
"chromium"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"bin": {
|
|
29
|
+
"devthink": "./dist/cli.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"extension/dist",
|
|
34
|
+
"extension/manifest.json",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "node tests/build.mjs",
|
|
40
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"sync:metadata": "node tests/release.mjs sync",
|
|
43
|
+
"check:metadata": "node tests/release.mjs check",
|
|
44
|
+
"sync:maintenance": "node tests/maintain.mjs sync",
|
|
45
|
+
"check:maintenance": "node tests/maintain.mjs check",
|
|
46
|
+
"dependency:updates": "node tests/dependencyupdates.mjs sync",
|
|
47
|
+
"workflow:updates": "node tests/workflowupdates.mjs sync",
|
|
48
|
+
"notes:release": "node tests/release.mjs notes",
|
|
49
|
+
"validate:workflow": "node tests/workflowcheck.mjs && node tests/npmgate.mjs",
|
|
50
|
+
"validate": "pnpm check:metadata && pnpm check && pnpm test && pnpm build && node dist/cli.js manifest && node tests/packageextension.mjs && pnpm validate:workflow",
|
|
51
|
+
"package": "pnpm build && npm pack --dry-run"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/chrome": "^0.0.306",
|
|
55
|
+
"@types/node": "^24.7.0",
|
|
56
|
+
"esbuild": "^0.25.11",
|
|
57
|
+
"typescript": "^5.9.3",
|
|
58
|
+
"vitest": "^2.1.4",
|
|
59
|
+
"yaml": "^2.9.0"
|
|
60
|
+
},
|
|
61
|
+
"packageManager": "pnpm@11.24.0"
|
|
62
|
+
}
|