@wenathlan/extension 1.1.62 → 1.1.63

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.
@@ -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.62",
5
+ "version": "1.1.63",
6
6
  "description": "A consent-first bridge for reviewed browser-agent tasks.",
7
7
  "permissions": [
8
8
  "activeTab",
@@ -74,6 +74,10 @@ chrome.runtime.onMessage.addListener((message, _sender, sendresponse) => {
74
74
  void runparse(message.request).then((answer) => sendresponse({ ok: answer.ok, result: answer.result, summary: answer.summary }));
75
75
  return true;
76
76
  }
77
+ if (message.action === "summary") {
78
+ 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}` }));
79
+ return true;
80
+ }
77
81
  if (message.action === "sandboxrender") {
78
82
  void runrender(message.render).then((answer) => sendresponse({ ok: answer.ok, text: answer.text, summary: answer.summary }));
79
83
  return true;
@@ -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 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 | 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 === \"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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",
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": "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",
6
6
  "names": ["worker"]
7
7
  }