@oh-my-pi/pi-coding-agent 16.1.9 → 16.1.10
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/CHANGELOG.md +15 -0
- package/dist/cli.js +3076 -3050
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/edit/streaming.d.ts +5 -5
- package/dist/types/modes/controllers/selector-controller.d.ts +0 -1
- package/dist/types/sdk.d.ts +1 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/tools/browser/aria/aria-snapshot.d.ts +39 -0
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +3 -0
- package/dist/types/tools/browser.d.ts +1 -0
- package/dist/types/tools/find.d.ts +1 -2
- package/dist/types/tools/write.d.ts +1 -2
- package/package.json +12 -12
- package/scripts/generate-aria-snapshot.ts +134 -0
- package/src/config/settings-schema.ts +12 -0
- package/src/edit/streaming.ts +5 -5
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/controllers/selector-controller.ts +3 -5
- package/src/prompts/system/project-prompt.md +2 -0
- package/src/prompts/system/system-prompt.md +0 -1
- package/src/prompts/tools/browser.md +2 -0
- package/src/sdk.ts +8 -1
- package/src/system-prompt.ts +15 -3
- package/src/tools/bash.ts +3 -3
- package/src/tools/browser/aria/aria-snapshot.bundle.txt +7 -0
- package/src/tools/browser/aria/aria-snapshot.ts +103 -0
- package/src/tools/browser/cmux/cmux-tab.ts +36 -1
- package/src/tools/browser/tab-worker.ts +89 -17
- package/src/tools/browser.ts +5 -0
- package/src/tools/find.ts +1 -2
- package/src/tools/index.ts +1 -1
- package/src/tools/write.ts +1 -2
- package/src/utils/git.ts +3 -2
|
@@ -738,6 +738,26 @@ export class EventController {
|
|
|
738
738
|
this.ctx.chatContainer.addChild(component);
|
|
739
739
|
this.ctx.pendingTools.set(event.toolCallId, component);
|
|
740
740
|
this.ctx.ui.requestRender();
|
|
741
|
+
} else {
|
|
742
|
+
// The tool is about to run, so its arguments are final and validated.
|
|
743
|
+
// A pending component created while args streamed (message_update) may
|
|
744
|
+
// still show a mid-reveal prefix — or, when the closing full-args
|
|
745
|
+
// `message_update` never lands (smooth-streaming off leaving the
|
|
746
|
+
// throttled `arguments` stale, an owned-dialect projector, or a
|
|
747
|
+
// superseded/aborted turn that still executes the call), a stale body
|
|
748
|
+
// the result render then freezes at its `…` placeholder. Reconcile the
|
|
749
|
+
// authoritative args here and drop any live reveal so a late tick can't
|
|
750
|
+
// re-truncate them: tool_execution_start is the one event every
|
|
751
|
+
// execution path emits with the full args immediately before the result.
|
|
752
|
+
this.#toolArgsReveal.finish(event.toolCallId);
|
|
753
|
+
const component = this.ctx.pendingTools.get(event.toolCallId);
|
|
754
|
+
if (component && typeof component.updateArgs === "function") {
|
|
755
|
+
component.updateArgs(event.args, event.toolCallId);
|
|
756
|
+
if (typeof component.setArgsComplete === "function") {
|
|
757
|
+
component.setArgsComplete(event.toolCallId);
|
|
758
|
+
}
|
|
759
|
+
this.ctx.ui.requestRender();
|
|
760
|
+
}
|
|
741
761
|
}
|
|
742
762
|
}
|
|
743
763
|
|
|
@@ -71,10 +71,6 @@ import { buildCopyTargets } from "../utils/copy-targets";
|
|
|
71
71
|
|
|
72
72
|
const MANUAL_LOGIN_TIP = "Tip: You can complete pairing with /login <redirect URL>.";
|
|
73
73
|
|
|
74
|
-
export function formatTemporaryModelStatus(modelLabel: string, roleSelectorHint = "Alt+M"): string {
|
|
75
|
-
return `Temporary model selection is session-only: ${modelLabel}. Use ${roleSelectorHint} or /model for role models (default/smol/plan/task/slow/custom roles).`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
74
|
export class SelectorController {
|
|
79
75
|
constructor(private ctx: InteractiveModeContext) {}
|
|
80
76
|
|
|
@@ -499,7 +495,9 @@ export class SelectorController {
|
|
|
499
495
|
this.ctx.statusLine.invalidate();
|
|
500
496
|
this.ctx.updateEditorBorderColor();
|
|
501
497
|
const roleSelectorHint = this.ctx.keybindings.getKeys("app.model.select")[0] ?? "Alt+M";
|
|
502
|
-
this.ctx.showStatus(
|
|
498
|
+
this.ctx.showStatus(
|
|
499
|
+
`Session-only model: ${selector ?? model.id}. Use ${roleSelectorHint} or /model for roles.`,
|
|
500
|
+
);
|
|
503
501
|
done();
|
|
504
502
|
this.ctx.ui.requestRender();
|
|
505
503
|
} else if (role === "default") {
|
|
@@ -29,6 +29,7 @@ Before making changes within these directories, you MUST read:
|
|
|
29
29
|
The context files above are loaded automatically. You NEVER `search`/`find` for `AGENTS.md`, `CLAUDE.md`, `.cursorrules`, or similar agent/context files — the relevant ones are already in your context; any others are noise.
|
|
30
30
|
{{/ifAny}}
|
|
31
31
|
|
|
32
|
+
{{#if includeWorkspaceTree}}
|
|
32
33
|
{{#if workspaceTree.rendered}}
|
|
33
34
|
<workspace-tree>
|
|
34
35
|
Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
|
@@ -38,6 +39,7 @@ Working directory layout (sorted by mtime, recent first; depth ≤ 3):
|
|
|
38
39
|
{{/if}}
|
|
39
40
|
</workspace-tree>
|
|
40
41
|
{{/if}}
|
|
42
|
+
{{/if}}
|
|
41
43
|
|
|
42
44
|
Today is {{date}}, and the current working directory is '{{cwd}}'.
|
|
43
45
|
|
|
@@ -17,7 +17,6 @@ You are a helpful assistant the team trusts with load-bearing changes, operating
|
|
|
17
17
|
- You are not alone in this repo. Treat unexpected changes as the user's work and adapt.
|
|
18
18
|
- In terminal prose and final chat, you MAY use LaTeX math (`$`, `$$`, `\text`, `\times`) and color (`\textcolor`, `\colorbox`, `\fcolorbox`).
|
|
19
19
|
- To show a diagram, you MAY emit a ` ```mermaid ` block — the terminal renders it as ASCII. Use it for genuine structure or flow, not trivia.
|
|
20
|
-
- For a visual separator between sections, use `─` (U+2500).
|
|
21
20
|
|
|
22
21
|
RUNTIME
|
|
23
22
|
==============
|
|
@@ -15,6 +15,8 @@ Drives real Chromium tab; full puppeteer access via JS.
|
|
|
15
15
|
- `tab` helpers; drop to raw puppeteer `page` for anything uncovered:
|
|
16
16
|
- `tab.goto(url, { waitUntil? })` — navigate.
|
|
17
17
|
- `tab.observe({ includeAll?, viewportOnly? })` — accessibility snapshot: `{ url, title, viewport, scroll, elements: [{ id, role, name, value, states, … }] }`. Ids stable until next observe/goto.
|
|
18
|
+
- `tab.ariaSnapshot(selector?, { depth?, boxes? })` — Playwright-format ARIA-tree YAML (nested roles + accessible names + `/url`/`/placeholder`), scoped to `selector` or the whole document. Every node carries a `[ref=eN]` id; `[cursor=pointer]` flags clickables. Captures dense, hierarchical structure/text that `observe()`'s flat list flattens away. Refs renumber from e1 each call and stay valid until the next `ariaSnapshot()`.
|
|
19
|
+
- `tab.ref("e5")` — `[ref=eN]` from the last ariaSnapshot → element handle with the common action methods (`.click()`, `.type()`, `.fill()`, `.hover()`, `.evaluate()`, …); the primary way to act on a ref. For convenience `aria-ref=e5` also works inline in `tab.click`/`type`/`fill`/`waitFor`/`scrollIntoView` (e.g. `tab.click("aria-ref=e5")`).
|
|
18
20
|
- `tab.id(n)` — id from last observe → `ElementHandle` (`.click()`, `.type()`, …).
|
|
19
21
|
- `tab.click(selector)` / `tab.type(selector, text)` / `tab.fill(selector, value)` / `tab.press(key, { selector? })` / `tab.scroll(dx, dy)`.
|
|
20
22
|
- `tab.waitFor(selector)` — wait until attached; returns `ElementHandle`.
|
package/src/sdk.ts
CHANGED
|
@@ -796,6 +796,7 @@ export interface BuildSystemPromptOptions {
|
|
|
796
796
|
customPrompt?: string;
|
|
797
797
|
appendPrompt?: string;
|
|
798
798
|
inlineToolDescriptors?: boolean;
|
|
799
|
+
includeWorkspaceTree?: boolean;
|
|
799
800
|
}
|
|
800
801
|
|
|
801
802
|
/**
|
|
@@ -813,6 +814,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
813
814
|
contextFiles: options.contextFiles,
|
|
814
815
|
appendSystemPrompt: options.appendPrompt,
|
|
815
816
|
inlineToolDescriptors: options.inlineToolDescriptors,
|
|
817
|
+
includeWorkspaceTree: options.includeWorkspaceTree,
|
|
816
818
|
toolNames: options.tools?.map(tool => tool.name),
|
|
817
819
|
tools: toolMap ? buildSystemPromptToolMetadata(toolMap) : undefined,
|
|
818
820
|
});
|
|
@@ -1120,9 +1122,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1120
1122
|
// startup does not perform a second recursive filesystem search. Subagents
|
|
1121
1123
|
// inherit the parent's resolved values via options.
|
|
1122
1124
|
const STARTUP_SCAN_DEADLINE_MS = 5000;
|
|
1125
|
+
const includeWorkspaceTree = settings.get("includeWorkspaceTree") ?? false;
|
|
1123
1126
|
const workspaceTreePromise: Promise<WorkspaceTree> = options.workspaceTree
|
|
1124
1127
|
? Promise.resolve(options.workspaceTree)
|
|
1125
|
-
:
|
|
1128
|
+
: includeWorkspaceTree
|
|
1129
|
+
? logger.time("buildWorkspaceTree", () => buildWorkspaceTree(cwd, { timeoutMs: STARTUP_SCAN_DEADLINE_MS }))
|
|
1130
|
+
: Promise.resolve({ rootPath: cwd, rendered: "", truncated: false, totalLines: 0, agentsMdFiles: [] });
|
|
1126
1131
|
workspaceTreePromise.catch(() => {});
|
|
1127
1132
|
|
|
1128
1133
|
// Independent discoveries that depend only on cwd/agentDir — kicked off in parallel and awaited
|
|
@@ -2101,6 +2106,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2101
2106
|
const eagerTasks = settings.get("task.eager") !== "default";
|
|
2102
2107
|
const eagerTasksAlways = settings.get("task.eager") === "always";
|
|
2103
2108
|
const intentField = $flag("PI_INTENT_TRACING", settings.get("tools.intentTracing")) ? INTENT_FIELD : undefined;
|
|
2109
|
+
const includeWorkspaceTree = settings.get("includeWorkspaceTree") ?? false;
|
|
2104
2110
|
const rebuildSystemPrompt = async (
|
|
2105
2111
|
toolNames: string[],
|
|
2106
2112
|
tools: Map<string, AgentTool>,
|
|
@@ -2194,6 +2200,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2194
2200
|
taskBatch: settings.get("task.batch"),
|
|
2195
2201
|
secretsEnabled,
|
|
2196
2202
|
workspaceTree: workspaceTreePromise,
|
|
2203
|
+
includeWorkspaceTree,
|
|
2197
2204
|
memoryRootEnabled: memoryBackend.id === "local",
|
|
2198
2205
|
model: settings.get("includeModelInPrompt") ? getActiveModelString() : undefined,
|
|
2199
2206
|
personality: agentKind === "sub" ? "none" : settings.get("personality"),
|
package/src/system-prompt.ts
CHANGED
|
@@ -421,6 +421,8 @@ export interface BuildSystemPromptOptions {
|
|
|
421
421
|
model?: string;
|
|
422
422
|
/** Personality preset rendered into the default system prompt. "none" omits the block. Default: "default" */
|
|
423
423
|
personality?: Personality;
|
|
424
|
+
/** Whether to include the workspace directory tree in the system prompt. Default: false */
|
|
425
|
+
includeWorkspaceTree?: boolean;
|
|
424
426
|
}
|
|
425
427
|
|
|
426
428
|
/** Result of building provider-facing system prompt messages. */
|
|
@@ -461,6 +463,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
461
463
|
memoryRootEnabled = false,
|
|
462
464
|
model,
|
|
463
465
|
personality = "default",
|
|
466
|
+
includeWorkspaceTree = false,
|
|
464
467
|
} = options;
|
|
465
468
|
const inlineToolDescriptors = providedInlineToolDescriptors ?? false;
|
|
466
469
|
const resolvedCwd = cwd ?? getProjectDir();
|
|
@@ -523,9 +526,17 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
523
526
|
const workspaceTreePromise =
|
|
524
527
|
providedWorkspaceTree !== undefined
|
|
525
528
|
? Promise.resolve(providedWorkspaceTree)
|
|
526
|
-
:
|
|
527
|
-
|
|
528
|
-
|
|
529
|
+
: includeWorkspaceTree
|
|
530
|
+
? logger.time("buildWorkspaceTree", () =>
|
|
531
|
+
buildWorkspaceTree(resolvedCwd, { timeoutMs: SYSTEM_PROMPT_PREP_TIMEOUT_MS }),
|
|
532
|
+
)
|
|
533
|
+
: Promise.resolve({
|
|
534
|
+
rootPath: resolvedCwd,
|
|
535
|
+
rendered: "",
|
|
536
|
+
truncated: false,
|
|
537
|
+
totalLines: 0,
|
|
538
|
+
agentsMdFiles: [],
|
|
539
|
+
});
|
|
529
540
|
const skillsPromise: Promise<Skill[]> =
|
|
530
541
|
providedSkills !== undefined
|
|
531
542
|
? Promise.resolve(providedSkills)
|
|
@@ -670,6 +681,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
670
681
|
secretsEnabled,
|
|
671
682
|
hasMemoryRoot: memoryRootEnabled,
|
|
672
683
|
hasObsidian: hasObsidian(),
|
|
684
|
+
includeWorkspaceTree,
|
|
673
685
|
};
|
|
674
686
|
const rendered = prompt.render(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
|
675
687
|
const systemPrompt = [rendered];
|
package/src/tools/bash.ts
CHANGED
|
@@ -1132,9 +1132,9 @@ function getPartialJson<TArgs>(args: TArgs | undefined): string | undefined {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
|
|
1134
1134
|
export function getBashEnvForDisplay(args: BashRenderArgs): Record<string, string> | undefined {
|
|
1135
|
-
//
|
|
1136
|
-
//
|
|
1137
|
-
//
|
|
1135
|
+
// The parsed args don't always mirror the exact current stream prefix, so recover
|
|
1136
|
+
// env from the raw JSON buffer to surface `NAME="..." cmd` in the preview as it
|
|
1137
|
+
// streams rather than only once the args object finishes.
|
|
1138
1138
|
const partialEnv = extractPartialBashEnv(args.__partialJson);
|
|
1139
1139
|
if (partialEnv && args.env) return { ...partialEnv, ...args.env };
|
|
1140
1140
|
return args.env ?? partialEnv;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// @generated by scripts/generate-aria-snapshot.ts from Playwright v1.61.0
|
|
2
|
+
// Bundled from Playwright's injected ARIA-snapshot sources (Apache-2.0, (c) Microsoft).
|
|
3
|
+
// Do not edit by hand. Regenerate with: bun scripts/generate-aria-snapshot.ts
|
|
4
|
+
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`
|
|
5
|
+
`: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,`
|
|
6
|
+
`).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(`
|
|
7
|
+
`),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}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { ElementHandle, JSHandle, Page } from "puppeteer-core";
|
|
2
|
+
import ariaBundle from "./aria-snapshot.bundle.txt" with { type: "text" };
|
|
3
|
+
// `aria-snapshot.bundle.txt` is a generated, committed artifact: Playwright's
|
|
4
|
+
// injected ARIA-snapshot sources (pinned, Apache-2.0) bundled to a CJS module.
|
|
5
|
+
// The upstream sources are NOT vendored — regenerate the bundle with:
|
|
6
|
+
// bun scripts/generate-aria-snapshot.ts
|
|
7
|
+
// (fetches the pinned tag, bundles in a temp dir, rewrites the .txt artifact.)
|
|
8
|
+
|
|
9
|
+
export interface AriaSnapshotOptions {
|
|
10
|
+
/** Maximum tree depth to render. */
|
|
11
|
+
depth?: number;
|
|
12
|
+
/** Append `[box=x,y,w,h]` bounding boxes to each node. */
|
|
13
|
+
boxes?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Page-side evaluators built ONCE here in the worker — never inside the page, so
|
|
18
|
+
* page CSP never applies. They run the generated Playwright ARIA-snapshot bundle
|
|
19
|
+
* (CJS, see scripts/generate-aria-snapshot.ts) in a throwaway module scope.
|
|
20
|
+
*
|
|
21
|
+
* Puppeteer serializes these functions to a CDP `Runtime.evaluate` in the page's
|
|
22
|
+
* MAIN world (the only world where the bundle's `_ariaRef` ref expandos live —
|
|
23
|
+
* isolated-world locators/query-handlers cannot see them). Nothing is installed
|
|
24
|
+
* on `window`; the only footprint is the `_ariaRef` markers the snapshot writes,
|
|
25
|
+
* which are the price of actionable `[ref=eN]` ids.
|
|
26
|
+
*/
|
|
27
|
+
function buildEvaluator(params: string, call: string): (...args: unknown[]) => unknown {
|
|
28
|
+
return new Function(
|
|
29
|
+
...params.split(",").map(p => p.trim()),
|
|
30
|
+
`var module = { exports: {} };\n${ariaBundle}\nreturn module.exports.${call};`,
|
|
31
|
+
) as unknown as (...args: unknown[]) => unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handles (root) must stay top-level args: Puppeteer only unwraps JSHandles
|
|
35
|
+
// passed positionally to page.evaluate, never ones nested inside an object.
|
|
36
|
+
const evaluateAriaSnapshot = buildEvaluator("root, request", "ariaSnapshot(root, request)");
|
|
37
|
+
const evaluateResolveRef = buildEvaluator("ref", "resolveAriaRef(ref)");
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Capture a Playwright-format ARIA snapshot of `root` (or the whole document when
|
|
41
|
+
* null). Always runs in `ai` mode so every node carries a `[ref=eN]` id; resolve
|
|
42
|
+
* those to elements with {@link resolveAriaRefHandle}. Ids are renumbered from e1
|
|
43
|
+
* on each call and remain valid until the next snapshot.
|
|
44
|
+
*/
|
|
45
|
+
export async function captureAriaSnapshot(
|
|
46
|
+
page: Page,
|
|
47
|
+
root: ElementHandle | null,
|
|
48
|
+
options: AriaSnapshotOptions = {},
|
|
49
|
+
): Promise<string> {
|
|
50
|
+
const request = { depth: options.depth, boxes: options.boxes };
|
|
51
|
+
return (await page.evaluate(evaluateAriaSnapshot as never, root as never, request as never)) as string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a `[ref=eN]` id from the latest snapshot to a live `ElementHandle`, or
|
|
56
|
+
* null when the ref no longer matches any element. Runs in the main world so it
|
|
57
|
+
* sees the `_ariaRef` expandos the snapshot wrote.
|
|
58
|
+
*/
|
|
59
|
+
export async function resolveAriaRefHandle(page: Page, ref: string): Promise<ElementHandle | null> {
|
|
60
|
+
const handle = (await page.evaluateHandle(evaluateResolveRef as never, ref as never)) as JSHandle;
|
|
61
|
+
const element = handle.asElement();
|
|
62
|
+
if (!element) {
|
|
63
|
+
await handle.dispose().catch(() => undefined);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return element as ElementHandle;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const ARIA_REF_PREFIXES = ["aria-ref=", "aria-ref/", "ariaref/"];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Recognize the explicit `[ref=eN]` selector forms and return the bare ref id,
|
|
73
|
+
* else null. Accepts `aria-ref=e5` (Playwright-MCP style), `aria-ref/e5`, and
|
|
74
|
+
* `ariaref/e5` — lets `tab.click("aria-ref=e5")` etc. act on snapshot refs. A
|
|
75
|
+
* bare `e5` is intentionally NOT a ref selector: the cmux backend already uses
|
|
76
|
+
* bare `eN`/`@eN` for its own observe ids, so requiring the prefix keeps action
|
|
77
|
+
* selectors meaning the same thing on both backends. (`tab.ref("e5")` still
|
|
78
|
+
* accepts a bare id directly.)
|
|
79
|
+
*/
|
|
80
|
+
export function parseAriaRefSelector(selector: string): string | null {
|
|
81
|
+
const trimmed = selector.trim();
|
|
82
|
+
for (const prefix of ARIA_REF_PREFIXES) {
|
|
83
|
+
if (trimmed.startsWith(prefix)) {
|
|
84
|
+
const id = trimmed.slice(prefix.length).trim();
|
|
85
|
+
return /^e\d+$/.test(id) ? id : null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Build a self-contained expression script that runs the vendored bundle in the
|
|
93
|
+
* page and returns the ARIA snapshot YAML. Used by the cmux backend, whose
|
|
94
|
+
* `browser.eval` RPC takes a script string and returns the completion value (it
|
|
95
|
+
* has no ElementHandle to pass in). The script resolves `selector` via
|
|
96
|
+
* `document.querySelector` in-page (CSS selectors only) or falls back to the
|
|
97
|
+
* whole document. Like the puppeteer path it installs nothing on `window`.
|
|
98
|
+
*/
|
|
99
|
+
export function buildAriaSnapshotScript(selector: string | undefined, options: AriaSnapshotOptions = {}): string {
|
|
100
|
+
const request = { depth: options.depth, boxes: options.boxes };
|
|
101
|
+
const sel = selector ? JSON.stringify(selector) : "null";
|
|
102
|
+
return `(function(){var module={exports:{}};\n${ariaBundle}\nvar __sel=${sel};var __root=__sel?document.querySelector(__sel):null;if(__sel&&!__root)throw new Error("tab.ariaSnapshot: selector "+__sel+" matched no element");return module.exports.ariaSnapshot(__root,${JSON.stringify(request)});})()`;
|
|
103
|
+
}
|
|
@@ -10,6 +10,7 @@ import { resizeImage } from "../../../utils/image-resize";
|
|
|
10
10
|
import { resolveToCwd } from "../../path-utils";
|
|
11
11
|
import { formatScreenshot } from "../../render-utils";
|
|
12
12
|
import { ToolAbortError, ToolError } from "../../tool-errors";
|
|
13
|
+
import { type AriaSnapshotOptions, buildAriaSnapshotScript } from "../aria/aria-snapshot";
|
|
13
14
|
import { DEFAULT_VIEWPORT } from "../launch";
|
|
14
15
|
import { extractReadableFromHtml, type ReadableFormat } from "../readable";
|
|
15
16
|
import type { Observation, ReadyInfo, RunResultOk, ScreenshotResult, SessionSnapshot } from "../tab-protocol";
|
|
@@ -49,7 +50,7 @@ interface RunContext {
|
|
|
49
50
|
|
|
50
51
|
type WaitUntil = "load" | "domcontentloaded" | "networkidle0" | "networkidle2";
|
|
51
52
|
type DragTarget = string | { readonly x: number; readonly y: number };
|
|
52
|
-
type SelectorKind = "css" | "ref" | "text" | "aria" | "xpath" | "pierce" | "ax";
|
|
53
|
+
type SelectorKind = "css" | "ref" | "aria-ref" | "text" | "aria" | "xpath" | "pierce" | "ax";
|
|
53
54
|
|
|
54
55
|
interface SelectorSpec {
|
|
55
56
|
kind: SelectorKind;
|
|
@@ -124,6 +125,20 @@ const accessibleName = element =>
|
|
|
124
125
|
const findElement = spec => {
|
|
125
126
|
if (spec.kind === "css") return document.querySelector(spec.value);
|
|
126
127
|
if (spec.kind === "pierce") return pierceQuery(document, spec.value);
|
|
128
|
+
if (spec.kind === "aria-ref") {
|
|
129
|
+
const wanted = spec.value;
|
|
130
|
+
const scan = root => {
|
|
131
|
+
for (const el of Array.from(root.querySelectorAll("*"))) {
|
|
132
|
+
if (el._ariaRef && el._ariaRef.ref === wanted) return el;
|
|
133
|
+
if (el.shadowRoot) {
|
|
134
|
+
const found = scan(el.shadowRoot);
|
|
135
|
+
if (found) return found;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
return scan(document);
|
|
141
|
+
}
|
|
127
142
|
if (spec.kind === "xpath") {
|
|
128
143
|
const result = document.evaluate(spec.value, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
129
144
|
return result.singleNodeValue instanceof Element ? result.singleNodeValue : null;
|
|
@@ -352,6 +367,24 @@ export class CmuxTab {
|
|
|
352
367
|
return observation;
|
|
353
368
|
}
|
|
354
369
|
|
|
370
|
+
async ariaSnapshot(selector?: string, opts?: AriaSnapshotOptions): Promise<string> {
|
|
371
|
+
const timeoutMs = Math.min(this.#runContext?.timeoutMs ?? 30_000, 30_000);
|
|
372
|
+
const result = (await this.#request(
|
|
373
|
+
"browser.eval",
|
|
374
|
+
{ script: buildAriaSnapshotScript(selector, opts) },
|
|
375
|
+
timeoutMs,
|
|
376
|
+
)) as CmuxEvalResult;
|
|
377
|
+
return result.value as string;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async ref(id: string): Promise<CmuxElementHandle> {
|
|
381
|
+
const refId = /^e\d+$/.test(id.trim()) ? id.trim() : id.trim().replace(/^(?:aria-ref=|aria-ref\/|ariaref\/)/, "");
|
|
382
|
+
const selector = `aria-ref=${refId}`;
|
|
383
|
+
const timeoutMs = this.#runContext?.timeoutMs ?? 30_000;
|
|
384
|
+
await this.#waitForSelector(selector, timeoutMs);
|
|
385
|
+
return new CmuxElementHandle(this, selector);
|
|
386
|
+
}
|
|
387
|
+
|
|
355
388
|
async click(selector: string): Promise<void> {
|
|
356
389
|
await this.#selectorAction(selector, "click");
|
|
357
390
|
}
|
|
@@ -893,6 +926,8 @@ export class CmuxTab {
|
|
|
893
926
|
else if (normalized.startsWith("p-aria/")) normalized = `aria/${normalized.slice("p-aria/".length)}`;
|
|
894
927
|
else if (normalized.startsWith("p-xpath/")) normalized = `xpath/${normalized.slice("p-xpath/".length)}`;
|
|
895
928
|
else if (normalized.startsWith("p-pierce/")) normalized = `pierce/${normalized.slice("p-pierce/".length)}`;
|
|
929
|
+
const ariaRef = /^(?:aria-ref=|aria-ref\/|ariaref\/)(e\d+)$/.exec(normalized);
|
|
930
|
+
if (ariaRef) return { kind: "aria-ref", value: ariaRef[1]!, raw };
|
|
896
931
|
const ref = /^@?e(\d+)$/.exec(normalized);
|
|
897
932
|
if (ref) return { kind: "ref", value: ref[1]!, raw, ref: `@e${ref[1]}` };
|
|
898
933
|
const slash = normalized.indexOf("/");
|