@hy-sde-org/dsh-browser 0.1.1-rc.2
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 +37 -0
- package/README.md +33 -0
- package/cordis.patch.yml +21 -0
- package/dist/aria-bundle.d.ts +9 -0
- package/dist/aria-bundle.d.ts.map +1 -0
- package/dist/aria-bundle.js +16 -0
- package/dist/aria-bundle.js.map +1 -0
- package/dist/aria.d.ts +45 -0
- package/dist/aria.d.ts.map +1 -0
- package/dist/aria.js +79 -0
- package/dist/aria.js.map +1 -0
- package/dist/assets/background.js.txt +242 -0
- package/dist/assets/manifest.json.txt +14 -0
- package/dist/assets/options.html.txt +53 -0
- package/dist/assets/options.js.txt +23 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/invariant.d.ts +16 -0
- package/dist/invariant.d.ts.map +1 -0
- package/dist/invariant.js +22 -0
- package/dist/invariant.js.map +1 -0
- package/dist/relay/bridge.d.ts +36 -0
- package/dist/relay/bridge.d.ts.map +1 -0
- package/dist/relay/bridge.js +860 -0
- package/dist/relay/bridge.js.map +1 -0
- package/dist/relay/index.d.ts +16 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/index.js +15 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/relay/kind.d.ts +30 -0
- package/dist/relay/kind.d.ts.map +1 -0
- package/dist/relay/kind.js +33 -0
- package/dist/relay/kind.js.map +1 -0
- package/dist/relay/protocol.d.ts +101 -0
- package/dist/relay/protocol.d.ts.map +1 -0
- package/dist/relay/protocol.js +12 -0
- package/dist/relay/protocol.js.map +1 -0
- package/dist/relay/server.d.ts +44 -0
- package/dist/relay/server.d.ts.map +1 -0
- package/dist/relay/server.js +173 -0
- package/dist/relay/server.js.map +1 -0
- package/dist/service.d.ts +157 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +291 -0
- package/dist/service.js.map +1 -0
- package/dist/stealth-scripts.d.ts +11 -0
- package/dist/stealth-scripts.d.ts.map +1 -0
- package/dist/stealth-scripts.js +2010 -0
- package/dist/stealth-scripts.js.map +1 -0
- package/dist/stealth.d.ts +62 -0
- package/dist/stealth.d.ts.map +1 -0
- package/dist/stealth.js +194 -0
- package/dist/stealth.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/examples/agent-preset/agent.cordis.yml +19 -0
- package/examples/agent-preset/preset.yml +3 -0
- package/package.json +99 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hy-sde
|
|
4
|
+
|
|
5
|
+
This repository is a port of the oh-my-pi memory surface (retain / recall /
|
|
6
|
+
reflect / memory_edit / learn and the durable project-scoped local memory
|
|
7
|
+
backend) onto the DeepSeek Harness `ctx.memory` service contract — see
|
|
8
|
+
port_omp.md item 4 in the hy-sde fork. The ported portions are distributed
|
|
9
|
+
under the same MIT license with their original copyright held by their
|
|
10
|
+
respective authors:
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2025 Mario Zechner
|
|
13
|
+
Copyright (c) 2025-2026 Can Bölük
|
|
14
|
+
|
|
15
|
+
See THIRD-PARTY-NOTICES.md for full provenance per module.
|
|
16
|
+
|
|
17
|
+
Parts of this repository are derived from DeepSeek Haarness
|
|
18
|
+
(https://github.com/deepseek-ai/deepseek-harness), MIT License,
|
|
19
|
+
Copyright (c) 2026 DeepSeek.
|
|
20
|
+
|
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
23
|
+
in the Software without restriction, including without limitation the rights
|
|
24
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
26
|
+
furnished to do so, subject to the following conditions:
|
|
27
|
+
|
|
28
|
+
The above copyright notice and this permission notice shall be included in all
|
|
29
|
+
copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
34
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
35
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
36
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
37
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @hy-sde-org/dsh-browser
|
|
2
|
+
|
|
3
|
+
The host `ctx.browser` service for the agentic browser tool (ported from omp / oh-my-pi): it owns real browser connections over Chrome DevTools Protocol through [playwright-core CDP](https://playwright.dev/docs/api/class-browsertype#browser-type-connect-over-cdp), with three backends — **launch** (stealth-patched browser binary), **attach** (existing CDP endpoint via `cdp_url`), and **relay** (the user's own Chrome tabs through an in-process relay server + companion MV3 extension). Intended to be consumed by [`@hy-sde-org/dsh-tool-browser`](../tool-browser/README.md), never by the model directly. A standalone plugin — no upstream harness changes required; installs on official DeepSeek Harness releases (`0.1.1-rc.2` and later).
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Registers one host service on the composition (`ctx.browser`). The surface:
|
|
8
|
+
|
|
9
|
+
- **Backends** — `resolveKind` maps a tool request to `launch` / `attach` / `relay`, mirroring omp's kind resolution (`app.path` → spawn, `app.cdp_url` → attach, `app.relay` / `DSH_BROWSER_RELAY` → relay); `ensureRelay` starts the in-process relay server (default `http://127.0.0.1:9224`, ephemeral port fallback).
|
|
10
|
+
- **Tabs** — `open` navigates a named tab (one tab per name, one browser connection per cwd+kind); `run` evaluates JS in a tab; `observe` returns title/url/size + an ARIA snapshot with `[ref=eN]` ids; `click`/`type` address elements by ARIA ref or CSS selector; `screenshot` writes a PNG; `close` closes tabs and, with `kill`, spawned browsers.
|
|
11
|
+
- **Stealth** — the 14 omp-puppeteer init scripts run in every launched page (`src/stealth-scripts.ts`, generated), the machine-tell launch flags are suppressed, and a spoofed user-agent + client-hints override is applied on the browser CDP session.
|
|
12
|
+
|
|
13
|
+
The ARIA snapshot is produced by the bundled Playwright ARIA-snapshot sources (Apache-2.0, Microsoft) vendored as `src/aria-bundle.ts` — the same generated bundle omp uses — so every snapshot carries actionable `[ref=eN]` ids that stay valid until the next snapshot.
|
|
14
|
+
|
|
15
|
+
## Backends
|
|
16
|
+
|
|
17
|
+
| kind | resolution | browser |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| `launch` | `app.path` (or `browserPath` config) | `chromium.launch({ executablePath, headless, args: STEALTH_LAUNCH_ARGS, ignoreDefaultArgs })` |
|
|
20
|
+
| `attach` | `app.cdp_url` | `chromium.connectOverCDP(cdpUrl)` — any real Chrome family endpoint |
|
|
21
|
+
| `relay` | `app.relay` / `DSH_BROWSER_RELAY=1` | `chromium.connectOverCDP(relay)` — the relay impersonates Chrome's CDP discovery |
|
|
22
|
+
|
|
23
|
+
The relay (`src/relay/server.ts`, `bridge.ts`, a port of omp's) binds loopback, serves `GET /json/version` (503 until the extension connects), `GET /json`, `WS /cdp` (downstream CDP clients), `WS /ext` (the extension, token-gated when configured), and `GET /ext-assets/*` so the extension can be sideloaded from `chrome://extensions` → Load unpacked. The bridge multiplexes every downstream CDP connection over the extension's one `chrome.debugger` attachment per tab with minted session ids — the same design as `omp browser-relay` (MIT).
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
- `browserPath` — default executable for `launch` (optional; Playwright resolves one).
|
|
28
|
+
- `headless` — default headless (true).
|
|
29
|
+
- `viewport` — launch viewport (default 1365×768 @ 1.25).
|
|
30
|
+
- `relayUrl` / `relayToken` — relay endpoint and optional extension token.
|
|
31
|
+
- `timeoutMs` — default navigation timeout (30000).
|
|
32
|
+
|
|
33
|
+
The service is host-plane, holds no durable state, and is disposed with its owning context (closes its browsers and stops the relay).
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @hy-sde-org/dsh-browser — install surface for the agentic browser service.
|
|
2
|
+
#
|
|
3
|
+
# The `ctx.browser` SERVICE is host-plane: it owns real browser connections
|
|
4
|
+
# (launch / CDP-attach / relay) that must be shared across sessions within one
|
|
5
|
+
# process, so a single instance across sessions is correct — this bundle
|
|
6
|
+
# inserts one row into the profile's base composition. The model-facing
|
|
7
|
+
# `browser` tool lives in @hy-sde-org/dsh-tool-browser and mounts at the AGENT
|
|
8
|
+
# plane from a user agent preset (it resolves this host instance) — see
|
|
9
|
+
# examples/agent-preset/ in the package for the ready-to-copy preset.
|
|
10
|
+
#
|
|
11
|
+
# `insert` is the stock harness patch form for rows that don't exist in the
|
|
12
|
+
# deployment's composition (a plain `id:`+`name:` entry is a modification of
|
|
13
|
+
# an existing row). This patch INSERTS a new row only — it touches no existing
|
|
14
|
+
# row, so `dsh plugin add @hy-sde-org/dsh-browser` never breaks boot on a stock
|
|
15
|
+
# DeepSeek Harness (0.1.1-rc.2 and later). Without the preset row you get the
|
|
16
|
+
# service but no tools; without this row the preset tools fail loudly
|
|
17
|
+
# ("browser: no browser service") the first time they run.
|
|
18
|
+
|
|
19
|
+
- insert:
|
|
20
|
+
- id: browser
|
|
21
|
+
name: '@hy-sde-org/dsh-browser'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright (Microsoft, Apache-2.0) ARIA-snapshot sources bundled to one CJS
|
|
3
|
+
* string by oh-my-pi; the `[ref=eN]` anchors are written straight into the page
|
|
4
|
+
* and resolve through `resolveAriaRef`. Generated — regenerate from omp
|
|
5
|
+
* `packages/coding-agent/src/tools/browser/aria/aria-snapshot.bundle.txt`.
|
|
6
|
+
*/
|
|
7
|
+
/** The bundled CJS source, evaluated in the page's main world. */
|
|
8
|
+
export declare const ariaSnapshotBundle: string;
|
|
9
|
+
//# sourceMappingURL=aria-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria-bundle.d.ts","sourceRoot":"","sources":["../src/aria-bundle.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,EAAE,MAOhC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright (Microsoft, Apache-2.0) ARIA-snapshot sources bundled to one CJS
|
|
3
|
+
* string by oh-my-pi; the `[ref=eN]` anchors are written straight into the page
|
|
4
|
+
* and resolve through `resolveAriaRef`. Generated — regenerate from omp
|
|
5
|
+
* `packages/coding-agent/src/tools/browser/aria/aria-snapshot.bundle.txt`.
|
|
6
|
+
*/
|
|
7
|
+
/** The bundled CJS source, evaluated in the page's main world. */
|
|
8
|
+
export const ariaSnapshotBundle = `// @generated by scripts/generate-aria-snapshot.ts from Playwright v1.61.0
|
|
9
|
+
// Bundled from Playwright's injected ARIA-snapshot sources (Apache-2.0, (c) Microsoft).
|
|
10
|
+
// Do not edit by hand. Regenerate with: bun scripts/generate-aria-snapshot.ts
|
|
11
|
+
var{defineProperty:M_,getOwnPropertyNames:WX,getOwnPropertyDescriptor:LX}=Object,zX=Object.prototype.hasOwnProperty;function MX(_){return this[_]}var jX=(_)=>{var J=(k_??=new WeakMap).get(_),Z;if(J)return J;if(J=M_({},"__esModule",{value:!0}),_&&typeof _==="object"||typeof _==="function"){for(var $ of WX(_))if(!zX.call(J,$))M_(J,$,{get:MX.bind(_,$),enumerable:!(Z=LX(_,$))||Z.enumerable})}return k_.set(_,J),J},k_;var FX=(_)=>_;function BX(_,J){this[_]=FX.bind(null,J)}var IX=(_,J)=>{for(var Z in J)M_(_,Z,{get:J[Z],enumerable:!0,configurable:!0,set:BX.bind(J,Z)})};var YZ={};IX(YZ,{resolveAriaRef:()=>$Z,ariaSnapshot:()=>ZZ});module.exports=jX(YZ);function h_(_,J){if(_.role!==J.role||_.name!==J.name)return!1;if(!VX(_,J)||d(_)!==d(J))return!1;let Z=Object.keys(_.props),$=Object.keys(J.props);return Z.length===$.length&&Z.every((X)=>_.props[X]===J.props[X])}function d(_){return _.box.cursor==="pointer"}function VX(_,J){return _.active===J.active&&_.checked===J.checked&&_.disabled===J.disabled&&_.expanded===J.expanded&&_.invalid===J.invalid&&_.selected===J.selected&&_.level===J.level&&_.pressed===J.pressed}var u_;function j_(_){let J=u_?.get(_);if(J===void 0)J=_.replace(/[\\u200b\\u00ad]/g,"").trim().replace(/\\s+/g," "),u_?.set(_,J);return J}function F_(_){return _.replace(/[.*+?^\${}()|[\\]\\\\]/g,"\\\\$&")}function p_(_,J){let Z=_.length,$=J.length,X=0,Q=0,U=Array(Z+1).fill(null).map(()=>Array($+1).fill(0));for(let W=1;W<=Z;W++)for(let Y=1;Y<=$;Y++)if(_[W-1]===J[Y-1]){if(U[W][Y]=U[W-1][Y-1]+1,U[W][Y]>X)X=U[W][Y],Q=W}return _.slice(Q-X,Q)}var HZ=new RegExp("([\\\\u001B\\\\u009B][[\\\\]()#?]*(?:(?:(?:[a-zA-Z\\\\d]*(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)|(?:(?:\\\\d{0,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~])))","g");function c_(_){if(!m_(_))return _;return"'"+_.replace(/'/g,"''")+"'"}function e(_){if(!m_(_))return _;return'"'+_.replace(/[\\\\"\\x00-\\x1f\\x7f-\\x9f]/g,(J)=>{switch(J){case"\\\\":return"\\\\\\\\";case'"':return"\\\\\\"";case"\\b":return"\\\\b";case"\\f":return"\\\\f";case\`
|
|
12
|
+
\`:return"\\\\n";case"\\r":return"\\\\r";case"\\t":return"\\\\t";default:return"\\\\x"+J.charCodeAt(0).toString(16).padStart(2,"0")}})+'"'}function m_(_){if(_.length===0)return!0;if(/^\\s|\\s$/.test(_))return!0;if(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/.test(_))return!0;if(/^-/.test(_))return!0;if(/[\\n:](\\s|$)/.test(_))return!0;if(/\\s#/.test(_))return!0;if(/[\\n\\r]/.test(_))return!0;if(/^[&*\\],?!>|@"'#%]/.test(_))return!0;if(/[{}\`]/.test(_))return!0;if(/^\\[/.test(_))return!0;if(!isNaN(Number(_))||["y","n","yes","no","true","false","on","off","null"].includes(_.toLowerCase()))return!0;return!1}var DX={};function h(_){if(_.parentElement)return _.parentElement;if(!_.parentNode)return;if(_.parentNode.nodeType===11&&_.parentNode.host)return _.parentNode.host}function d_(_){let J=_;while(J.parentNode)J=J.parentNode;if(J.nodeType===11||J.nodeType===9)return J}function OX(_){while(_.parentElement)_=_.parentElement;return h(_)}function s(_,J,Z){while(_){let $=_.closest(J);if(Z&&$!==Z&&$?.contains(Z))return;if($)return $;_=OX(_)}}function b(_,J){let Z=J==="::before"?R_:J==="::after"?D_:V_;if(Z&&Z.has(_))return Z.get(_);let $=_.ownerDocument&&_.ownerDocument.defaultView?_.ownerDocument.defaultView.getComputedStyle(_,J):void 0;return Z?.set(_,$),$}function B_(_,J){if(J=J??b(_),!J)return!0;if(Element.prototype.checkVisibility&&DX.browserNameForWorkarounds!=="webkit"){if(!_.checkVisibility())return!1}else{let Z=_.closest("details,summary");if(Z!==_&&Z?.nodeName==="DETAILS"&&!Z.open)return!1}if(J.visibility!=="visible")return!1;return!0}function i(_){let J=b(_);if(!J)return{visible:!0,inline:!1};let Z=J.cursor;if(J.display==="contents"){for(let X=_.firstChild;X;X=X.nextSibling){if(X.nodeType===1&&__(X))return{visible:!0,inline:!1,cursor:Z};if(X.nodeType===3&&I_(X))return{visible:!0,inline:!0,cursor:Z}}return{visible:!1,inline:!1,cursor:Z}}if(!B_(_,J))return{cursor:Z,visible:!1,inline:!1};let $=_.getBoundingClientRect();return{cursor:Z,visible:$.width>0&&$.height>0,inline:J.display==="inline"}}function __(_){return i(_).visible}function I_(_){let J=_.ownerDocument.createRange();J.selectNode(_);let Z=J.getBoundingClientRect();return Z.width>0&&Z.height>0}function V(_){let J=_.tagName;if(typeof J==="string")return J.toUpperCase();if(_ instanceof HTMLFormElement)return"FORM";return _.tagName.toUpperCase()}var V_,R_,D_,s_=0;function i_(){++s_,V_??=new Map,R_??=new Map,D_??=new Map}function l_(){if(!--s_)V_=void 0,R_=void 0,D_=void 0}var R=function(_,J,Z){return _>=J&&_<=Z};function A(_){return R(_,48,57)}function r_(_){return A(_)||R(_,65,70)||R(_,97,102)}function wX(_){return R(_,65,90)}function AX(_){return R(_,97,122)}function EX(_){return wX(_)||AX(_)}function PX(_){return _>=128}function J_(_){return EX(_)||PX(_)||_===95}function a_(_){return J_(_)||A(_)||_===45}function fX(_){return R(_,0,8)||_===11||R(_,14,31)||_===127}function u(_){return _===10}function T(_){return u(_)||_===9||_===32}var CX=1114111;class Z_ extends Error{constructor(_){super(_);this.name="InvalidCharacterError"}}function bX(_){let J=[];for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===13&&_.charCodeAt(Z+1)===10)$=10,Z++;if($===13||$===12)$=10;if($===0)$=65533;if(R($,55296,56319)&&R(_.charCodeAt(Z+1),56320,57343)){let X=$-55296,Q=_.charCodeAt(Z+1)-56320;$=Math.pow(2,16)+X*Math.pow(2,10)+Q,Z++}J.push($)}return J}function D(_){if(_<=65535)return String.fromCharCode(_);_-=Math.pow(2,16);let J=Math.floor(_/Math.pow(2,10))+55296,Z=_%Math.pow(2,10)+56320;return String.fromCharCode(J)+String.fromCharCode(Z)}function n_(_){let J=bX(_),Z=-1,$=[],X,Q=0,U=0,W=0,Y=function(){Q+=1,W=U,U=0},K={line:Q,column:U},z=function(G){if(G>=J.length)return-1;return J[G]},q=function(G){if(G===void 0)G=1;if(G>3)throw"Spec Error: no more than three codepoints of lookahead.";return z(Z+G)},L=function(G){if(G===void 0)G=1;if(Z+=G,X=z(Z),u(X))Y();else U+=G;return!0},I=function(){if(Z-=1,u(X))Q-=1,U=W;else U-=1;return K.line=Q,K.column=U,!0},H=function(G){if(G===void 0)G=X;return G===-1},F=function(){},j=function(){},w=function(){if(E(),L(),T(X)){while(T(q()))L();return new $_}else if(X===34)return K_();else if(X===35)if(a_(q())||k(q(1),q(2))){let G=new jJ("");if(o(q(1),q(2),q(3)))G.type="id";return G.value=t(),G}else return new O(X);else if(X===36)if(q()===61)return L(),new KJ;else return new O(X);else if(X===39)return K_();else if(X===40)return new HJ;else if(X===41)return new Y_;else if(X===42)if(q()===61)return L(),new WJ;else return new O(X);else if(X===43)if(W_())return I(),S();else return new O(X);else if(X===44)return new XJ;else if(X===45)if(W_())return I(),S();else if(q(1)===45&&q(2)===62)return L(2),new e_;else if(QX())return I(),m();else return new O(X);else if(X===46)if(W_())return I(),S();else return new O(X);else if(X===58)return new _J;else if(X===59)return new JJ;else if(X===60)if(q(1)===33&&q(2)===45&&q(3)===45)return L(3),new t_;else return new O(X);else if(X===64)if(o(q(1),q(2),q(3)))return new MJ(t());else return new O(X);else if(X===91)return new YJ;else if(X===92)if(n())return I(),m();else return j(),new O(X);else if(X===93)return new QJ;else if(X===94)if(q()===61)return L(),new UJ;else return new O(X);else if(X===123)return new ZJ;else if(X===124)if(q()===61)return L(),new GJ;else if(q()===124)return L(),new LJ;else return new O(X);else if(X===125)return new $J;else if(X===126)if(q()===61)return L(),new qJ;else return new O(X);else if(A(X))return I(),S();else if(J_(X))return I(),m();else if(H())return new zJ;else return new O(X)},E=function(){while(q(1)===47&&q(2)===42){L(2);while(!0)if(L(),X===42&&q()===47){L();break}else if(H()){j();return}}},S=function(){let G=qX();if(o(q(1),q(2),q(3))){let M=new VJ;return M.value=G.value,M.repr=G.repr,M.type=G.type,M.unit=t(),M}else if(q()===37){L();let M=new IJ;return M.value=G.value,M.repr=G.repr,M}else{let M=new BJ;return M.value=G.value,M.repr=G.repr,M.type=G.type,M}},m=function(){let G=t();if(G.toLowerCase()==="url"&&q()===40){L();while(T(q(1))&&T(q(2)))L();if(q()===34||q()===39)return new p(G);else if(T(q())&&(q(2)===34||q(2)===39))return new p(G);else return a()}else if(q()===40)return L(),new p(G);else return new Q_(G)},K_=function(G){if(G===void 0)G=X;let M="";while(L())if(X===G||H())return new H_(M);else if(u(X))return j(),I(),new o_;else if(X===92)if(H(q()))F();else if(u(q()))L();else M+=D(C());else M+=D(X);throw Error("Internal error")},a=function(){let G=new FJ("");while(T(q()))L();if(H(q()))return G;while(L())if(X===41||H())return G;else if(T(X)){while(T(q()))L();if(q()===41||H(q()))return L(),G;else return L_(),new X_}else if(X===34||X===39||X===40||fX(X))return j(),L_(),new X_;else if(X===92)if(n())G.value+=D(C());else return j(),L_(),new X_;else G.value+=D(X);throw Error("Internal error")},C=function(){if(L(),r_(X)){let G=[X];for(let P=0;P<5;P++)if(r_(q()))L(),G.push(X);else break;if(T(q()))L();let M=parseInt(G.map(function(P){return String.fromCharCode(P)}).join(""),16);if(M>CX)M=65533;return M}else if(H())return 65533;else return X},k=function(G,M){if(G!==92)return!1;if(u(M))return!1;return!0},n=function(){return k(X,q())},o=function(G,M,P){if(G===45)return J_(M)||M===45||k(M,P);else if(J_(G))return!0;else if(G===92)return k(G,M);else return!1},QX=function(){return o(X,q(1),q(2))},HX=function(G,M,P){if(G===43||G===45){if(A(M))return!0;if(M===46&&A(P))return!0;return!1}else if(G===46){if(A(M))return!0;return!1}else if(A(G))return!0;else return!1},W_=function(){return HX(X,q(1),q(2))},t=function(){let G="";while(L())if(a_(X))G+=D(X);else if(n())G+=D(C());else return I(),G;throw Error("Internal parse error")},qX=function(){let G="",M="integer";if(q()===43||q()===45)L(),G+=D(X);while(A(q()))L(),G+=D(X);if(q(1)===46&&A(q(2))){L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}let P=q(1),z_=q(2),UX=q(3);if((P===69||P===101)&&A(z_)){L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}else if((P===69||P===101)&&(z_===43||z_===45)&&A(UX)){L(),G+=D(X),L(),G+=D(X),L(),G+=D(X),M="number";while(A(q()))L(),G+=D(X)}let KX=GX(G);return{type:M,value:KX,repr:G}},GX=function(G){return+G},L_=function(){while(L())if(X===41||H())return;else if(n())C(),F();else F()},N_=0;while(!H(q()))if($.push(w()),N_++,N_>J.length*2)throw Error("I'm infinite-looping!");return $}class B{tokenType="";value;toJSON(){return{token:this.tokenType}}toString(){return this.tokenType}toSource(){return""+this}}class o_ extends B{tokenType="BADSTRING"}class X_ extends B{tokenType="BADURL"}class $_ extends B{tokenType="WHITESPACE";toString(){return"WS"}toSource(){return" "}}class t_ extends B{tokenType="CDO";toSource(){return"<!--"}}class e_ extends B{tokenType="CDC";toSource(){return"-->"}}class _J extends B{tokenType=":"}class JJ extends B{tokenType=";"}class XJ extends B{tokenType=","}class g extends B{value="";mirror=""}class ZJ extends g{tokenType="{";constructor(){super();this.value="{",this.mirror="}"}}class $J extends g{tokenType="}";constructor(){super();this.value="}",this.mirror="{"}}class YJ extends g{tokenType="[";constructor(){super();this.value="[",this.mirror="]"}}class QJ extends g{tokenType="]";constructor(){super();this.value="]",this.mirror="["}}class HJ extends g{tokenType="(";constructor(){super();this.value="(",this.mirror=")"}}class Y_ extends g{tokenType=")";constructor(){super();this.value=")",this.mirror="("}}class qJ extends B{tokenType="~="}class GJ extends B{tokenType="|="}class UJ extends B{tokenType="^="}class KJ extends B{tokenType="$="}class WJ extends B{tokenType="*="}class LJ extends B{tokenType="||"}class zJ extends B{tokenType="EOF";toSource(){return""}}class O extends B{tokenType="DELIM";value="";constructor(_){super();this.value=D(_)}toString(){return"DELIM("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_}toSource(){if(this.value==="\\\\")return"\\\\\\n";else return this.value}}class N extends B{value="";ASCIIMatch(_){return this.value.toLowerCase()===_.toLowerCase()}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_}}class Q_ extends N{constructor(_){super();this.value=_}tokenType="IDENT";toString(){return"IDENT("+this.value+")"}toSource(){return l(this.value)}}class p extends N{tokenType="FUNCTION";mirror;constructor(_){super();this.value=_,this.mirror=")"}toString(){return"FUNCTION("+this.value+")"}toSource(){return l(this.value)+"("}}class MJ extends N{tokenType="AT-KEYWORD";constructor(_){super();this.value=_}toString(){return"AT("+this.value+")"}toSource(){return"@"+l(this.value)}}class jJ extends N{tokenType="HASH";type;constructor(_){super();this.value=_,this.type="unrestricted"}toString(){return"HASH("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.type=this.type,_}toSource(){if(this.type==="id")return"#"+l(this.value);else return"#"+yX(this.value)}}class H_ extends N{tokenType="STRING";constructor(_){super();this.value=_}toString(){return'"'+RJ(this.value)+'"'}}class FJ extends N{tokenType="URL";constructor(_){super();this.value=_}toString(){return"URL("+this.value+")"}toSource(){return'url("'+RJ(this.value)+'")'}}class BJ extends B{tokenType="NUMBER";type;repr;constructor(){super();this.type="integer",this.repr=""}toString(){if(this.type==="integer")return"INT("+this.value+")";return"NUMBER("+this.value+")"}toJSON(){let _=super.toJSON();return _.value=this.value,_.type=this.type,_.repr=this.repr,_}toSource(){return this.repr}}class IJ extends B{tokenType="PERCENTAGE";repr;constructor(){super();this.repr=""}toString(){return"PERCENTAGE("+this.value+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.repr=this.repr,_}toSource(){return this.repr+"%"}}class VJ extends B{tokenType="DIMENSION";type;repr;unit;constructor(){super();this.type="integer",this.repr="",this.unit=""}toString(){return"DIM("+this.value+","+this.unit+")"}toJSON(){let _=this.constructor.prototype.constructor.prototype.toJSON.call(this);return _.value=this.value,_.type=this.type,_.repr=this.repr,_.unit=this.unit,_}toSource(){let _=this.repr,J=l(this.unit);if(J[0].toLowerCase()==="e"&&(J[1]==="-"||R(J.charCodeAt(1),48,57)))J="\\\\65 "+J.slice(1,J.length);return _+J}}function l(_){_=""+_;let J="",Z=_.charCodeAt(0);for(let $=0;$<_.length;$++){let X=_.charCodeAt($);if(X===0)throw new Z_("Invalid character: the input contains U+0000.");if(R(X,1,31)||X===127||$===0&&R(X,48,57)||$===1&&R(X,48,57)&&Z===45)J+="\\\\"+X.toString(16)+" ";else if(X>=128||X===45||X===95||R(X,48,57)||R(X,65,90)||R(X,97,122))J+=_[$];else J+="\\\\"+_[$]}return J}function yX(_){_=""+_;let J="";for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===0)throw new Z_("Invalid character: the input contains U+0000.");if($>=128||$===45||$===95||R($,48,57)||R($,65,90)||R($,97,122))J+=_[Z];else J+="\\\\"+$.toString(16)+" "}return J}function RJ(_){_=""+_;let J="";for(let Z=0;Z<_.length;Z++){let $=_.charCodeAt(Z);if($===0)throw new Z_("Invalid character: the input contains U+0000.");if(R($,1,31)||$===127)J+="\\\\"+$.toString(16)+" ";else if($===34||$===92)J+="\\\\"+_[Z];else J+=_[Z]}return J}function DJ(_){return _.hasAttribute("aria-label")||_.hasAttribute("aria-labelledby")}var OJ="article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]",TX=[["aria-atomic",void 0],["aria-busy",void 0],["aria-controls",void 0],["aria-current",void 0],["aria-describedby",void 0],["aria-details",void 0],["aria-dropeffect",void 0],["aria-flowto",void 0],["aria-grabbed",void 0],["aria-hidden",void 0],["aria-keyshortcuts",void 0],["aria-label",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-labelledby",["caption","code","deletion","emphasis","generic","insertion","paragraph","presentation","strong","subscript","superscript"]],["aria-live",void 0],["aria-owns",void 0],["aria-relevant",void 0],["aria-roledescription",["generic"]]];function fJ(_,J){return TX.some(([Z,$])=>{return!$?.includes(J||"")&&_.hasAttribute(Z)})}function CJ(_){return!Number.isNaN(Number(String(_.getAttribute("tabindex"))))}function xX(_){return!mJ(_)&&(vX(_)||CJ(_))}function vX(_){let J=V(_);if(["BUTTON","DETAILS","SELECT","TEXTAREA"].includes(J))return!0;if(J==="A"||J==="AREA")return _.hasAttribute("href");if(J==="INPUT")return!_.hidden;return!1}var gX={A:(_)=>{return _.hasAttribute("href")?"link":null},AREA:(_)=>{return _.hasAttribute("href")?"link":null},ARTICLE:()=>"article",ASIDE:()=>"complementary",BLOCKQUOTE:()=>"blockquote",BUTTON:()=>"button",CAPTION:()=>"caption",CODE:()=>"code",DATALIST:()=>"listbox",DD:()=>"definition",DEL:()=>"deletion",DETAILS:()=>"group",DFN:()=>"term",DIALOG:()=>"dialog",DT:()=>"term",EM:()=>"emphasis",FIELDSET:()=>"group",FIGURE:()=>"figure",FOOTER:(_)=>s(_,OJ)?null:"contentinfo",FORM:(_)=>DJ(_)?"form":null,H1:()=>"heading",H2:()=>"heading",H3:()=>"heading",H4:()=>"heading",H5:()=>"heading",H6:()=>"heading",HEADER:(_)=>s(_,OJ)?null:"banner",HR:()=>"separator",HTML:()=>"document",IMG:(_)=>_.getAttribute("alt")===""&&!_.getAttribute("title")&&!fJ(_)&&!CJ(_)?"presentation":"img",INPUT:(_)=>{let J=_.type.toLowerCase();if(J==="search")return _.hasAttribute("list")?"combobox":"searchbox";if(["email","tel","text","url",""].includes(J)){let Z=G_(_,_.getAttribute("list"))[0];return Z&&V(Z)==="DATALIST"?"combobox":"textbox"}if(J==="hidden")return null;if(J==="file")return"button";return lX[J]||"textbox"},INS:()=>"insertion",LI:()=>"listitem",MAIN:()=>"main",MARK:()=>"mark",MATH:()=>"math",MENU:()=>"list",METER:()=>"meter",NAV:()=>"navigation",OL:()=>"list",OPTGROUP:()=>"group",OPTION:()=>"option",OUTPUT:()=>"status",P:()=>"paragraph",PROGRESS:()=>"progressbar",SEARCH:()=>"search",SECTION:(_)=>DJ(_)?"region":null,SELECT:(_)=>_.hasAttribute("multiple")||_.size>1?"listbox":"combobox",STRONG:()=>"strong",SUB:()=>"subscript",SUP:()=>"superscript",SVG:()=>"img",TABLE:()=>"table",TBODY:()=>"rowgroup",TD:(_)=>{let J=s(_,"table"),Z=J?O_(J):"";return Z==="grid"||Z==="treegrid"?"gridcell":"cell"},TEXTAREA:()=>"textbox",TFOOT:()=>"rowgroup",TH:(_)=>{let J=_.getAttribute("scope");if(J==="col"||J==="colgroup")return"columnheader";if(J==="row"||J==="rowgroup")return"rowheader";let{nextElementSibling:Z,previousElementSibling:$}=_,X=!!_.parentElement&&V(_.parentElement)==="TR"?_.parentElement:void 0;if(!Z&&!$){if(X){let Q=s(X,"table");if(Q&&Q.rows.length<=1)return null}return"columnheader"}if(wJ(Z)&&wJ($))return"columnheader";if(AJ(Z)||AJ($))return"rowheader";return"columnheader"},THEAD:()=>"rowgroup",TIME:()=>"time",TR:()=>"row",UL:()=>"list"};function wJ(_){return!!_&&V(_)==="TH"}function AJ(_){if(!_||V(_)!=="TD")return!1;return!!(_.textContent?.trim()||_.children.length>0)}var NX={DD:["DL","DIV"],DIV:["DL"],DT:["DL","DIV"],LI:["OL","UL"],TBODY:["TABLE"],TD:["TR"],TFOOT:["TABLE"],TH:["TR"],THEAD:["TABLE"],TR:["THEAD","TBODY","TFOOT","TABLE"]};function EJ(_){let J=gX[V(_)]?.(_)||"";if(!J)return null;let Z=_;while(Z){let $=h(Z),X=NX[V(Z)];if(!X||!$||!X.includes(V($)))break;let Q=O_($);if((Q==="none"||Q==="presentation")&&!bJ($,Q))return Q;Z=$}return J}var kX=["alert","alertdialog","application","article","banner","blockquote","button","caption","cell","checkbox","code","columnheader","combobox","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","grid","gridcell","group","heading","img","insertion","link","list","listbox","listitem","log","main","mark","marquee","math","meter","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","navigation","none","note","option","paragraph","presentation","progressbar","radio","radiogroup","region","row","rowgroup","rowheader","scrollbar","search","searchbox","separator","slider","spinbutton","status","strong","subscript","superscript","switch","tab","table","tablist","tabpanel","term","textbox","time","timer","toolbar","tooltip","tree","treegrid","treeitem"];function O_(_){return(_.getAttribute("role")||"").split(" ").map((Z)=>Z.trim()).find((Z)=>kX.includes(Z))||null}function bJ(_,J){return fJ(_,J)||xX(_)}function f(_){let J=O_(_);if(!J)return EJ(_);if(J==="none"||J==="presentation"){let Z=EJ(_);if(bJ(_,Z))return Z}return J}function yJ(_){return _===null?void 0:_.toLowerCase()==="true"}function SJ(_){return["STYLE","SCRIPT","NOSCRIPT","TEMPLATE"].includes(V(_))}function y(_){if(SJ(_))return!0;let J=b(_),Z=_.nodeName==="SLOT";if(J?.display==="contents"&&!Z){for(let X=_.firstChild;X;X=X.nextSibling){if(X.nodeType===1&&!y(X))return!1;if(X.nodeType===3&&I_(X))return!1}return!0}if(!(_.nodeName==="OPTION"&&!!_.closest("select"))&&!Z&&!B_(_,J))return!0;return TJ(_)}function TJ(_){let J=q_?.get(_);if(J===void 0){if(J=!1,_.parentElement&&_.parentElement.shadowRoot&&!_.assignedSlot)J=!0;if(!J){let Z=b(_);J=!Z||Z.display==="none"||yJ(_.getAttribute("aria-hidden"))===!0}if(!J){let Z=h(_);if(Z)J=TJ(Z)}q_?.set(_,J)}return J}function G_(_,J){if(!J)return[];let Z=d_(_);if(!Z)return[];try{let $=J.split(" ").filter((Q)=>!!Q),X=[];for(let Q of $){let U=Z.querySelector("#"+CSS.escape(Q));if(U&&!X.includes(U))X.push(U)}return X}catch($){return[]}}function x(_){return _.trim()}function hX(_){return _.split(" ").map((J)=>J.replace(/\\r\\n/g,\`
|
|
13
|
+
\`).replace(/[\\u200b\\u00ad]/g,"").replace(/\\s\\s*/g," ")).join(" ").trim()}function PJ(_,J){let Z=[..._.querySelectorAll(J)];for(let $ of G_(_,_.getAttribute("aria-owns"))){if($.matches(J))Z.push($);Z.push(...$.querySelectorAll(J))}return Z}function c(_,J){let Z=J==="::before"?T_:J==="::after"?x_:S_;if(Z?.has(_))return Z?.get(_);let $=b(_,J),X;if($){let Q=$.content;if(Q&&Q!=="none"&&Q!=="normal"){if($.display!=="none"&&$.visibility!=="hidden")X=uX(_,Q,!!J)}}if(J&&X!==void 0){if(($?.display||"inline")!=="inline")X=" "+X+" "}if(Z)Z.set(_,X);return X}function uX(_,J,Z){if(!J||J==="none"||J==="normal")return;try{let $=n_(J).filter((W)=>!(W instanceof $_)),X=$.findIndex((W)=>W instanceof O&&W.value==="/");if(X!==-1)$=$.slice(X+1);else if(!Z)return;let Q=[],U=0;while(U<$.length)if($[U]instanceof H_)Q.push($[U].value),U++;else if(U+2<$.length&&$[U]instanceof p&&$[U].value==="attr"&&$[U+1]instanceof Q_&&$[U+2]instanceof Y_){let W=$[U+1].value;Q.push(_.getAttribute(W)||""),U+=3}else return;return Q.join("")}catch{}}function pX(_){let J=_.getAttribute("aria-labelledby");if(J===null)return null;let Z=G_(_,J);return Z.length?Z:null}function cX(_,J){let Z=["button","cell","checkbox","columnheader","gridcell","heading","link","menuitem","menuitemcheckbox","menuitemradio","option","radio","row","rowheader","switch","tab","tooltip","treeitem"].includes(_),$=J&&["","caption","code","contentinfo","definition","deletion","emphasis","insertion","list","listitem","mark","none","paragraph","presentation","region","row","rowgroup","section","strong","subscript","superscript","table","term","time"].includes(_);return Z||$}function xJ(_,J){let Z=J?y_:b_,$=Z?.get(_);if($===void 0){if($="",!["caption","code","definition","deletion","emphasis","generic","insertion","mark","paragraph","presentation","strong","subscript","suggestion","superscript","term","time"].includes(f(_)||""))$=hX(v(_,{includeHidden:J,visitedElements:new Set,embeddedInTargetElement:"self"}));Z?.set(_,$)}return $}var vJ=["application","checkbox","columnheader","combobox","gridcell","listbox","radiogroup","rowheader","searchbox","slider","spinbutton","switch","textbox","tree"];function gJ(_){let J=_.getAttribute("aria-invalid");if(!J||J.trim()===""||J.toLocaleLowerCase()==="false")return"false";if(J==="true"||J==="grammar"||J==="spelling")return J;return"true"}function v(_,J){if(J.visitedElements.has(_))return"";let Z={...J,embeddedInTargetElement:J.embeddedInTargetElement==="self"?"descendant":J.embeddedInTargetElement};if(!J.includeHidden){let Y=!!J.embeddedInLabelledBy?.hidden||!!J.embeddedInDescribedBy?.hidden||!!J.embeddedInNativeTextAlternative?.hidden||!!J.embeddedInLabel?.hidden;if(SJ(_)||!Y&&y(_))return J.visitedElements.add(_),""}let $=pX(_);if(!J.embeddedInLabelledBy){let Y=($||[]).map((K)=>v(K,{...J,embeddedInLabelledBy:{element:K,hidden:y(K)},embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0,embeddedInLabel:void 0,embeddedInNativeTextAlternative:void 0})).join(" ");if(Y)return Y}let X=f(_)||"",Q=V(_);if(!!J.embeddedInLabel||!!J.embeddedInLabelledBy||J.embeddedInTargetElement==="descendant"){let Y=[..._.labels||[]].includes(_),K=($||[]).includes(_);if(!Y&&!K){if(X==="textbox"){if(J.visitedElements.add(_),Q==="INPUT"||Q==="TEXTAREA")return _.value;return _.textContent||""}if(["combobox","listbox"].includes(X)){J.visitedElements.add(_);let z;if(Q==="SELECT"){if(z=[..._.selectedOptions],!z.length&&_.options.length)z.push(_.options[0])}else{let q=X==="combobox"?PJ(_,"*").find((L)=>f(L)==="listbox"):_;z=q?PJ(q,'[aria-selected="true"]').filter((L)=>f(L)==="option"):[]}if(!z.length&&Q==="INPUT")return _.value;return z.map((q)=>v(q,Z)).join(" ")}if(["progressbar","scrollbar","slider","spinbutton","meter"].includes(X)){if(J.visitedElements.add(_),_.hasAttribute("aria-valuetext"))return _.getAttribute("aria-valuetext")||"";if(_.hasAttribute("aria-valuenow"))return _.getAttribute("aria-valuenow")||"";return _.getAttribute("value")||""}if(["menu"].includes(X))return J.visitedElements.add(_),""}}let U=_.getAttribute("aria-label")||"";if(x(U))return J.visitedElements.add(_),U;if(!["presentation","none"].includes(X)){if(Q==="INPUT"&&["button","submit","reset"].includes(_.type)){J.visitedElements.add(_);let Y=_.value||"";if(x(Y))return Y;if(_.type==="submit")return"Submit";if(_.type==="reset")return"Reset";return _.getAttribute("title")||""}if(Q==="INPUT"&&_.type==="file"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length&&!J.embeddedInLabelledBy)return r(Y,J);return"Choose File"}if(Q==="INPUT"&&_.type==="image"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length&&!J.embeddedInLabelledBy)return r(Y,J);let K=_.getAttribute("alt")||"";if(x(K))return K;let z=_.getAttribute("title")||"";if(x(z))return z;return"Submit"}if(!$&&Q==="BUTTON"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J)}if(!$&&Q==="OUTPUT"){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J);return _.getAttribute("title")||""}if(!$&&(Q==="TEXTAREA"||Q==="SELECT"||Q==="INPUT")){J.visitedElements.add(_);let Y=_.labels||[];if(Y.length)return r(Y,J);let K=Q==="INPUT"&&["text","password","search","tel","email","url"].includes(_.type)||Q==="TEXTAREA",z=_.getAttribute("placeholder")||"",q=_.getAttribute("title")||"";if(!K||q)return q;return z}if(!$&&Q==="FIELDSET"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="LEGEND")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});return _.getAttribute("title")||""}if(!$&&Q==="FIGURE"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="FIGCAPTION")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});return _.getAttribute("title")||""}if(Q==="IMG"){J.visitedElements.add(_);let Y=_.getAttribute("alt")||"";if(x(Y))return Y;return _.getAttribute("title")||""}if(Q==="TABLE"){J.visitedElements.add(_);for(let K=_.firstElementChild;K;K=K.nextElementSibling)if(V(K)==="CAPTION")return v(K,{...Z,embeddedInNativeTextAlternative:{element:K,hidden:y(K)}});let Y=_.getAttribute("summary")||"";if(Y)return Y}if(Q==="AREA"){J.visitedElements.add(_);let Y=_.getAttribute("alt")||"";if(x(Y))return Y;return _.getAttribute("title")||""}if(Q==="SVG"||_.ownerSVGElement){J.visitedElements.add(_);for(let Y=_.firstElementChild;Y;Y=Y.nextElementSibling)if(V(Y)==="TITLE"&&Y.ownerSVGElement)return v(Y,{...Z,embeddedInLabelledBy:{element:Y,hidden:y(Y)}})}if(_.ownerSVGElement&&Q==="A"){let Y=_.getAttribute("xlink:title")||"";if(x(Y))return J.visitedElements.add(_),Y}}let W=Q==="SUMMARY"&&!["presentation","none"].includes(X);if(cX(X,J.embeddedInTargetElement==="descendant")||W||!!J.embeddedInLabelledBy||!!J.embeddedInDescribedBy||!!J.embeddedInLabel||!!J.embeddedInNativeTextAlternative){J.visitedElements.add(_);let Y=mX(_,Z);if(J.embeddedInTargetElement==="self"?x(Y):Y)return Y}if(!["presentation","none"].includes(X)||Q==="IFRAME"){J.visitedElements.add(_);let Y=_.getAttribute("title")||"";if(x(Y))return Y}return J.visitedElements.add(_),""}function mX(_,J){let Z=[],$=(Q,U)=>{if(U&&Q.assignedSlot)return;if(Q.nodeType===1){let W=b(Q)?.display||"inline",Y=v(Q,J);if(W!=="inline"||Q.nodeName==="BR")Y=" "+Y+" ";Z.push(Y)}else if(Q.nodeType===3)Z.push(Q.textContent||"")};Z.push(c(_,"::before")||"");let X=c(_);if(X!==void 0)Z.push(X);else{let Q=_.nodeName==="SLOT"?_.assignedNodes():[];if(Q.length)for(let U of Q)$(U,!1);else{for(let U=_.firstChild;U;U=U.nextSibling)$(U,!0);if(_.shadowRoot)for(let U=_.shadowRoot.firstChild;U;U=U.nextSibling)$(U,!0);for(let U of G_(_,_.getAttribute("aria-owns")))$(U,!0)}}return Z.push(c(_,"::after")||""),Z.join("")}var w_=["gridcell","option","row","tab","rowheader","columnheader","treeitem"];function NJ(_){if(V(_)==="OPTION")return _.selected;if(w_.includes(f(_)||""))return yJ(_.getAttribute("aria-selected"))===!0;return!1}var A_=["checkbox","menuitemcheckbox","option","radio","switch","menuitemradio","treeitem"];function kJ(_){let J=dX(_,!0);return J==="error"?!1:J}function dX(_,J){let Z=V(_);if(J&&Z==="INPUT"&&_.indeterminate)return"mixed";if(Z==="INPUT"&&["checkbox","radio"].includes(_.type))return _.checked;if(A_.includes(f(_)||"")){let $=_.getAttribute("aria-checked");if($==="true")return!0;if(J&&$==="mixed")return"mixed";return!1}return"error"}var E_=["button"];function hJ(_){if(E_.includes(f(_)||"")){let J=_.getAttribute("aria-pressed");if(J==="true")return!0;if(J==="mixed")return"mixed"}return!1}var P_=["application","button","checkbox","combobox","gridcell","link","listbox","menuitem","row","rowheader","tab","treeitem","columnheader","menuitemcheckbox","menuitemradio","rowheader","switch"];function uJ(_){if(V(_)==="DETAILS")return _.open;if(P_.includes(f(_)||"")){let J=_.getAttribute("aria-expanded");if(J===null)return;if(J==="true")return!0;return!1}return}var f_=["heading","listitem","row","treeitem"];function pJ(_){let J={H1:1,H2:2,H3:3,H4:4,H5:5,H6:6}[V(_)];if(J)return J;if(f_.includes(f(_)||"")){let Z=_.getAttribute("aria-level"),$=Z===null?Number.NaN:Number(Z);if(Number.isInteger($)&&$>=1)return $}return 0}var C_=["application","button","composite","gridcell","group","input","link","menuitem","scrollbar","separator","tab","checkbox","columnheader","combobox","grid","listbox","menu","menubar","menuitemcheckbox","menuitemradio","option","radio","radiogroup","row","rowheader","searchbox","select","slider","spinbutton","switch","tablist","textbox","toolbar","tree","treegrid","treeitem"];function cJ(_){return mJ(_)||dJ(_)}function mJ(_){return["BUTTON","INPUT","SELECT","TEXTAREA","OPTION","OPTGROUP"].includes(V(_))&&(_.hasAttribute("disabled")||sX(_)||iX(_))}function sX(_){return V(_)==="OPTION"&&!!_.closest("OPTGROUP[DISABLED]")}function iX(_){let J=_?.closest("FIELDSET[DISABLED]");if(!J)return!1;let Z=J.querySelector(":scope > LEGEND");return!Z||!Z.contains(_)}function dJ(_,J=!1){if(!_)return!1;if(J||C_.includes(f(_)||"")){let Z=(_.getAttribute("aria-disabled")||"").toLowerCase();if(Z==="true")return!0;if(Z==="false")return!1;return dJ(h(_),!0)}return!1}function r(_,J){return[..._].map((Z)=>v(Z,{...J,embeddedInLabel:{element:Z,hidden:y(Z)},embeddedInNativeTextAlternative:void 0,embeddedInLabelledBy:void 0,embeddedInDescribedBy:void 0,embeddedInTargetElement:void 0})).filter((Z)=>!!Z).join(" ")}function sJ(_){let J=v_,Z=_,$,X=[];for(;Z;Z=h(Z)){let Q=J.get(Z);if(Q!==void 0){$=Q;break}X.push(Z);let U=b(Z);if(!U){$=!0;break}let W=U.pointerEvents;if(W){$=W!=="none";break}}if($===void 0)$=!0;for(let Q of X)J.set(Q,$);return $}var b_,y_,iJ,lJ,rJ,q_,S_,T_,x_,v_,aJ=0;function nJ(){i_(),++aJ,b_??=new Map,y_??=new Map,iJ??=new Map,lJ??=new Map,rJ??=new Map,q_??=new Map,S_??=new Map,T_??=new Map,x_??=new Map,v_??=new Map}function oJ(){if(!--aJ)b_=void 0,y_=void 0,iJ=void 0,lJ=void 0,rJ=void 0,q_=void 0,S_=void 0,T_=void 0,x_=void 0,v_=void 0;l_()}var lX={button:"button",checkbox:"checkbox",image:"button",number:"spinbutton",radio:"radio",range:"slider",reset:"button",submit:"button"};var aX=0;function eJ(_){let J=_.boxes;if(_.mode==="ai")return{visibility:"ariaOrVisible",refs:"interactable",refPrefix:_.refPrefix,includeGenericRole:!0,renderActive:!_.doNotRenderActive,renderCursorPointer:!0,renderBoxes:J};if(_.mode==="autoexpect")return{visibility:"ariaAndVisible",refs:"none",renderBoxes:J};if(_.mode==="codegen")return{visibility:"aria",refs:"none",renderStringsAsRegex:!0,renderBoxes:J};return{visibility:"aria",refs:"none",renderBoxes:J}}function _X(_,J){let Z=eJ(J),$=new Set,X={root:{role:"fragment",name:"",children:[],props:{},box:i(_),receivesPointerEvents:!0},elements:new Map,refs:new Map,iframeRefs:[]};g_(X.root,_);let Q=(W,Y,K)=>{if($.has(Y))return;if($.add(Y),Y.nodeType===Node.TEXT_NODE&&Y.nodeValue){if(!K)return;let F=Y.nodeValue;if(W.role!=="textbox"&&F)W.children.push(Y.nodeValue||"");return}if(Y.nodeType!==Node.ELEMENT_NODE)return;let z=Y,q=!y(z),L=q;if(Z.visibility==="ariaOrVisible")L=q||__(z);if(Z.visibility==="ariaAndVisible")L=q&&__(z);if(Z.visibility==="aria"&&!L)return;let I=[];if(z.hasAttribute("aria-owns")){let F=z.getAttribute("aria-owns").split(/\\s+/);for(let j of F){let w=_.ownerDocument.getElementById(j);if(w)I.push(w)}}let H=L?nX(z,Z):null;if(H){if(H.ref){if(X.elements.set(H.ref,z),X.refs.set(z,H.ref),H.role==="iframe")X.iframeRefs.push(H.ref)}W.children.push(H)}U(H||W,z,I,L)};function U(W,Y,K,z){let L=(b(Y)?.display||"inline")!=="inline"||Y.nodeName==="BR"?" ":"";if(L)W.children.push(L);W.children.push(c(Y,"::before")||"");let I=Y.nodeName==="SLOT"?Y.assignedNodes():[];if(I.length)for(let H of I)Q(W,H,z);else{for(let H=Y.firstChild;H;H=H.nextSibling)if(!H.assignedSlot)Q(W,H,z);if(Y.shadowRoot)for(let H=Y.shadowRoot.firstChild;H;H=H.nextSibling)Q(W,H,z)}for(let H of K)Q(W,H,z);if(W.children.push(c(Y,"::after")||""),L)W.children.push(L);if(W.children.length===1&&W.name===W.children[0])W.children=[];if(W.role==="link"&&Y.hasAttribute("href")){let H=Y.getAttribute("href");W.props.url=H}if(W.role==="textbox"&&Y.hasAttribute("placeholder")&&Y.getAttribute("placeholder")!==W.name){let H=Y.getAttribute("placeholder");W.props.placeholder=H}}nJ();try{Q(X.root,_,!0)}finally{oJ()}return tX(X.root),oX(X.root),X}function tJ(_,J){if(J.refs==="none")return;if(J.refs==="interactable"&&(!_.box.visible||!_.receivesPointerEvents))return;let Z=$X(_),$=Z._ariaRef;if(!$||$.role!==_.role||$.name!==_.name)$={role:_.role,name:_.name,ref:(J.refPrefix??"")+"e"+ ++aX},Z._ariaRef=$;_.ref=$.ref}function nX(_,J){let Z=_.ownerDocument.activeElement===_;if(_.nodeName==="IFRAME"){let K={role:"iframe",name:"",children:[],props:{},box:i(_),receivesPointerEvents:!0,active:Z};return g_(K,_),tJ(K,J),K}let $=J.includeGenericRole?"generic":null,X=f(_)??$;if(!X||X==="presentation"||X==="none")return null;let Q=j_(xJ(_,!1)||""),U=sJ(_),W=i(_);if(X==="generic"&&W.inline&&_.childNodes.length===1&&_.childNodes[0].nodeType===Node.TEXT_NODE)return null;let Y={role:X,name:Q,children:[],props:{},box:W,receivesPointerEvents:U,active:Z};if(g_(Y,_),tJ(Y,J),A_.includes(X))Y.checked=kJ(_);if(C_.includes(X))Y.disabled=cJ(_);if(P_.includes(X))Y.expanded=uJ(_);if(vJ.includes(X)){let K=gJ(_);Y.invalid=K==="false"?!1:K==="true"?!0:K}if(f_.includes(X))Y.level=pJ(_);if(E_.includes(X))Y.pressed=hJ(_);if(w_.includes(X))Y.selected=NJ(_);if(_ instanceof HTMLInputElement||_ instanceof HTMLTextAreaElement){if(_.type!=="checkbox"&&_.type!=="radio"&&_.type!=="file")Y.children=[_.value]}return Y}function oX(_){let J=(Z)=>{let $=[];for(let Q of Z.children||[]){if(typeof Q==="string"){$.push(Q);continue}let U=J(Q);$.push(...U)}if(Z.role==="generic"&&!Z.name&&$.length<=1&&$.every((Q)=>typeof Q!=="string"&&!!Q.ref))return $;return Z.children=$,[Z]};J(_)}function tX(_){let J=($,X)=>{if(!$.length)return;let Q=j_($.join(""));if(Q)X.push(Q);$.length=0},Z=($)=>{let X=[],Q=[];for(let U of $.children||[])if(typeof U==="string")Q.push(U);else J(Q,X),Z(U),X.push(U);if(J(Q,X),$.children=X.length?X:[],$.children.length===1&&$.children[0]===$.name)$.children=[]};Z(_)}var jZ=Symbol("cachedRegex");function JX(_,J=new Map){if(_?.ref)J.set(_.ref,_);for(let Z of _?.children||[])if(typeof Z!=="string")JX(Z,J);return J}function eX(_,J){let Z=JX(J?.root),$=new Map,X=(Q,U)=>{let W=Q.children.length===U?.children.length&&h_(Q,U),Y=W;for(let K=0;K<Q.children.length;K++){let z=Q.children[K],q=U?.children[K];if(typeof z==="string")W&&=z===q,Y&&=z===q;else{let L=typeof q!=="string"?q:void 0;if(z.ref)L=Z.get(z.ref);let I=X(z,L);if(!L||!I&&!z.ref||L!==q)Y=!1;W&&=I&&L===q}}return $.set(Q,W?"same":Y?"skip":"changed"),W};return X(_.root,Z.get(J?.root?.ref)),$}function _Z(_,J){let Z=[],$=(X)=>{let Q=J.get(X);if(Q==="same");else if(Q==="skip"){for(let U of X.children)if(typeof U!=="string")$(U)}else Z.push(X)};for(let X of _)if(typeof X==="string")Z.push(X);else $(X);return Z}function U_(_){return" ".repeat(_)}function XX(_,J,Z){let $=eJ(J),X=[],Q={},U=$.renderStringsAsRegex?XZ:()=>!0,W=$.renderStringsAsRegex?JZ:(H)=>H,Y=_.root.role==="fragment"?_.root.children:[_.root],K=eX(_,Z);if(Z)Y=_Z(Y,K);let z=(H,F)=>{if(J.depth&&F>J.depth)return;let j=e(W(H));if(j)X.push(U_(F)+"- text: "+j)},q=(H,F)=>{let j=H.role;if(H.name&&H.name.length<=900){let w=W(H.name);if(w){let E=w.startsWith("/")&&w.endsWith("/")?w:JSON.stringify(w);j+=" "+E}}if(H.checked==="mixed")j+=" [checked=mixed]";if(H.checked===!0)j+=" [checked]";if(H.disabled)j+=" [disabled]";if(H.expanded)j+=" [expanded]";if(H.active&&$.renderActive)j+=" [active]";if(H.invalid==="grammar"||H.invalid==="spelling")j+=\` [invalid=\${H.invalid}]\`;if(H.invalid===!0)j+=" [invalid]";if(H.level)j+=\` [level=\${H.level}]\`;if(H.pressed==="mixed")j+=" [pressed=mixed]";if(H.pressed===!0)j+=" [pressed]";if(H.selected===!0)j+=" [selected]";if(H.ref){if(j+=\` [ref=\${H.ref}]\`,F&&d(H))j+=" [cursor=pointer]"}if($.renderBoxes){let w=$X(H);if(w){let E=w.getBoundingClientRect();j+=\` [box=\${Math.round(E.x)},\${Math.round(E.y)},\${Math.round(E.width)},\${Math.round(E.height)}]\`}}return j},L=(H)=>{return H?.children.length===1&&typeof H.children[0]==="string"&&!Object.keys(H.props).length?H.children[0]:void 0},I=(H,F,j)=>{if(J.depth&&F>J.depth)return;if(H.role==="iframe"&&H.ref)Q[H.ref]=F;if(K.get(H)==="same"&&H.ref){X.push(U_(F)+\`- ref=\${H.ref} [unchanged]\`);return}let w=!!Z&&!F,E=U_(F)+"- "+(w?"<changed> ":"")+c_(q(H,j)),S=L(H),m=!!J.depth&&F===J.depth;if(!S&&(!H.children.length||m)&&!Object.keys(H.props).length)X.push(E);else if(S!==void 0)if(U(H,S))X.push(E+": "+e(W(S)));else X.push(E);else{X.push(E+":");for(let[C,k]of Object.entries(H.props))X.push(U_(F+1)+"- /"+C+": "+e(k));let a=!!H.ref&&j&&d(H);for(let C of H.children)if(typeof C==="string")z(U(H,C)?C:"",F+1);else I(C,F+1,j&&!a)}};for(let H of Y)if(typeof H==="string")z(H,0);else I(H,0,!!$.renderCursorPointer);return{text:X.join(\`
|
|
14
|
+
\`),iframeDepths:Q}}function JZ(_){let J=[{regex:/\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b/,replacement:"[0-9a-fA-F-]+"},{regex:/\\b[\\d,.]+[bkmBKM]+\\b/,replacement:"[\\\\d,.]+[bkmBKM]+"},{regex:/\\b\\d+[hmsp]+\\b/,replacement:"\\\\d+[hmsp]+"},{regex:/\\b[\\d,.]+[hmsp]+\\b/,replacement:"[\\\\d,.]+[hmsp]+"},{regex:/\\b\\d+,\\d+\\b/,replacement:"\\\\d+,\\\\d+"},{regex:/\\b\\d+\\.\\d{2,}\\b/,replacement:"\\\\d+\\\\.\\\\d+"},{regex:/\\b\\d{2,}\\.\\d+\\b/,replacement:"\\\\d+\\\\.\\\\d+"},{regex:/\\b\\d{2,}\\b/,replacement:"\\\\d+"}],Z="",$=0,X=new RegExp(J.map((Q)=>"("+Q.regex.source+")").join("|"),"g");if(_.replace(X,(Q,...U)=>{let W=U[U.length-2],Y=U.slice(0,-2);Z+=F_(_.slice($,W));for(let K=0;K<Y.length;K++)if(Y[K]){let{replacement:z}=J[K];Z+=z;break}return $=W+Q.length,Q}),!Z)return _;return Z+=F_(_.slice($)),String(new RegExp(Z))}function XZ(_,J){if(!J.length)return!1;if(!_.name)return!0;let Z=J.length<=200&&_.name.length<=200?p_(J,_.name):"",$=J;while(Z&&$.includes(Z))$=$.replace(Z,"");return $.trim().length/J.length>0.1}var ZX=Symbol("element");function $X(_){return _[ZX]}function g_(_,J){_[ZX]=J}function YX(_){let J=(Z)=>{for(let $ of Array.from(Z.querySelectorAll("*"))){_($);let X=$.shadowRoot;if(X)J(X)}};J(document)}function ZZ(_,J={}){YX((Q)=>{if(Q._ariaRef)delete Q._ariaRef});let Z=_??document.body??document.documentElement,$={mode:"ai",depth:J.depth,boxes:J.boxes},X=_X(Z,$);return XX(X,$).text}function $Z(_){let J=null;return YX((Z)=>{if(!J&&Z._ariaRef?.ref===_)J=Z}),J}
|
|
15
|
+
`;
|
|
16
|
+
//# sourceMappingURL=aria-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria-bundle.js","sourceRoot":"","sources":["../src/aria-bundle.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,kBAAkB,GAAW;;;;;;;CAOzC,CAAA"}
|
package/dist/aria.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARIA snapshot + ref resolution for the browser service.
|
|
3
|
+
*
|
|
4
|
+
* Port of omp's `aria/aria-snapshot.ts` (MIT, see port_omp.md item: browser
|
|
5
|
+
* tool with relay): the bundled Playwright ARIA-snapshot sources
|
|
6
|
+
* (Apache-2.0, Microsoft) run in the page's MAIN world where their `[ref=eN]`
|
|
7
|
+
* ids live; a snapshot is cheap and addresses elements model-side. The page
|
|
8
|
+
* bundle is Playwright's, so the snapshot dialect matches what Playwright
|
|
9
|
+
* users expect, and the refs stay valid until the next snapshot.
|
|
10
|
+
* @module @hy-sde-org/dsh-browser/aria
|
|
11
|
+
*/
|
|
12
|
+
import type { Page, ElementHandle } from 'playwright-core';
|
|
13
|
+
export interface AriaSnapshotOptions {
|
|
14
|
+
/** Maximum tree depth to render. */
|
|
15
|
+
depth?: number;
|
|
16
|
+
/** Append `[box=x,y,w,h]` bounding boxes to each node. */
|
|
17
|
+
boxes?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Capture a Playwright-format ARIA snapshot of the document (root is reserved
|
|
21
|
+
* for element-scoped snapshots). Always runs in `ai` mode so every node
|
|
22
|
+
* carries a `[ref=eN]` id; resolve those refs to elements with
|
|
23
|
+
* {@link resolveAriaRefElement}. Ids are renumbered from e1 on each call and
|
|
24
|
+
* remain valid until the next snapshot.
|
|
25
|
+
*/
|
|
26
|
+
export declare function captureAriaSnapshot(page: Page, root: ElementHandle | null, options?: AriaSnapshotOptions): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a `[ref=eN]` id from the latest snapshot to a live element, or null
|
|
29
|
+
* when the ref no longer matches any element. Runs in the main world so it
|
|
30
|
+
* sees the `_ariaRef` expandos the snapshot wrote.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveAriaRefElement(page: Page, ref: string): Promise<ElementHandle | null>;
|
|
33
|
+
/** Whether a selector string is an ARIA snapshot ref selector. */
|
|
34
|
+
export declare function isAriaRefSelector(selector: string | undefined): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Parse an ARIA ref selector (`aria-ref=e5` / `aria-ref/e5` / `ariaref/e5`)
|
|
37
|
+
* to the bare `eN` id, or null when it is not an ARIA ref form.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseAriaRefSelector(selector: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Build a CSS selector (`[aria-ref=e5]`) from an ARIA snapshot selector form
|
|
42
|
+
* (`aria-ref=e5`), or return undefined when it is not an ARIA ref form.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildAriaSnapshotScript(selector: string | undefined, _options?: AriaSnapshotOptions): string | undefined;
|
|
45
|
+
//# sourceMappingURL=aria.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria.d.ts","sourceRoot":"","sources":["../src/aria.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAG1D,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,0DAA0D;IAC1D,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAgBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,aAAa,GAAG,IAAI,EAC1B,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAO/B;AAID,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIvE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASpE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAE,mBAAwB,GAAG,MAAM,GAAG,SAAS,CAI5H"}
|
package/dist/aria.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARIA snapshot + ref resolution for the browser service.
|
|
3
|
+
*
|
|
4
|
+
* Port of omp's `aria/aria-snapshot.ts` (MIT, see port_omp.md item: browser
|
|
5
|
+
* tool with relay): the bundled Playwright ARIA-snapshot sources
|
|
6
|
+
* (Apache-2.0, Microsoft) run in the page's MAIN world where their `[ref=eN]`
|
|
7
|
+
* ids live; a snapshot is cheap and addresses elements model-side. The page
|
|
8
|
+
* bundle is Playwright's, so the snapshot dialect matches what Playwright
|
|
9
|
+
* users expect, and the refs stay valid until the next snapshot.
|
|
10
|
+
* @module @hy-sde-org/dsh-browser/aria
|
|
11
|
+
*/
|
|
12
|
+
import { ariaSnapshotBundle } from "./aria-bundle.js";
|
|
13
|
+
/** Page-side evaluator built ONCE here, outside the page, so CSP never applies. */
|
|
14
|
+
function buildEvaluator(params, call) {
|
|
15
|
+
// oxlint-disable-next-line typescript/no-implied-eval -- ported omp mechanic: the trusted bundle is the eval surface
|
|
16
|
+
return new Function(...params.split(',').map(p => p.trim()), `var module = { exports: {} };\n${ariaSnapshotBundle}\nreturn module.exports.${call};`);
|
|
17
|
+
}
|
|
18
|
+
// Playwright's evaluate passes at most ONE argument, so the snapshot request is
|
|
19
|
+
// carried in a single payload value (root is always null for document snapshots).
|
|
20
|
+
const evaluateAriaSnapshot = buildEvaluator('payload', 'ariaSnapshot(payload.root ?? null, payload.request)');
|
|
21
|
+
const evaluateResolveRef = buildEvaluator('ref', 'resolveAriaRef(ref)');
|
|
22
|
+
/**
|
|
23
|
+
* Capture a Playwright-format ARIA snapshot of the document (root is reserved
|
|
24
|
+
* for element-scoped snapshots). Always runs in `ai` mode so every node
|
|
25
|
+
* carries a `[ref=eN]` id; resolve those refs to elements with
|
|
26
|
+
* {@link resolveAriaRefElement}. Ids are renumbered from e1 on each call and
|
|
27
|
+
* remain valid until the next snapshot.
|
|
28
|
+
*/
|
|
29
|
+
export async function captureAriaSnapshot(page, root, options = {}) {
|
|
30
|
+
const request = { depth: options.depth, boxes: options.boxes };
|
|
31
|
+
return await page.evaluate(evaluateAriaSnapshot, { root, request });
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a `[ref=eN]` id from the latest snapshot to a live element, or null
|
|
35
|
+
* when the ref no longer matches any element. Runs in the main world so it
|
|
36
|
+
* sees the `_ariaRef` expandos the snapshot wrote.
|
|
37
|
+
*/
|
|
38
|
+
export async function resolveAriaRefElement(page, ref) {
|
|
39
|
+
try {
|
|
40
|
+
const handle = await page.evaluateHandle(evaluateResolveRef, ref);
|
|
41
|
+
return handle.asElement();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const ARIA_REF_PREFIXES = ['aria-ref=', 'aria-ref/', 'ariaref/'];
|
|
48
|
+
/** Whether a selector string is an ARIA snapshot ref selector. */
|
|
49
|
+
export function isAriaRefSelector(selector) {
|
|
50
|
+
if (!selector)
|
|
51
|
+
return false;
|
|
52
|
+
const trimmed = selector.trim();
|
|
53
|
+
return ARIA_REF_PREFIXES.some(prefix => trimmed.startsWith(prefix));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse an ARIA ref selector (`aria-ref=e5` / `aria-ref/e5` / `ariaref/e5`)
|
|
57
|
+
* to the bare `eN` id, or null when it is not an ARIA ref form.
|
|
58
|
+
*/
|
|
59
|
+
export function parseAriaRefSelector(selector) {
|
|
60
|
+
const trimmed = selector.trim();
|
|
61
|
+
for (const prefix of ARIA_REF_PREFIXES) {
|
|
62
|
+
if (trimmed.startsWith(prefix)) {
|
|
63
|
+
const ref = trimmed.slice(prefix.length);
|
|
64
|
+
return /^e\d+$/.test(ref) ? ref : null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build a CSS selector (`[aria-ref=e5]`) from an ARIA snapshot selector form
|
|
71
|
+
* (`aria-ref=e5`), or return undefined when it is not an ARIA ref form.
|
|
72
|
+
*/
|
|
73
|
+
export function buildAriaSnapshotScript(selector, _options = {}) {
|
|
74
|
+
if (!selector)
|
|
75
|
+
return undefined;
|
|
76
|
+
const ref = parseAriaRefSelector(selector);
|
|
77
|
+
return ref ? `[aria-ref=${ref}]` : undefined;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=aria.js.map
|
package/dist/aria.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aria.js","sourceRoot":"","sources":["../src/aria.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AASrD,mFAAmF;AACnF,SAAS,cAAc,CAAC,MAAc,EAAE,IAAY;IAClD,qHAAqH;IACrH,OAAO,IAAI,QAAQ,CACjB,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EACvC,kCAAkC,kBAAkB,2BAA2B,IAAI,GAAG,CACzC,CAAA;AACjD,CAAC;AAED,gFAAgF;AAChF,kFAAkF;AAClF,MAAM,oBAAoB,GAAG,cAAc,CAAC,SAAS,EAAE,qDAAqD,CAAC,CAAA;AAC7G,MAAM,kBAAkB,GAAG,cAAc,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAA;AAEvE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAU,EACV,IAA0B,EAC1B,UAA+B,EAAE;IAEjC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAA;IAC9D,OAAO,MAAO,IAAI,CAAC,QAAQ,CAAC,oBAA6B,EAAE,EAAE,IAAI,EAAE,OAAO,EAAW,CAAqB,CAAA;AAC5G,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAU,EACV,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,kBAA2B,EAAE,GAAY,CAAC,CAAA;QACnF,OAAO,MAAM,CAAC,SAAS,EAAE,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,CAAA;AAEhE,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,QAA4B;IAC5D,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC/B,OAAO,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;AACrE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC/B,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACxC,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;QACxC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAA4B,EAAE,WAAgC,EAAE;IACtG,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/B,MAAM,GAAG,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;IAC1C,OAAO,GAAG,CAAC,CAAC,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9C,CAAC"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// extension/background.ts
|
|
2
|
+
var DEFAULT_PORT = 9224;
|
|
3
|
+
var PING_INTERVAL_MS = 20000;
|
|
4
|
+
var RECONNECT_MIN_MS = 1000;
|
|
5
|
+
var RECONNECT_MAX_MS = 1e4;
|
|
6
|
+
var ws = null;
|
|
7
|
+
var reconnectDelay = RECONNECT_MIN_MS;
|
|
8
|
+
var pingTimer = null;
|
|
9
|
+
async function loadSettings() {
|
|
10
|
+
const stored = await chrome.storage.local.get({ port: DEFAULT_PORT, token: "" });
|
|
11
|
+
const port = Number(stored.port);
|
|
12
|
+
return {
|
|
13
|
+
port: Number.isInteger(port) && port > 0 && port <= 65535 ? port : DEFAULT_PORT,
|
|
14
|
+
token: typeof stored.token === "string" ? stored.token : ""
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function snapshot(tab) {
|
|
18
|
+
if (tab.id === undefined)
|
|
19
|
+
return null;
|
|
20
|
+
return {
|
|
21
|
+
tabId: tab.id,
|
|
22
|
+
url: tab.url ?? tab.pendingUrl ?? "",
|
|
23
|
+
title: tab.title ?? "",
|
|
24
|
+
active: tab.active,
|
|
25
|
+
windowId: tab.windowId,
|
|
26
|
+
pinned: tab.pinned,
|
|
27
|
+
groupId: tab.groupId
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
var ompGroupTitle = null;
|
|
31
|
+
var groupOps = Promise.resolve();
|
|
32
|
+
function enqueueGroupOp(fn) {
|
|
33
|
+
const result = groupOps.then(fn, fn);
|
|
34
|
+
groupOps = result.catch(() => {});
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
async function groupTabs(tabIds, title, color) {
|
|
38
|
+
ompGroupTitle = title;
|
|
39
|
+
chrome.storage.session.set({ ompGroupTitle: title });
|
|
40
|
+
const byWindow = new Map;
|
|
41
|
+
for (const tabId of tabIds) {
|
|
42
|
+
try {
|
|
43
|
+
const tab = await chrome.tabs.get(tabId);
|
|
44
|
+
if (tab.pinned || tab.id === undefined)
|
|
45
|
+
continue;
|
|
46
|
+
const bucket = byWindow.get(tab.windowId) ?? [];
|
|
47
|
+
bucket.push(tab.id);
|
|
48
|
+
byWindow.set(tab.windowId, bucket);
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
const grouped = {};
|
|
52
|
+
for (const [windowId, ids] of byWindow) {
|
|
53
|
+
const existing = await chrome.tabGroups.query({ title, windowId });
|
|
54
|
+
let groupId;
|
|
55
|
+
if (existing[0]) {
|
|
56
|
+
groupId = existing[0].id;
|
|
57
|
+
for (const dupe of existing.slice(1)) {
|
|
58
|
+
const dupeTabs = await chrome.tabs.query({ groupId: dupe.id });
|
|
59
|
+
const dupeIds = dupeTabs.map((tab) => tab.id).filter((id) => id !== undefined);
|
|
60
|
+
if (dupeIds.length > 0)
|
|
61
|
+
await chrome.tabs.group({ tabIds: dupeIds, groupId });
|
|
62
|
+
}
|
|
63
|
+
await chrome.tabs.group({ tabIds: ids, groupId });
|
|
64
|
+
} else {
|
|
65
|
+
groupId = await chrome.tabs.group({ tabIds: ids });
|
|
66
|
+
}
|
|
67
|
+
await chrome.tabGroups.update(groupId, { title, color });
|
|
68
|
+
for (const id of ids)
|
|
69
|
+
grouped[String(id)] = groupId;
|
|
70
|
+
}
|
|
71
|
+
return { grouped };
|
|
72
|
+
}
|
|
73
|
+
async function restoreGroups() {
|
|
74
|
+
if (!ompGroupTitle) {
|
|
75
|
+
const stored = await chrome.storage.session.get({ ompGroupTitle: "" }).catch(() => ({ ompGroupTitle: "" }));
|
|
76
|
+
ompGroupTitle = typeof stored.ompGroupTitle === "string" && stored.ompGroupTitle ? stored.ompGroupTitle : null;
|
|
77
|
+
}
|
|
78
|
+
if (!ompGroupTitle)
|
|
79
|
+
return;
|
|
80
|
+
const groups = await chrome.tabGroups.query({ title: ompGroupTitle }).catch(() => []);
|
|
81
|
+
for (const group of groups) {
|
|
82
|
+
const tabs = await chrome.tabs.query({ groupId: group.id }).catch(() => []);
|
|
83
|
+
const ids = tabs.map((tab) => tab.id).filter((id) => id !== undefined);
|
|
84
|
+
if (ids.length > 0)
|
|
85
|
+
await chrome.tabs.ungroup(ids).catch(() => {});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function post(msg) {
|
|
89
|
+
if (ws?.readyState === WebSocket.OPEN)
|
|
90
|
+
ws.send(JSON.stringify(msg));
|
|
91
|
+
}
|
|
92
|
+
async function setBadge(connected) {
|
|
93
|
+
try {
|
|
94
|
+
await chrome.action.setBadgeText({ text: connected ? "on" : "off" });
|
|
95
|
+
await chrome.action.setBadgeBackgroundColor({ color: connected ? "#1a7f37" : "#8b8b8b" });
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
async function buildHello() {
|
|
99
|
+
const [tabs, targets] = await Promise.all([chrome.tabs.query({}), chrome.debugger.getTargets()]);
|
|
100
|
+
const snapshots = [];
|
|
101
|
+
for (const tab of tabs) {
|
|
102
|
+
const snap = snapshot(tab);
|
|
103
|
+
if (snap)
|
|
104
|
+
snapshots.push(snap);
|
|
105
|
+
}
|
|
106
|
+
const attachedTabIds = [];
|
|
107
|
+
for (const target of targets) {
|
|
108
|
+
if (target.attached && target.tabId !== undefined)
|
|
109
|
+
attachedTabIds.push(target.tabId);
|
|
110
|
+
}
|
|
111
|
+
const versionMatch = /Chrome\/[\d.]+/.exec(navigator.userAgent);
|
|
112
|
+
return {
|
|
113
|
+
t: "hello",
|
|
114
|
+
userAgent: navigator.userAgent,
|
|
115
|
+
browserVersion: versionMatch?.[0] ?? "Chrome/unknown",
|
|
116
|
+
tabs: snapshots,
|
|
117
|
+
attachedTabIds
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function runRpc(msg) {
|
|
121
|
+
switch (msg.op) {
|
|
122
|
+
case "attach":
|
|
123
|
+
await chrome.debugger.attach({ tabId: msg.tabId }, "1.3");
|
|
124
|
+
return {};
|
|
125
|
+
case "detach":
|
|
126
|
+
await chrome.debugger.detach({ tabId: msg.tabId });
|
|
127
|
+
return {};
|
|
128
|
+
case "send":
|
|
129
|
+
return await chrome.debugger.sendCommand(msg.sessionId ? { tabId: msg.tabId, sessionId: msg.sessionId } : { tabId: msg.tabId }, msg.method, msg.params);
|
|
130
|
+
case "createTab": {
|
|
131
|
+
const tab = await chrome.tabs.create({ url: msg.url });
|
|
132
|
+
const snap = snapshot(tab);
|
|
133
|
+
if (!snap)
|
|
134
|
+
throw new Error("created tab has no id");
|
|
135
|
+
return { tab: snap };
|
|
136
|
+
}
|
|
137
|
+
case "removeTab":
|
|
138
|
+
await chrome.tabs.remove(msg.tabId);
|
|
139
|
+
return {};
|
|
140
|
+
case "activateTab": {
|
|
141
|
+
const tab = await chrome.tabs.get(msg.tabId);
|
|
142
|
+
await chrome.windows.update(tab.windowId, { focused: true });
|
|
143
|
+
await chrome.tabs.update(msg.tabId, { active: true });
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
146
|
+
case "group":
|
|
147
|
+
return await enqueueGroupOp(() => groupTabs(msg.tabIds, msg.title, msg.color));
|
|
148
|
+
case "ungroup":
|
|
149
|
+
await enqueueGroupOp(() => chrome.tabs.ungroup(msg.tabIds).catch(() => {}));
|
|
150
|
+
return {};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function handleRelayMessage(raw) {
|
|
154
|
+
let msg;
|
|
155
|
+
try {
|
|
156
|
+
msg = JSON.parse(raw);
|
|
157
|
+
} catch {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (msg.t === "pong")
|
|
161
|
+
return;
|
|
162
|
+
runRpc(msg).then((result) => post({ t: "rpcResult", id: msg.id, ok: true, result })).catch((err) => {
|
|
163
|
+
post({ t: "rpcResult", id: msg.id, ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function scheduleReconnect() {
|
|
167
|
+
const delay = reconnectDelay;
|
|
168
|
+
reconnectDelay = Math.min(reconnectDelay * 2, RECONNECT_MAX_MS);
|
|
169
|
+
setTimeout(() => void connect(), delay);
|
|
170
|
+
}
|
|
171
|
+
async function connect() {
|
|
172
|
+
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING))
|
|
173
|
+
return;
|
|
174
|
+
const settings = await loadSettings();
|
|
175
|
+
const url = `ws://127.0.0.1:${settings.port}/ext${settings.token ? `?token=${encodeURIComponent(settings.token)}` : ""}`;
|
|
176
|
+
const socket = new WebSocket(url);
|
|
177
|
+
ws = socket;
|
|
178
|
+
socket.onopen = () => {
|
|
179
|
+
reconnectDelay = RECONNECT_MIN_MS;
|
|
180
|
+
setBadge(true);
|
|
181
|
+
buildHello().then((hello) => post(hello));
|
|
182
|
+
clearInterval(pingTimer ?? undefined);
|
|
183
|
+
pingTimer = setInterval(() => post({ t: "ping" }), PING_INTERVAL_MS);
|
|
184
|
+
};
|
|
185
|
+
socket.onmessage = (event) => {
|
|
186
|
+
if (typeof event.data === "string")
|
|
187
|
+
handleRelayMessage(event.data);
|
|
188
|
+
};
|
|
189
|
+
socket.onclose = () => {
|
|
190
|
+
if (ws !== socket)
|
|
191
|
+
return;
|
|
192
|
+
ws = null;
|
|
193
|
+
if (pingTimer !== null) {
|
|
194
|
+
clearInterval(pingTimer);
|
|
195
|
+
pingTimer = null;
|
|
196
|
+
}
|
|
197
|
+
setBadge(false);
|
|
198
|
+
restoreGroups();
|
|
199
|
+
scheduleReconnect();
|
|
200
|
+
};
|
|
201
|
+
socket.onerror = () => {
|
|
202
|
+
socket.close();
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
chrome.debugger.onEvent.addListener((source, method, params) => {
|
|
206
|
+
if (source.tabId === undefined)
|
|
207
|
+
return;
|
|
208
|
+
post({ t: "cdpEvent", tabId: source.tabId, sessionId: source.sessionId, method, params });
|
|
209
|
+
});
|
|
210
|
+
chrome.debugger.onDetach.addListener((source, reason) => {
|
|
211
|
+
if (source.tabId === undefined)
|
|
212
|
+
return;
|
|
213
|
+
post({ t: "detached", tabId: source.tabId, reason });
|
|
214
|
+
});
|
|
215
|
+
chrome.tabs.onCreated.addListener((tab) => {
|
|
216
|
+
const snap = snapshot(tab);
|
|
217
|
+
if (snap)
|
|
218
|
+
post({ t: "tabCreated", tab: snap });
|
|
219
|
+
});
|
|
220
|
+
chrome.tabs.onUpdated.addListener((_tabId, _changeInfo, tab) => {
|
|
221
|
+
const snap = snapshot(tab);
|
|
222
|
+
if (snap)
|
|
223
|
+
post({ t: "tabUpdated", tab: snap });
|
|
224
|
+
});
|
|
225
|
+
chrome.tabs.onRemoved.addListener((tabId) => {
|
|
226
|
+
post({ t: "tabRemoved", tabId });
|
|
227
|
+
});
|
|
228
|
+
chrome.alarms.create("omp-relay-keepalive", { periodInMinutes: 0.5 });
|
|
229
|
+
chrome.alarms.onAlarm.addListener((alarm) => {
|
|
230
|
+
if (alarm.name === "omp-relay-keepalive")
|
|
231
|
+
connect();
|
|
232
|
+
});
|
|
233
|
+
chrome.storage.onChanged.addListener((_changes, areaName) => {
|
|
234
|
+
if (areaName !== "local")
|
|
235
|
+
return;
|
|
236
|
+
ws?.close();
|
|
237
|
+
connect();
|
|
238
|
+
});
|
|
239
|
+
chrome.action.onClicked.addListener(() => void chrome.runtime.openOptionsPage());
|
|
240
|
+
chrome.runtime.onInstalled.addListener(() => void connect());
|
|
241
|
+
chrome.runtime.onStartup.addListener(() => void connect());
|
|
242
|
+
connect();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "OMP Browser Relay",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Lets the omp coding agent drive your existing tabs through a local CDP relay.",
|
|
6
|
+
"permissions": ["debugger", "tabs", "tabGroups", "storage", "alarms"],
|
|
7
|
+
"background": {
|
|
8
|
+
"service_worker": "background.js"
|
|
9
|
+
},
|
|
10
|
+
"options_page": "options.html",
|
|
11
|
+
"action": {
|
|
12
|
+
"default_title": "OMP Browser Relay (click for settings)"
|
|
13
|
+
}
|
|
14
|
+
}
|