From cd2d33a9f6fded65e2a6124a1244709da5a39380 Mon Sep 17 00:00:00 2001 From: zfangqijun Date: Sat, 21 Mar 2026 20:17:01 +0800 Subject: [PATCH 01/40] chore(page-controller): export actions as internal methods --- packages/page-controller/src/PageController.ts | 2 ++ packages/page-controller/src/actions.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/packages/page-controller/src/PageController.ts b/packages/page-controller/src/PageController.ts index 2f56a73..a8392ae 100644 --- a/packages/page-controller/src/PageController.ts +++ b/packages/page-controller/src/PageController.ts @@ -424,3 +424,5 @@ export class PageController extends EventTarget { this.mask = null } } + +export * from './actions' diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 92bb2b4..92c7388 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -15,6 +15,7 @@ import { /** * Get the HTMLElement by index from a selectorMap. + * @private Internal method, subject to change at any time. */ export function getElementByIndex( selectorMap: Map, @@ -54,6 +55,7 @@ function blurLastClickedElement() { /** * Simulate a click on the element + * @private Internal method, subject to change at any time. */ export async function clickElement(element: HTMLElement) { blurLastClickedElement() @@ -89,6 +91,9 @@ export async function clickElement(element: HTMLElement) { await waitFor(0.2) // Wait to ensure click event processing completes } +/** + * @private Internal method, subject to change at any time. + */ export async function inputTextElement(element: HTMLElement, text: string) { const isContentEditable = element.isContentEditable if (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) { @@ -196,6 +201,7 @@ export async function inputTextElement(element: HTMLElement, text: string) { /** * @todo browser-use version is very complex and supports menu tags, need to follow up + * @private Internal method, subject to change at any time. */ export async function selectOptionElement(selectElement: HTMLSelectElement, optionText: string) { if (!isSelectElement(selectElement)) { @@ -219,6 +225,9 @@ interface ScrollableElement extends Element { scrollIntoViewIfNeeded?: (centerIfNeeded?: boolean) => void } +/** + * @private Internal method, subject to change at any time. + */ export async function scrollIntoViewIfNeeded(element: Element) { const el = element as ScrollableElement if (typeof el.scrollIntoViewIfNeeded === 'function') { @@ -231,6 +240,9 @@ export async function scrollIntoViewIfNeeded(element: Element) { } } +/** + * @private Internal method, subject to change at any time. + */ export async function scrollVertically( down: boolean, scroll_amount: number, @@ -359,6 +371,9 @@ export async function scrollVertically( } } +/** + * @private Internal method, subject to change at any time. + */ export async function scrollHorizontally( right: boolean, scroll_amount: number, From 3456f45590d1fd62886344c27dda86634d1a0c87 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sun, 22 Mar 2026 03:21:33 +0800 Subject: [PATCH 02/40] docs: MCP --- README.md | 2 +- docs/README-zh.md | 13 ++-- .../src/components/LanguageSwitcher.tsx | 2 +- packages/website/src/pages/docs/Layout.tsx | 1 + .../pages/docs/features/mcp-server/page.tsx | 70 +++++++++++++++++++ .../src/pages/docs/features/models/page.tsx | 2 +- packages/website/src/pages/docs/index.tsx | 6 ++ .../src/pages/home/OneMoreThingSection.tsx | 24 +++++-- packages/website/vite.config.js | 1 + 9 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 packages/website/src/pages/docs/features/mcp-server/page.tsx diff --git a/README.md b/README.md index 7a9dd89..5e698bb 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua - **📖 Text-based DOM manipulation** - No screenshots. No multi-modal LLMs or special permissions needed. - **🧠 Bring your own LLMs** -- **🎨 Pretty UI with human-in-the-loop** - **🐙 Optional [chrome extension](https://alibaba.github.io/page-agent/docs/features/chrome-extension) for multi-page tasks.** + - [MCP Server (Beta)](https://alibaba.github.io/page-agent/docs/features/mcp-server) ## 💡 Use Cases diff --git a/docs/README-zh.md b/docs/README-zh.md index 9f6a166..fa6a407 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -20,17 +20,16 @@ ## ✨ Features - **🎯 轻松集成** - - 无需 `浏览器插件` / `Python` / `无头浏览器`。 - - 纯页面内 JavaScript,一切都在你的网页中完成。 + - 无需 `浏览器插件` / `Python` / `无头浏览器`,纯页面内 JavaScript - **📖 基于文本的 DOM 操作** - - 无需截图,无需多模态模型或特殊权限。 -- **🧠 用你自己的 LLM** -- **🎨 精美 UI,支持人机协同** -- **🐙 可选的 [Chrome 扩展](https://alibaba.github.io/page-agent/docs/features/chrome-extension),支持跨页面任务。** + - 无需截图,无需多模态模型或特殊权限 +- **🧠 自备 LLM** +- 🐙 可选的 [Chrome 扩展](https://alibaba.github.io/page-agent/docs/features/chrome-extension),支持跨页面任务 + - [MCP Server (Beta)](https://alibaba.github.io/page-agent/docs/features/mcp-server) ## 💡 应用场景 -- **SaaS AI 副驾驶** — 几行代码为你的产品加上 AI 副驾驶,无需重写后端。 +- **SaaS AI Copilot** — 几行代码为你的产品加上 AI 副驾驶,无需重写后端。 - **智能表单填写** — 把 20 次点击变成一句话。ERP、CRM、管理后台的最佳拍档。 - **无障碍增强** — 用自然语言让任何网页无障碍。语音指令、屏幕阅读器,零门槛。 - **跨页面 Agent** — 通过可选的 [Chrome 扩展](https://alibaba.github.io/page-agent/docs/features/chrome-extension),让你自己的 Agent 跨标签页工作。 diff --git a/packages/website/src/components/LanguageSwitcher.tsx b/packages/website/src/components/LanguageSwitcher.tsx index e5af95d..8c73eff 100644 --- a/packages/website/src/components/LanguageSwitcher.tsx +++ b/packages/website/src/components/LanguageSwitcher.tsx @@ -8,8 +8,8 @@ export default function LanguageSwitcher() { const dropdownRef = useRef(null) const languages = [ - { code: 'zh-CN' as const, label: '中文' }, { code: 'en-US' as const, label: 'English' }, + { code: 'zh-CN' as const, label: '中文' }, ] const currentLanguage = languages.find((lang) => lang.code === language) || languages[0] diff --git a/packages/website/src/pages/docs/Layout.tsx b/packages/website/src/pages/docs/Layout.tsx index e9abee8..44292e3 100644 --- a/packages/website/src/pages/docs/Layout.tsx +++ b/packages/website/src/pages/docs/Layout.tsx @@ -45,6 +45,7 @@ export default function DocsLayout({ children }: DocsLayoutProps) { { title: isZh ? '知识注入' : 'Instructions', path: '/features/custom-instructions' }, { title: isZh ? '数据脱敏' : 'Data Masking', path: '/features/data-masking' }, { title: isZh ? 'Chrome 扩展' : 'Chrome Extension', path: '/features/chrome-extension' }, + { title: 'MCP Server (Beta)', path: '/features/mcp-server' }, { title: isZh ? '接入第三方 Agent' : 'Third-party Agent', path: '/features/third-party-agent', diff --git a/packages/website/src/pages/docs/features/mcp-server/page.tsx b/packages/website/src/pages/docs/features/mcp-server/page.tsx new file mode 100644 index 0000000..b31454f --- /dev/null +++ b/packages/website/src/pages/docs/features/mcp-server/page.tsx @@ -0,0 +1,70 @@ +import BetaNotice from '@/components/BetaNotice' +import CodeEditor from '@/components/CodeEditor' +import { Heading } from '@/components/Heading' + +export default function McpServerPage() { + return ( +
+

MCP Server (Beta)

+ +

+ Use the MCP server to let your local agent send natural-language browser tasks to Page Agent + Ext. +

+ +
+ + How to use + +
+
+

+ 1. Install Page Agent Ext in Chrome. +
+ 2. Add the MCP server to your local agent client. +
+ 3. Start the client and approve the Hub connection in the browser when prompted. +
+ 4. Ask your agent to do something in the browser. The client will call execute_task + for you. +

+
+ + +
+
+ +
+ + The Hub + + +

+ The Hub is the control center for communication between Page Agent Ext and external + callers. +

+

+ When the MCP server starts, it opens a local launcher page. The launcher asks the + extension to open the Hub tab, and the Hub receives tasks from your local agent. MCP uses + this path, but the Hub itself is the extension's general external communication entry + point. +

+
+
+ ) +} diff --git a/packages/website/src/pages/docs/features/models/page.tsx b/packages/website/src/pages/docs/features/models/page.tsx index 2dc0c37..f427b0d 100644 --- a/packages/website/src/pages/docs/features/models/page.tsx +++ b/packages/website/src/pages/docs/features/models/page.tsx @@ -33,8 +33,8 @@ const MODEL_GROUPS: Record = { 'claude-haiku-4.5', 'claude-sonnet-3.5', ], - xAI: ['grok-4.1-fast', 'grok-4', 'grok-code-fast'], MiniMax: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed', 'MiniMax-M2.5', 'MiniMax-M2.5-highspeed'], + xAI: ['grok-4.1-fast', 'grok-4', 'grok-code-fast'], MoonshotAI: ['kimi-k2.5'], 'Z.AI': ['glm-5', 'glm-4.7'], } diff --git a/packages/website/src/pages/docs/index.tsx b/packages/website/src/pages/docs/index.tsx index 868f27a..a614ca1 100644 --- a/packages/website/src/pages/docs/index.tsx +++ b/packages/website/src/pages/docs/index.tsx @@ -13,6 +13,7 @@ import ChromeExtension from './features/chrome-extension/page' import Instructions from './features/custom-instructions/page' import CustomTools from './features/custom-tools/page' import DataMasking from './features/data-masking/page' +import McpServerPage from './features/mcp-server/page' import Models from './features/models/page' import ThirdPartyAgent from './features/third-party-agent/page' import Limitations from './introduction/limitations/page' @@ -80,6 +81,11 @@ export default function DocsRouter() { + + + + + diff --git a/packages/website/src/pages/home/OneMoreThingSection.tsx b/packages/website/src/pages/home/OneMoreThingSection.tsx index 10e338b..767de48 100644 --- a/packages/website/src/pages/home/OneMoreThingSection.tsx +++ b/packages/website/src/pages/home/OneMoreThingSection.tsx @@ -58,6 +58,22 @@ export default function OneMoreThingSection() { +
+

+ {isZh + ? '从 Claude Desktop、Copilot 或其他本地 Agent 直接发起浏览器任务?' + : 'Using Claude Desktop, Copilot, or another local agent? Connect it to the extension with the MCP server.'} +

+

+ + {isZh ? '查看 MCP 文档' : 'Read the MCP docs'} + +

+
+
{[ { @@ -67,16 +83,16 @@ export default function OneMoreThingSection() { : 'Run tasks across multiple pages and tabs without being limited to a single page context', }, { - title: isZh ? '页面内发起控制' : 'Control from Your Page', + title: isZh ? '从页面发起控制' : 'Control from a WebPage', desc: isZh ? '在页面 JS 中发起任务,驱动整个浏览器完成跨标签操作' - : 'Trigger tasks from page JS to drive the entire browser across tabs', + : 'Trigger tasks from in-page JS to drive the entire browser across tabs', }, { - title: isZh ? '外部发起任务' : 'External Triggers', + title: isZh ? '外部发起任务' : 'External Caller', desc: isZh ? '页面 JS、本地 Agent 或云端 Agent 均可通过扩展发起任务' - : 'Page JS, local agents, or cloud agents can trigger tasks through the extension', + : 'Local agents and cloud agents can control user browser through the extension', }, ].map((item) => ( Date: Sun, 22 Mar 2026 03:27:17 +0800 Subject: [PATCH 03/40] chore(mcp): opt descriptions --- packages/mcp/src/index.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/mcp/src/index.js b/packages/mcp/src/index.js index d88211e..2661b6c 100755 --- a/packages/mcp/src/index.js +++ b/packages/mcp/src/index.js @@ -35,11 +35,14 @@ const mcpServer = new McpServer({ name: 'page-agent', version: '1.5.8' }) mcpServer.registerTool( 'execute_task', { - description: - 'Execute a browser automation task described in natural language. ' + - 'The Page Agent extension will control the browser to complete the task. ' + - 'Blocks until the task is complete.', - inputSchema: { task: z.string().describe('Task description in natural language') }, + description: "Execute a task in user's browser.", + inputSchema: { + task: z + .string() + .describe( + 'Task description. Give specific instructions for the task. Steps preferable. And the information you want to get after the task is done.' + ), + }, }, async ({ task }) => { try { @@ -50,7 +53,7 @@ mcpServer.registerTool( { type: 'text', text: result.success - ? `Task completed successfully.\n\n${result.data}` + ? `Task completed.\n\n${result.data}` : `Task failed.\n\n${result.data}`, }, ], @@ -67,7 +70,7 @@ mcpServer.registerTool( mcpServer.registerTool( 'get_status', { - description: 'Check the current status of the Page Agent hub connection and agent.', + description: 'Check the current status of the Page Agent hub.', }, async () => ({ content: [ From eede819ea855d3f47aa0342fe8959ffbb22d58d6 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sun, 22 Mar 2026 03:27:51 +0800 Subject: [PATCH 04/40] chore(version): bump version to 1.6.1 --- README.md | 4 +-- docs/README-zh.md | 4 +-- package-lock.json | 40 +++++++++++++-------------- package.json | 2 +- packages/core/package.json | 6 ++-- packages/extension/package.json | 10 +++---- packages/llms/package.json | 2 +- packages/mcp/package.json | 2 +- packages/page-agent/package.json | 10 +++---- packages/page-controller/package.json | 2 +- packages/ui/package.json | 2 +- packages/website/package.json | 2 +- packages/website/src/constants.ts | 4 +-- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 5e698bb..60fe829 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ Fastest way to try PageAgent with our free Demo LLM: | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.0/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.0/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js | ### NPM Installation diff --git a/docs/README-zh.md b/docs/README-zh.md index fa6a407..e51c25c 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -48,8 +48,8 @@ | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.0/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.0/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js | ### NPM 安装 diff --git a/package-lock.json b/package-lock.json index 1ed40cf..8194ed2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "root", - "version": "1.6.0", + "version": "1.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "root", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "workspaces": [ "packages/page-controller", @@ -11799,11 +11799,11 @@ }, "packages/core": { "name": "@page-agent/core", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "dependencies": { - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0", + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1", "chalk": "^5.6.2" }, "devDependencies": { @@ -11815,13 +11815,13 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "1.6.0", + "version": "1.6.1", "hasInstallScript": true, "dependencies": { - "@page-agent/core": "1.6.0", - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0", - "@page-agent/ui": "1.6.0", + "@page-agent/core": "1.6.1", + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1", + "@page-agent/ui": "1.6.1", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, @@ -11858,7 +11858,7 @@ }, "packages/llms": { "name": "@page-agent/llms", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "dependencies": { "chalk": "^5.6.2" @@ -11872,7 +11872,7 @@ }, "packages/mcp": { "name": "@page-agent/mcp", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", @@ -11887,13 +11887,13 @@ } }, "packages/page-agent": { - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "dependencies": { - "@page-agent/core": "1.6.0", - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0", - "@page-agent/ui": "1.6.0", + "@page-agent/core": "1.6.1", + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1", + "@page-agent/ui": "1.6.1", "chalk": "^5.6.2" }, "devDependencies": { @@ -11905,7 +11905,7 @@ }, "packages/page-controller": { "name": "@page-agent/page-controller", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT", "dependencies": { "ai-motion": "^0.4.8" @@ -11913,12 +11913,12 @@ }, "packages/ui": { "name": "@page-agent/ui", - "version": "1.6.0", + "version": "1.6.1", "license": "MIT" }, "packages/website": { "name": "@page-agent/website", - "version": "1.6.0", + "version": "1.6.1", "devDependencies": { "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-separator": "^1.1.8", diff --git a/package.json b/package.json index 21b827b..93fe042 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "root", "private": true, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "workspaces": [ "packages/page-controller", diff --git a/packages/core/package.json b/packages/core/package.json index bca9c1c..555fdc8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/core", "private": false, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "main": "./dist/esm/page-agent-core.js", "module": "./dist/esm/page-agent-core.js", @@ -44,8 +44,8 @@ }, "dependencies": { "chalk": "^5.6.2", - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0" + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" diff --git a/packages/extension/package.json b/packages/extension/package.json index d7e312e..8ad646d 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "scripts": { "dev": "wxt", @@ -37,10 +37,10 @@ "wxt": "^0.20.19" }, "dependencies": { - "@page-agent/core": "1.6.0", - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0", - "@page-agent/ui": "1.6.0", + "@page-agent/core": "1.6.1", + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1", + "@page-agent/ui": "1.6.1", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, diff --git a/packages/llms/package.json b/packages/llms/package.json index bcf6c4c..bb375a1 100644 --- a/packages/llms/package.json +++ b/packages/llms/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/llms", - "version": "1.6.0", + "version": "1.6.1", "type": "module", "main": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 23d018c..f6e782f 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/mcp", "private": false, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "bin": { "page-agent-mcp": "src/index.js" diff --git a/packages/page-agent/package.json b/packages/page-agent/package.json index 4414a28..1f29cee 100644 --- a/packages/page-agent/package.json +++ b/packages/page-agent/package.json @@ -1,7 +1,7 @@ { "name": "page-agent", "private": false, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "main": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js", @@ -44,10 +44,10 @@ "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" }, "dependencies": { - "@page-agent/core": "1.6.0", - "@page-agent/llms": "1.6.0", - "@page-agent/page-controller": "1.6.0", - "@page-agent/ui": "1.6.0", + "@page-agent/core": "1.6.1", + "@page-agent/llms": "1.6.1", + "@page-agent/page-controller": "1.6.1", + "@page-agent/ui": "1.6.1", "chalk": "^5.6.2" }, "peerDependencies": { diff --git a/packages/page-controller/package.json b/packages/page-controller/package.json index 928a859..f464396 100644 --- a/packages/page-controller/package.json +++ b/packages/page-controller/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/page-controller", - "version": "1.6.0", + "version": "1.6.1", "type": "module", "main": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js", diff --git a/packages/ui/package.json b/packages/ui/package.json index 491ce15..b304f6a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/ui", - "version": "1.6.0", + "version": "1.6.1", "type": "module", "main": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js", diff --git a/packages/website/package.json b/packages/website/package.json index bcb8f46..d5bcfa9 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/website", "private": true, - "version": "1.6.0", + "version": "1.6.1", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/packages/website/src/constants.ts b/packages/website/src/constants.ts index 4d7c5f1..572fb53 100644 --- a/packages/website/src/constants.ts +++ b/packages/website/src/constants.ts @@ -1,8 +1,8 @@ // Demo build (auto-init with demo LLM, for quick testing) export const CDN_DEMO_URL = - 'https://cdn.jsdelivr.net/npm/page-agent@1.6.0/dist/iife/page-agent.demo.js' + 'https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js' export const CDN_DEMO_CN_URL = - 'https://registry.npmmirror.com/page-agent/1.6.0/files/dist/iife/page-agent.demo.js' + 'https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js' // Demo LLM for website testing (homepage quick trial uses flash) export const DEMO_MODEL = 'qwen3.5-flash' From 6dd0ceab73b8e612d0c1be6b53655e9c3ce4e7e5 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sun, 22 Mar 2026 12:49:10 +0800 Subject: [PATCH 05/40] chore: README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60fe829..bc55164 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua - No screenshots. No multi-modal LLMs or special permissions needed. - **🧠 Bring your own LLMs** - **🐙 Optional [chrome extension](https://alibaba.github.io/page-agent/docs/features/chrome-extension) for multi-page tasks.** - - [MCP Server (Beta)](https://alibaba.github.io/page-agent/docs/features/mcp-server) + - And an [MCP Server (Beta)](https://alibaba.github.io/page-agent/docs/features/mcp-server) to control it from outside ## 💡 Use Cases @@ -79,7 +79,7 @@ We welcome contributions from the community! Follow our instructions in [CONTRIB Please read [Code of Conduct](docs/CODE_OF_CONDUCT.md) before contributing. -Contributions generated entirely by bots or agents without substantial human involvement will not be accepted, and bot accounts may be blocked. +Contributions generated entirely by **bots or agents** without substantial human involvement will **not be accepted**. ## 👏 Acknowledgments From abfa903c9c0d30eea92ab3711a68c807ea210a58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 19:15:07 +0000 Subject: [PATCH 06/40] chore(deps): bump ws in the production-dependencies group Bumps the production-dependencies group with 1 update: [ws](https://github.com/websockets/ws). Updates `ws` from 8.19.0 to 8.20.0 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.19.0...8.20.0) --- updated-dependencies: - dependency-name: ws dependency-version: 8.20.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- packages/mcp/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8194ed2..3dc2d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11451,9 +11451,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -11876,7 +11876,7 @@ "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", - "ws": "^8.19.0", + "ws": "^8.20.0", "zod": "^4.3.5" }, "bin": { diff --git a/packages/mcp/package.json b/packages/mcp/package.json index f6e782f..1624b16 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", - "ws": "^8.19.0", + "ws": "^8.20.0", "zod": "^4.3.5" } } From 64a90e3b3a810815e0e07dd1669c05cbb6b7dd15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 19:17:32 +0000 Subject: [PATCH 07/40] chore(deps-dev): bump lucide-react from 0.577.0 to 1.0.1 Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.577.0 to 1.0.1. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/commits/1.0.1/packages/lucide-react) --- updated-dependencies: - dependency-name: lucide-react dependency-version: 1.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 10 +++++----- packages/extension/package.json | 2 +- packages/website/package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8194ed2..8744112 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8296,9 +8296,9 @@ } }, "node_modules/lucide-react": { - "version": "0.577.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz", - "integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.0.1.tgz", + "integrity": "sha512-lih7tKEczCYOQjVEzpFuxEuNzlwf+1yhvlMlEkGWJM3va8Pugv8bYXc/pRtcjPncaP7k84X0Pt/71ufxvqEPtQ==", "dev": true, "license": "ISC", "peerDependencies": { @@ -11839,7 +11839,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "idb": "^8.0.3", - "lucide-react": "^0.577.0", + "lucide-react": "^1.0.1", "motion": "^12.37.0", "next-themes": "^0.4.6", "react": "^19.2.4", @@ -11929,7 +11929,7 @@ "@types/react-dom": "^19.2.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.577.0", + "lucide-react": "^1.0.1", "motion": "^12.37.0", "next-themes": "^0.4.6", "react": "^19.2.4", diff --git a/packages/extension/package.json b/packages/extension/package.json index 8ad646d..4a5703b 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -23,7 +23,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "idb": "^8.0.3", - "lucide-react": "^0.577.0", + "lucide-react": "^1.0.1", "motion": "^12.37.0", "next-themes": "^0.4.6", "react": "^19.2.4", diff --git a/packages/website/package.json b/packages/website/package.json index d5bcfa9..1b8d685 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -19,7 +19,7 @@ "@types/react-dom": "^19.2.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.577.0", + "lucide-react": "^1.0.1", "motion": "^12.37.0", "next-themes": "^0.4.6", "react": "^19.2.4", From 53c9149d06557750a9cfc9e2cacd00b6fda05a4e Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 24 Mar 2026 17:42:56 +0800 Subject: [PATCH 08/40] docs: add maintainer note --- CONTRIBUTING.md | 2 ++ README.md | 2 +- docs/README-zh.md | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3599e02..9f303d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,7 @@ # Contributing to PageAgent +> **[A note from the maintainer](https://github.com/alibaba/page-agent/issues/349)** — Please read before opening issues or PRs. + ♥️ We welcome contributions from everyone. ## 🚀 Quick Start diff --git a/README.md b/README.md index bc55164..9a16cf2 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ For more programmatic usage, see [📖 Documentations](https://alibaba.github.io We welcome contributions from the community! Follow our instructions in [CONTRIBUTING.md](CONTRIBUTING.md) for setup and guidelines. -Please read [Code of Conduct](docs/CODE_OF_CONDUCT.md) before contributing. +Please read the [maintainer note](https://github.com/alibaba/page-agent/issues/349) and [Code of Conduct](docs/CODE_OF_CONDUCT.md) before opening issues or PRs. Contributions generated entirely by **bots or agents** without substantial human involvement will **not be accepted**. diff --git a/docs/README-zh.md b/docs/README-zh.md index e51c25c..404f28d 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -74,7 +74,9 @@ await agent.execute('点击登录按钮') ## 🤝 贡献 -欢迎社区贡献!请参阅 [CONTRIBUTING.md](../CONTRIBUTING.md) 了解安装与贡献指南。请在贡献前阅读[行为准则](CODE_OF_CONDUCT.md)。 +欢迎社区贡献!请参阅 [CONTRIBUTING.md](../CONTRIBUTING.md) 了解安装与贡献指南。 + +提交 issue 或 PR 之前,请先阅读[维护者说明](https://github.com/alibaba/page-agent/issues/349)和[行为准则](CODE_OF_CONDUCT.md)。 我们不接受未经实质性人类参与、完全由 Bot 或 Agent 自动生成的代码,机器人账号可能被禁止参与互动。 From 583f757f0a33634aff2b9b6ac81dc573d847cae3 Mon Sep 17 00:00:00 2001 From: Ryanba <92616678+Gujiassh@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:23:59 +0800 Subject: [PATCH 09/40] fix(ui): set task input max length to 1000 (#292) --- packages/page-agent/src/PageAgent.ts | 5 +++-- packages/ui/src/panel/Panel.ts | 3 ++- packages/website/src/pages/docs/advanced/page-agent/page.tsx | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/page-agent/src/PageAgent.ts b/packages/page-agent/src/PageAgent.ts index f6e5e48..486396b 100644 --- a/packages/page-agent/src/PageAgent.ts +++ b/packages/page-agent/src/PageAgent.ts @@ -4,11 +4,11 @@ */ import { type AgentConfig, PageAgentCore } from '@page-agent/core' import { PageController, type PageControllerConfig } from '@page-agent/page-controller' -import { Panel } from '@page-agent/ui' +import { Panel, type PanelConfig } from '@page-agent/ui' export * from '@page-agent/core' -export type PageAgentConfig = AgentConfig & PageControllerConfig +export type PageAgentConfig = AgentConfig & PageControllerConfig & Omit export class PageAgent extends PageAgentCore { panel: Panel @@ -23,6 +23,7 @@ export class PageAgent extends PageAgentCore { this.panel = new Panel(this, { language: config.language, + promptForNextTask: config.promptForNextTask, }) } } diff --git a/packages/ui/src/panel/Panel.ts b/packages/ui/src/panel/Panel.ts index ab5c430..ae15473 100644 --- a/packages/ui/src/panel/Panel.ts +++ b/packages/ui/src/panel/Panel.ts @@ -369,6 +369,7 @@ export class Panel { } #createWrapper(): HTMLElement { + const taskInputMaxLength = 1000 const wrapper = document.createElement('div') wrapper.id = 'page-agent-runtime_agent-panel' wrapper.className = styles.wrapper @@ -406,7 +407,7 @@ export class Panel {
diff --git a/packages/website/src/pages/docs/advanced/page-agent/page.tsx b/packages/website/src/pages/docs/advanced/page-agent/page.tsx index 7428223..a0e2471 100644 --- a/packages/website/src/pages/docs/advanced/page-agent/page.tsx +++ b/packages/website/src/pages/docs/advanced/page-agent/page.tsx @@ -100,7 +100,7 @@ console.log(result.history) // Full execution history`} > AgentConfig {' '} - 和{' '} + 、 PanelConfig 和{' '} AgentConfig {' '} - and{' '} + , PanelConfig, and{' '} Date: Tue, 24 Mar 2026 16:28:24 +0000 Subject: [PATCH 10/40] chore(deps-dev): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.2.1` | `4.2.2` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.57.1` | `8.57.2` | | [@types/chrome](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chrome) | `0.1.37` | `0.1.38` | | [motion](https://github.com/motiondivision/motion) | `12.37.0` | `12.38.0` | | [simple-icons](https://github.com/simple-icons/simple-icons) | `16.12.0` | `16.13.0` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.2.1` | `4.2.2` | | [wxt](https://github.com/wxt-dev/wxt) | `0.20.19` | `0.20.20` | Updates `@tailwindcss/vite` from 4.2.1 to 4.2.2 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-vite) Updates `typescript-eslint` from 8.57.1 to 8.57.2 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.2/packages/typescript-eslint) Updates `@types/chrome` from 0.1.37 to 0.1.38 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chrome) Updates `motion` from 12.37.0 to 12.38.0 - [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md) - [Commits](https://github.com/motiondivision/motion/compare/v12.37.0...v12.38.0) Updates `simple-icons` from 16.12.0 to 16.13.0 - [Release notes](https://github.com/simple-icons/simple-icons/releases) - [Commits](https://github.com/simple-icons/simple-icons/compare/16.12.0...16.13.0) Updates `tailwindcss` from 4.2.1 to 4.2.2 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss) Updates `wxt` from 0.20.19 to 0.20.20 - [Release notes](https://github.com/wxt-dev/wxt/releases) - [Commits](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.19...wxt-v0.20.20) --- updated-dependencies: - dependency-name: "@tailwindcss/vite" dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: typescript-eslint dependency-version: 8.57.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: "@types/chrome" dependency-version: 0.1.38 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: motion dependency-version: 12.38.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: simple-icons dependency-version: 16.13.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: tailwindcss dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: wxt dependency-version: 0.20.20 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 426 ++++++++++++++++---------------- package.json | 4 +- packages/extension/package.json | 8 +- packages/website/package.json | 4 +- 4 files changed, 221 insertions(+), 221 deletions(-) diff --git a/package-lock.json b/package-lock.json index a16e051..1a9235e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@commitlint/config-conventional": "^20.5.0", "@eslint/js": "^9.39.2", "@microsoft/api-extractor": "^7.57.7", - "@tailwindcss/vite": "^4.2.1", + "@tailwindcss/vite": "^4.2.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@types/node": "^25.5.0", "@vitejs/plugin-react-swc": "^4.3.0", @@ -41,7 +41,7 @@ "lint-staged": "^16.4.0", "prettier": "^3.8.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.1", + "typescript-eslint": "^8.57.2", "unplugin-dts": "^1.0.0-beta.6", "vite": "^7.3.1", "vite-bundle-analyzer": "^1.3.6", @@ -3352,49 +3352,49 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", - "lightningcss": "1.31.1", + "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" + "tailwindcss": "4.2.2" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", "dev": true, "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", "cpu": [ "arm64" ], @@ -3409,9 +3409,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", "cpu": [ "arm64" ], @@ -3426,9 +3426,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", "cpu": [ "x64" ], @@ -3443,9 +3443,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", "cpu": [ "x64" ], @@ -3460,9 +3460,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", "cpu": [ "arm" ], @@ -3477,9 +3477,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", "cpu": [ "arm64" ], @@ -3494,9 +3494,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", "cpu": [ "arm64" ], @@ -3511,9 +3511,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", "cpu": [ "x64" ], @@ -3528,9 +3528,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", "cpu": [ "x64" ], @@ -3545,9 +3545,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -3639,9 +3639,9 @@ "optional": true }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", "cpu": [ "arm64" ], @@ -3656,9 +3656,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", "cpu": [ "x64" ], @@ -3673,18 +3673,18 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", - "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz", + "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==", "dev": true, "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "tailwindcss": "4.2.1" + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "tailwindcss": "4.2.2" }, "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" + "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "node_modules/@trivago/prettier-plugin-sort-imports": { @@ -3807,9 +3807,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.1.37", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.37.tgz", - "integrity": "sha512-IJE4ceuDO7lrEuua7Pow47zwNcI8E6qqkowRP7aFPaZ0lrjxh6y836OPqqkIZeTX64FTogbw+4RNH0+QrweCTQ==", + "version": "0.1.38", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.38.tgz", + "integrity": "sha512-5aK4m9wZqoWAoB98aElESLm/5pXpqJnFWMNoiCs/XdPsXR6wNdVkJFSdQ9Wr4PnTuUrxD0SuNuDHh3EG5QeBzA==", "dev": true, "license": "MIT", "dependencies": { @@ -3893,17 +3893,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.1.tgz", - "integrity": "sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", + "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.1", - "@typescript-eslint/type-utils": "8.57.1", - "@typescript-eslint/utils": "8.57.1", - "@typescript-eslint/visitor-keys": "8.57.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/type-utils": "8.57.2", + "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -3916,7 +3916,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.1", + "@typescript-eslint/parser": "^8.57.2", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3932,16 +3932,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.1.tgz", - "integrity": "sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", + "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.1", - "@typescript-eslint/types": "8.57.1", - "@typescript-eslint/typescript-estree": "8.57.1", - "@typescript-eslint/visitor-keys": "8.57.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3" }, "engines": { @@ -3957,14 +3957,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.1.tgz", - "integrity": "sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", + "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.1", - "@typescript-eslint/types": "^8.57.1", + "@typescript-eslint/tsconfig-utils": "^8.57.2", + "@typescript-eslint/types": "^8.57.2", "debug": "^4.4.3" }, "engines": { @@ -3979,14 +3979,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.1.tgz", - "integrity": "sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", + "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.1", - "@typescript-eslint/visitor-keys": "8.57.1" + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3997,9 +3997,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.1.tgz", - "integrity": "sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", + "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", "dev": true, "license": "MIT", "engines": { @@ -4014,15 +4014,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.1.tgz", - "integrity": "sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", + "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.1", - "@typescript-eslint/typescript-estree": "8.57.1", - "@typescript-eslint/utils": "8.57.1", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/utils": "8.57.2", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -4039,9 +4039,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", - "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", + "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", "dev": true, "license": "MIT", "engines": { @@ -4053,16 +4053,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.1.tgz", - "integrity": "sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", + "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.1", - "@typescript-eslint/tsconfig-utils": "8.57.1", - "@typescript-eslint/types": "8.57.1", - "@typescript-eslint/visitor-keys": "8.57.1", + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4081,16 +4081,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.1.tgz", - "integrity": "sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", + "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.1", - "@typescript-eslint/types": "8.57.1", - "@typescript-eslint/typescript-estree": "8.57.1" + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4105,13 +4105,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.1.tgz", - "integrity": "sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", + "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.1", + "@typescript-eslint/types": "8.57.2", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4237,9 +4237,9 @@ "license": "MIT" }, "node_modules/@wxt-dev/browser": { - "version": "0.1.37", - "resolved": "https://registry.npmjs.org/@wxt-dev/browser/-/browser-0.1.37.tgz", - "integrity": "sha512-I32XWCNRy2W6UgbaVXz8BHGBGtm8urGRRBrcNLagUBXTrBi7wCE6zWePUvvK+nUl7qUCZ7iQ1ufdP0c1DEWisw==", + "version": "0.1.38", + "resolved": "https://registry.npmjs.org/@wxt-dev/browser/-/browser-0.1.38.tgz", + "integrity": "sha512-Y9nUfNOMqgsoO8KQ1BssrwzHEmrSr/2pUowAG4Wcr9EyKyhOK7mC7Vdyj2kXAmp5NOUXHjhghzJ6qIb5h+RbCA==", "dev": true, "license": "MIT", "dependencies": { @@ -5851,9 +5851,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "dev": true, "license": "MIT", "dependencies": { @@ -6676,13 +6676,13 @@ } }, "node_modules/framer-motion": { - "version": "12.37.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.37.0.tgz", - "integrity": "sha512-j/QUcZS9Nw3NzZWoAbkzr3ETRFHyVeQMlGOUYUmG15U+uiyn9DqIktYruVPDcqY8I35qYR70JaZBvFmS6p+Pdg==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", "dev": true, "license": "MIT", "dependencies": { - "motion-dom": "^12.37.0", + "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, @@ -7821,9 +7821,9 @@ } }, "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -7837,23 +7837,23 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", "cpu": [ "arm64" ], @@ -7872,9 +7872,9 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", "cpu": [ "arm64" ], @@ -7893,9 +7893,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", "cpu": [ "x64" ], @@ -7914,9 +7914,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", "cpu": [ "x64" ], @@ -7935,9 +7935,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", "cpu": [ "arm" ], @@ -7956,9 +7956,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", "cpu": [ "arm64" ], @@ -7977,9 +7977,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", "cpu": [ "arm64" ], @@ -7998,9 +7998,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", "cpu": [ "x64" ], @@ -8019,9 +8019,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", "cpu": [ "x64" ], @@ -8040,9 +8040,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", "cpu": [ "arm64" ], @@ -8061,9 +8061,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", "cpu": [ "x64" ], @@ -8521,13 +8521,13 @@ } }, "node_modules/motion": { - "version": "12.37.0", - "resolved": "https://registry.npmjs.org/motion/-/motion-12.37.0.tgz", - "integrity": "sha512-Ph6oyO5hGSIAPjDsqwchEP+EKXjyFK0ci6FTIFBbx+qaMl8zLzLzPLzd9q3DKhAHcvnV7LxQonMyA+FyAv9+gA==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.38.0.tgz", + "integrity": "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w==", "dev": true, "license": "MIT", "dependencies": { - "framer-motion": "^12.37.0", + "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -8548,9 +8548,9 @@ } }, "node_modules/motion-dom": { - "version": "12.37.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.37.0.tgz", - "integrity": "sha512-LnppZuwX1jQizRWTl9LBLMN3RbAEmdQkX/2Af0UW70NCqYJI/7GfI83vQP9Ucel/Avc0Tf2ZWy8FHawuc0O6Vg==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", "dev": true, "license": "MIT", "dependencies": { @@ -10114,9 +10114,9 @@ } }, "node_modules/simple-icons": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.12.0.tgz", - "integrity": "sha512-fDJDqXUpkb2twqH+eBQpJsCYUE6jEH7VkuuPL9dH16sbLf6KKnwyijULmcx7SCoy3c2L6pl8WCzt+4rpYjoWfw==", + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.13.0.tgz", + "integrity": "sha512-N4AMZvFERU5YLEtUudtUesiM2H4O5xQ9qfS3K0oOV5II5KVtxOUAlmZ7KqBgiTSGBgCVkuLD/Z9dJKBtnI3kKQ==", "dev": true, "funding": [ { @@ -10424,16 +10424,16 @@ } }, "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", "dev": true, "license": "MIT" }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", "dev": true, "license": "MIT", "engines": { @@ -10683,16 +10683,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.1.tgz", - "integrity": "sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", + "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.1", - "@typescript-eslint/parser": "8.57.1", - "@typescript-eslint/typescript-estree": "8.57.1", - "@typescript-eslint/utils": "8.57.1" + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/utils": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11489,9 +11489,9 @@ } }, "node_modules/wxt": { - "version": "0.20.19", - "resolved": "https://registry.npmjs.org/wxt/-/wxt-0.20.19.tgz", - "integrity": "sha512-LNQXDyStuenNSLLbSs3aXDscKB6g6NYUXppBu7uAmIUZNKLy04Hyg3EE9p9w683t0B+j2CBYciDmqglfwisNuA==", + "version": "0.20.20", + "resolved": "https://registry.npmjs.org/wxt/-/wxt-0.20.20.tgz", + "integrity": "sha512-OGvOD1YEXwasjlOmfYzCGlIa88Jm9mxjM+hqx7zw+Xctg+TKjhF1bIt7vVJ1oT1t4RqvczTAcD2mUduiDltZaw==", "dev": true, "license": "MIT", "dependencies": { @@ -11500,7 +11500,7 @@ "@webext-core/fake-browser": "^1.3.4", "@webext-core/isolated-element": "^1.1.3", "@webext-core/match-patterns": "^1.0.3", - "@wxt-dev/browser": "^0.1.37", + "@wxt-dev/browser": "^0.1.38", "@wxt-dev/storage": "^1.0.0", "async-mutex": "^0.5.0", "c12": "^3.3.3", @@ -11537,7 +11537,7 @@ "tinyglobby": "^0.2.15", "unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0", "vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0", - "vite-node": "^3.2.4 || ^5.0.0", + "vite-node": "^3.2.4 || ^5.0.0 || ^6.0.0", "web-ext-run": "^0.2.4" }, "bin": { @@ -11832,7 +11832,7 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", - "@types/chrome": "^0.1.37", + "@types/chrome": "^0.1.38", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.1", "@wxt-dev/module-react": "^1.2.2", @@ -11840,17 +11840,17 @@ "clsx": "^2.1.1", "idb": "^8.0.3", "lucide-react": "^1.0.1", - "motion": "^12.37.0", + "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.12.0", + "simple-icons": "^16.13.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", "tw-animate-css": "^1.4.0", - "wxt": "^0.20.19" + "wxt": "^0.20.20" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" @@ -11930,12 +11930,12 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.0.1", - "motion": "^12.37.0", + "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.12.0", + "simple-icons": "^16.13.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", diff --git a/package.json b/package.json index 93fe042..f0a018d 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@commitlint/config-conventional": "^20.5.0", "@eslint/js": "^9.39.2", "@microsoft/api-extractor": "^7.57.7", - "@tailwindcss/vite": "^4.2.1", + "@tailwindcss/vite": "^4.2.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@types/node": "^25.5.0", "@vitejs/plugin-react-swc": "^4.3.0", @@ -60,7 +60,7 @@ "lint-staged": "^16.4.0", "prettier": "^3.8.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.1", + "typescript-eslint": "^8.57.2", "unplugin-dts": "^1.0.0-beta.6", "vite": "^7.3.1", "vite-plugin-css-injected-by-js": "^4.0.1", diff --git a/packages/extension/package.json b/packages/extension/package.json index 4a5703b..e196d6b 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -16,7 +16,7 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", - "@types/chrome": "^0.1.37", + "@types/chrome": "^0.1.38", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.1", "@wxt-dev/module-react": "^1.2.2", @@ -24,17 +24,17 @@ "clsx": "^2.1.1", "idb": "^8.0.3", "lucide-react": "^1.0.1", - "motion": "^12.37.0", + "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.12.0", + "simple-icons": "^16.13.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", "tw-animate-css": "^1.4.0", - "wxt": "^0.20.19" + "wxt": "^0.20.20" }, "dependencies": { "@page-agent/core": "1.6.1", diff --git a/packages/website/package.json b/packages/website/package.json index 1b8d685..e5e151a 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -20,12 +20,12 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.0.1", - "motion": "^12.37.0", + "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.12.0", + "simple-icons": "^16.13.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", From 78a31ef5d1dc667b44605b89b1d8c4afebb6b98f Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:50:29 +0800 Subject: [PATCH 11/40] fix: tslint --- packages/extension/src/components/ConfigPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extension/src/components/ConfigPanel.tsx b/packages/extension/src/components/ConfigPanel.tsx index f1dd250..0a0c338 100644 --- a/packages/extension/src/components/ConfigPanel.tsx +++ b/packages/extension/src/components/ConfigPanel.tsx @@ -31,7 +31,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { const [model, setModel] = useState(config?.model || DEMO_MODEL) const [apiKey, setApiKey] = useState(config?.apiKey) const [language, setLanguage] = useState(config?.language) - const [maxSteps, setMaxSteps] = useState(config?.maxSteps) + const [maxSteps, setMaxSteps] = useState(config?.maxSteps) const [systemInstruction, setSystemInstruction] = useState(config?.systemInstruction ?? '') const [experimentalLlmsTxt, setExperimentalLlmsTxt] = useState( config?.experimentalLlmsTxt ?? false @@ -41,7 +41,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { ) const [advancedOpen, setAdvancedOpen] = useState(false) const [saving, setSaving] = useState(false) - const [userAuthToken, setUserAuthToken] = useState('') + const [userAuthToken, setUserAuthToken] = useState('') const [copied, setCopied] = useState(false) const [showToken, setShowToken] = useState(false) const [showApiKey, setShowApiKey] = useState(false) From 75bc69c0c0b8f9a39a14990e0e1022e840aa49c3 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Wed, 25 Mar 2026 01:05:20 +0800 Subject: [PATCH 12/40] chore(version): bump version to 1.6.2 --- README.md | 4 +-- docs/README-zh.md | 4 +-- package-lock.json | 40 +++++++++++++-------------- package.json | 2 +- packages/core/package.json | 6 ++-- packages/extension/package.json | 10 +++---- packages/llms/package.json | 2 +- packages/mcp/package.json | 2 +- packages/page-agent/package.json | 10 +++---- packages/page-controller/package.json | 2 +- packages/ui/package.json | 2 +- packages/website/package.json | 2 +- packages/website/src/constants.ts | 4 +-- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 9a16cf2..4161ae6 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ Fastest way to try PageAgent with our free Demo LLM: | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js | ### NPM Installation diff --git a/docs/README-zh.md b/docs/README-zh.md index 404f28d..19baaef 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -48,8 +48,8 @@ | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js | ### NPM 安装 diff --git a/package-lock.json b/package-lock.json index 1a9235e..2675f70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "root", - "version": "1.6.1", + "version": "1.6.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "root", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "workspaces": [ "packages/page-controller", @@ -11799,11 +11799,11 @@ }, "packages/core": { "name": "@page-agent/core", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "dependencies": { - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1", + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2", "chalk": "^5.6.2" }, "devDependencies": { @@ -11815,13 +11815,13 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "1.6.1", + "version": "1.6.2", "hasInstallScript": true, "dependencies": { - "@page-agent/core": "1.6.1", - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1", - "@page-agent/ui": "1.6.1", + "@page-agent/core": "1.6.2", + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2", + "@page-agent/ui": "1.6.2", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, @@ -11858,7 +11858,7 @@ }, "packages/llms": { "name": "@page-agent/llms", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "dependencies": { "chalk": "^5.6.2" @@ -11872,7 +11872,7 @@ }, "packages/mcp": { "name": "@page-agent/mcp", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", @@ -11887,13 +11887,13 @@ } }, "packages/page-agent": { - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "dependencies": { - "@page-agent/core": "1.6.1", - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1", - "@page-agent/ui": "1.6.1", + "@page-agent/core": "1.6.2", + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2", + "@page-agent/ui": "1.6.2", "chalk": "^5.6.2" }, "devDependencies": { @@ -11905,7 +11905,7 @@ }, "packages/page-controller": { "name": "@page-agent/page-controller", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT", "dependencies": { "ai-motion": "^0.4.8" @@ -11913,12 +11913,12 @@ }, "packages/ui": { "name": "@page-agent/ui", - "version": "1.6.1", + "version": "1.6.2", "license": "MIT" }, "packages/website": { "name": "@page-agent/website", - "version": "1.6.1", + "version": "1.6.2", "devDependencies": { "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-separator": "^1.1.8", diff --git a/package.json b/package.json index f0a018d..14fd8fe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "root", "private": true, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "workspaces": [ "packages/page-controller", diff --git a/packages/core/package.json b/packages/core/package.json index 555fdc8..6c750ea 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/core", "private": false, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "main": "./dist/esm/page-agent-core.js", "module": "./dist/esm/page-agent-core.js", @@ -44,8 +44,8 @@ }, "dependencies": { "chalk": "^5.6.2", - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1" + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" diff --git a/packages/extension/package.json b/packages/extension/package.json index e196d6b..e40a192 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "scripts": { "dev": "wxt", @@ -37,10 +37,10 @@ "wxt": "^0.20.20" }, "dependencies": { - "@page-agent/core": "1.6.1", - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1", - "@page-agent/ui": "1.6.1", + "@page-agent/core": "1.6.2", + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2", + "@page-agent/ui": "1.6.2", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, diff --git a/packages/llms/package.json b/packages/llms/package.json index bb375a1..6479db1 100644 --- a/packages/llms/package.json +++ b/packages/llms/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/llms", - "version": "1.6.1", + "version": "1.6.2", "type": "module", "main": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 1624b16..6ba3da1 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/mcp", "private": false, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "bin": { "page-agent-mcp": "src/index.js" diff --git a/packages/page-agent/package.json b/packages/page-agent/package.json index 1f29cee..3f650f2 100644 --- a/packages/page-agent/package.json +++ b/packages/page-agent/package.json @@ -1,7 +1,7 @@ { "name": "page-agent", "private": false, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "main": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js", @@ -44,10 +44,10 @@ "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" }, "dependencies": { - "@page-agent/core": "1.6.1", - "@page-agent/llms": "1.6.1", - "@page-agent/page-controller": "1.6.1", - "@page-agent/ui": "1.6.1", + "@page-agent/core": "1.6.2", + "@page-agent/llms": "1.6.2", + "@page-agent/page-controller": "1.6.2", + "@page-agent/ui": "1.6.2", "chalk": "^5.6.2" }, "peerDependencies": { diff --git a/packages/page-controller/package.json b/packages/page-controller/package.json index f464396..1341693 100644 --- a/packages/page-controller/package.json +++ b/packages/page-controller/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/page-controller", - "version": "1.6.1", + "version": "1.6.2", "type": "module", "main": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js", diff --git a/packages/ui/package.json b/packages/ui/package.json index b304f6a..e1b5da0 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/ui", - "version": "1.6.1", + "version": "1.6.2", "type": "module", "main": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js", diff --git a/packages/website/package.json b/packages/website/package.json index e5e151a..6ff6349 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/website", "private": true, - "version": "1.6.1", + "version": "1.6.2", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/packages/website/src/constants.ts b/packages/website/src/constants.ts index 572fb53..cd71d3c 100644 --- a/packages/website/src/constants.ts +++ b/packages/website/src/constants.ts @@ -1,8 +1,8 @@ // Demo build (auto-init with demo LLM, for quick testing) export const CDN_DEMO_URL = - 'https://cdn.jsdelivr.net/npm/page-agent@1.6.1/dist/iife/page-agent.demo.js' + 'https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js' export const CDN_DEMO_CN_URL = - 'https://registry.npmmirror.com/page-agent/1.6.1/files/dist/iife/page-agent.demo.js' + 'https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js' // Demo LLM for website testing (homepage quick trial uses flash) export const DEMO_MODEL = 'qwen3.5-flash' From 48fb65d00b267597c3810be7005e7ea8118ef2b8 Mon Sep 17 00:00:00 2001 From: 1245040330 <32012815+1245040330@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:26:13 +0800 Subject: [PATCH 13/40] =?UTF-8?q?feat(extension):=20=E7=A6=81=E7=94=A8=20E?= =?UTF-8?q?mptyState=20=E7=BB=84=E4=BB=B6=E7=9A=84=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 EmptyState 组件的动画配置中添加了 startOnView=false 属性 - 防止动画在视图加载时自动开始播放 - 优化了用户体验,避免不必要的动画干扰 --- packages/extension/src/components/misc.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/extension/src/components/misc.tsx b/packages/extension/src/components/misc.tsx index 6de0f19..66bfa48 100644 --- a/packages/extension/src/components/misc.tsx +++ b/packages/extension/src/components/misc.tsx @@ -111,6 +111,7 @@ export function EmptyState() { ]} cursorStyle="underscore" loop + startOnView={false} typeSpeed={20} deleteSpeed={10} pauseDelay={3000} From ac72f557316ae75462796422813738408a4f6963 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:23:31 +0800 Subject: [PATCH 14/40] docs: simplify readme --- README.md | 16 +++------------- docs/README-zh.md | 21 ++++++--------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 4161ae6..2a71057 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ The GUI Agent Living in Your Webpage. Control web interfaces with natural langua - **SaaS AI Copilot** — Ship an AI copilot in your product in lines of code. No backend rewrite. - **Smart Form Filling** — Turn 20-click workflows into one sentence. Perfect for ERP, CRM, and admin systems. - **Accessibility** — Make any web app accessible through natural language. Voice commands, screen readers, zero barrier. -- **Multi-page Agent** — Extend your own agent's reach across browser tabs with the optional [chrome extension](https://alibaba.github.io/page-agent/docs/features/chrome-extension). +- **Multi-page Agent** — Extend your own web agent's reach across browser tabs [chrome extension](https://alibaba.github.io/page-agent/docs/features/chrome-extension). +- **MCP** - Allow your agent clients to control your browser. ## 🚀 Quick Start @@ -97,23 +98,12 @@ Licensed under the MIT License We gratefully acknowledge the browser-use project and its contributors for their excellent work on web automation and DOM interaction patterns that helped make this project possible. - -Third-party dependencies and their licenses can be found in the package.json -file and in the node_modules directory after installation. ``` -## 📄 License +## ⚖️ License [MIT License](LICENSE) --- **⭐ Star this repo if you find PageAgent helpful!** - - - - - - Star History Chart - - diff --git a/docs/README-zh.md b/docs/README-zh.md index 19baaef..0406773 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -32,7 +32,8 @@ - **SaaS AI Copilot** — 几行代码为你的产品加上 AI 副驾驶,无需重写后端。 - **智能表单填写** — 把 20 次点击变成一句话。ERP、CRM、管理后台的最佳拍档。 - **无障碍增强** — 用自然语言让任何网页无障碍。语音指令、屏幕阅读器,零门槛。 -- **跨页面 Agent** — 通过可选的 [Chrome 扩展](https://alibaba.github.io/page-agent/docs/features/chrome-extension),让你自己的 Agent 跨标签页工作。 +- **跨页面 Agent** — 通过可选的 [Chrome 扩展](https://alibaba.github.io/page-agent/docs/features/chrome-extension),让你自己的 Web Agent 跨标签页工作。 +- 通过 MCP 为现有 Agent 加入浏览器控制能力。 ## 🚀 快速开始 @@ -76,11 +77,11 @@ await agent.execute('点击登录按钮') 欢迎社区贡献!请参阅 [CONTRIBUTING.md](../CONTRIBUTING.md) 了解安装与贡献指南。 -提交 issue 或 PR 之前,请先阅读[维护者说明](https://github.com/alibaba/page-agent/issues/349)和[行为准则](CODE_OF_CONDUCT.md)。 +提交 issue 或 PR 之前,请先阅读[作者声明](https://github.com/alibaba/page-agent/issues/349)和[行为准则](CODE_OF_CONDUCT.md)。 -我们不接受未经实质性人类参与、完全由 Bot 或 Agent 自动生成的代码,机器人账号可能被禁止参与互动。 +我们不接受未经实质性人类参与、完全由 Bot 或 Agent 自动生成的代码。 -## 👏 致谢 +## 👏 声明与致谢 本项目基于 **[`browser-use`](https://github.com/browser-use/browser-use)** 的优秀工作构建。 @@ -96,12 +97,9 @@ Licensed under the MIT License We gratefully acknowledge the browser-use project and its contributors for their excellent work on web automation and DOM interaction patterns that helped make this project possible. - -Third-party dependencies and their licenses can be found in the package.json -file and in the node_modules directory after installation. ``` -## 📄 许可证 +## ⚖️ 许可证 [MIT License](../LICENSE) @@ -109,10 +107,3 @@ file and in the node_modules directory after installation. **⭐ 如果觉得 PageAgent 有用或有趣,请给项目点个星!** - - - - - Star History Chart - - From 2322d6c46bb20cb6f97d137b93b60af284918d89 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:32:04 +0800 Subject: [PATCH 15/40] docs: add awesome section --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2a71057..9aa79f6 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,10 @@ Please read the [maintainer note](https://github.com/alibaba/page-agent/issues/3 Contributions generated entirely by **bots or agents** without substantial human involvement will **not be accepted**. +## ⚖️ License + +[MIT License](LICENSE) + ## 👏 Acknowledgments This project builds upon the excellent work of **[`browser-use`](https://github.com/browser-use/browser-use)**. @@ -100,9 +104,15 @@ excellent work on web automation and DOM interaction patterns that helped make this project possible. ``` -## ⚖️ License +## 🌟 Awesome Page Agent -[MIT License](LICENSE) +Built something cool with PageAgent? Add it here! Open a PR to share your project. + +> These are community projects — not maintained or endorsed by us. Use at your own discretion. + +| Project | Description | +| ------- | ----------- | +| _Yours?_ | [Open a PR](https://github.com/alibaba/page-agent/pulls) 🙌 | --- From e1fede1194006f76e4bf61bd122ef59f7f8dee25 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:18:13 +0800 Subject: [PATCH 16/40] feat(ext): option to control all tabs --- .../extension/src/agent/MultiPageAgent.ts | 11 +++-- .../src/agent/TabsController.background.ts | 13 ++++++ .../extension/src/agent/TabsController.ts | 42 +++++++++++++++---- packages/extension/src/agent/useAgent.ts | 1 + .../extension/src/entrypoints/main-world.ts | 4 ++ 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/packages/extension/src/agent/MultiPageAgent.ts b/packages/extension/src/agent/MultiPageAgent.ts index f2e7b0a..aa768bc 100644 --- a/packages/extension/src/agent/MultiPageAgent.ts +++ b/packages/extension/src/agent/MultiPageAgent.ts @@ -11,13 +11,18 @@ function detectLanguage(): 'en-US' | 'zh-CN' { return lang.startsWith('zh') ? 'zh-CN' : 'en-US' } +interface MultiPageAgentConfig extends AgentConfig { + includeInitialTab?: boolean + experimentalIncludeAllTabs?: boolean +} + /** * MultiPageAgent * - use with extension * - can be used from a side panel or a content script */ export class MultiPageAgent extends PageAgentCore { - constructor(config: AgentConfig & { includeInitialTab?: boolean }) { + constructor(config: MultiPageAgentConfig) { // multi page controller const tabsController = new TabsController() const pageController = new RemotePageController(tabsController) @@ -31,8 +36,8 @@ export class MultiPageAgent extends PageAgentCore { `Default working language: **${targetLanguage}**` ) - // include initial tab for controlling const includeInitialTab = config.includeInitialTab ?? true + const experimentalIncludeAllTabs = config.experimentalIncludeAllTabs ?? false /** * When the agent is in side-panel and user closed the side-panel. @@ -50,7 +55,7 @@ export class MultiPageAgent extends PageAgentCore { customSystemPrompt: systemPrompt, onBeforeTask: async (agent) => { - await tabsController.init(agent.task, includeInitialTab) + await tabsController.init(agent.task, { includeInitialTab, experimentalIncludeAllTabs }) heartBeatInterval = window.setInterval(() => { chrome.storage.local.set({ diff --git a/packages/extension/src/agent/TabsController.background.ts b/packages/extension/src/agent/TabsController.background.ts index 39c628a..43e5ade 100644 --- a/packages/extension/src/agent/TabsController.background.ts +++ b/packages/extension/src/agent/TabsController.background.ts @@ -114,6 +114,19 @@ export function handleTabControlMessage( return true // async response } + case 'get_window_tabs': { + debug('get_window_tabs') + chrome.tabs + .query({ currentWindow: true }) + .then((tabs) => { + sendResponse({ success: true, tabs }) + }) + .catch((error) => { + sendResponse({ error: error instanceof Error ? error.message : String(error) }) + }) + return true + } + default: sendResponse({ error: `Unknown action: ${action}` }) return diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index 46fabf6..6fe2c1f 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -28,16 +28,19 @@ export class TabsController extends EventTarget { private tabs: TabMeta[] = [] private initialTabId: number | null = null private tabGroupId: number | null = null + private experimentalIncludeAllTabs = false private task: string = '' - async init(task: string, includeInitialTab: boolean = true) { - debug('init', task, includeInitialTab) + async init(task: string, options: TabsInitOptions = {}) { + const { includeInitialTab = true, experimentalIncludeAllTabs = false } = options + debug('init', task, options) this.task = task this.tabs = [] this.currentTabId = null this.tabGroupId = null this.initialTabId = null + this.experimentalIncludeAllTabs = experimentalIncludeAllTabs const result = await sendMessage({ type: 'TAB_CONTROL', @@ -50,14 +53,34 @@ export class TabsController extends EventTarget { throw new Error('Failed to get initial tab ID') } - if (includeInitialTab) { + if (experimentalIncludeAllTabs) { + const allTabs = await sendMessage({ + type: 'TAB_CONTROL', + action: 'get_window_tabs', + }) + for (const tab of allTabs.tabs as chrome.tabs.Tab[]) { + if (tab.id && !tab.pinned && isContentScriptAllowed(tab.url)) { + this.tabs.push({ + id: tab.id, + isInitial: tab.id === this.initialTabId, + url: tab.url, + title: tab.title, + status: tab.status, + }) + } + } + if (this.tabs.find((t) => t.id === this.initialTabId)) { + this.currentTabId = this.initialTabId + await this.createTabGroup([this.initialTabId]) + } + } else if (includeInitialTab) { const info = await sendMessage({ type: 'TAB_CONTROL', action: 'get_tab_info', payload: { tabId: this.initialTabId }, }) - if (isContentScriptAllowed(info.url)) { + if (isContentScriptAllowed(info.url) && !info.pinned) { this.currentTabId = this.initialTabId this.tabs.push({ @@ -76,14 +99,13 @@ export class TabsController extends EventTarget { const tabChangeHandler = (message: any): void => { if (message.type !== 'TAB_CHANGE') { - // throw new Error(`[TabsController]: Invalid message type: ${message.type}`) return } if (message.action === 'created') { const tab = message.payload.tab as chrome.tabs.Tab - if (tab.groupId === this.tabGroupId && tab.id != null) { - // Tab created in our controlled group + const shouldTrack = this.experimentalIncludeAllTabs || tab.groupId === this.tabGroupId + if (shouldTrack && tab.id != null) { if (!this.tabs.find((t) => t.id === tab.id)) { this.tabs.push({ id: tab.id, isInitial: false }) } @@ -293,6 +315,11 @@ export class TabsController extends EventTarget { } } +export interface TabsInitOptions { + includeInitialTab?: boolean + experimentalIncludeAllTabs?: boolean +} + export type TabAction = | 'get_active_tab' | 'get_tab_info' @@ -302,6 +329,7 @@ export type TabAction = | 'add_tab_to_group' | 'close_tab' | 'get_tab_title' + | 'get_window_tabs' interface TabMeta { id: number diff --git a/packages/extension/src/agent/useAgent.ts b/packages/extension/src/agent/useAgent.ts index f5596a5..97d0a39 100644 --- a/packages/extension/src/agent/useAgent.ts +++ b/packages/extension/src/agent/useAgent.ts @@ -21,6 +21,7 @@ export interface AdvancedConfig { maxSteps?: number systemInstruction?: string experimentalLlmsTxt?: boolean + experimentalIncludeAllTabs?: boolean disableNamedToolChoice?: boolean } diff --git a/packages/extension/src/entrypoints/main-world.ts b/packages/extension/src/entrypoints/main-world.ts index fd93e68..c7946e8 100644 --- a/packages/extension/src/entrypoints/main-world.ts +++ b/packages/extension/src/entrypoints/main-world.ts @@ -13,6 +13,9 @@ export interface ExecuteConfig { */ includeInitialTab?: boolean + /** Control all unpinned tabs in the window instead of only the tab group. */ + experimentalIncludeAllTabs?: boolean + onStatusChange?: (status: AgentStatus) => void onActivity?: (activity: AgentActivity) => void onHistoryUpdate?: (history: HistoricalEvent[]) => void @@ -87,6 +90,7 @@ export default defineUnlistedScript(() => { model: config.model, apiKey: config.apiKey, includeInitialTab: config.includeInitialTab, + experimentalIncludeAllTabs: config.experimentalIncludeAllTabs, }, }, }, From 7f8ddde748aba78e97f13ae6c1e9e13bfe65dd07 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:11:54 +0800 Subject: [PATCH 17/40] docs: move setup details to dev-guide; simplify readme and contributing --- CONTRIBUTING.md | 186 +++------------------------------------- README.md | 10 +-- docs/developer-guide.md | 117 +++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 178 deletions(-) create mode 100644 docs/developer-guide.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f303d7..ca044ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,45 +1,14 @@ # Contributing to PageAgent -> **[A note from the maintainer](https://github.com/alibaba/page-agent/issues/349)** — Please read before opening issues or PRs. - ♥️ We welcome contributions from everyone. -## 🚀 Quick Start - -### Development Setup - -1. **Prerequisites** - - `macOS` / `Linux` / `WSL` - - `node.js >= 20` with `npm >= 10` - - An editor that supports `ts/eslint/prettier` - - Make sure `eslint`, `prettier` and `commitlint` work well. Un-linted code won't pass the CI. - -2. **Setup** - - ```bash - npm i - npm start # Start demo and documentation site - npm run build # Build libs and website - ``` - -### Project Structure - -This is a **monorepo** with npm workspaces containing **4 main packages**: - -- **Page Agent** (`packages/page-agent/`) - Main entry with built-in UI Panel, published as `page-agent` on npm -- **Core** (`packages/core/`) - Core agent logic without UI (npm: `@page-agent/core`) -- **Extension** (`packages/extension/`) - Chrome extension for multi-page tasks and browser-level automation -- **Website** (`packages/website/`) - React documentation and landing page. Also as demo and test page for the core lib. private package `@page-agent/website` - -> We use a simplified monorepo solution with `native npm-workspace + ts reference + vite alias`. No fancy tooling. Hoisting is required. -> -> - When developing. Use alias so that we don't have to pre-build. -> - When bundling. Use external and disable ts `paths` alias. -> - When bundling `IIFE` and `Website`. Bundle everything together. +For local development workflows, setup, local LLM config, extension development, testing on other websites, and more details, see [docs/developer-guide.md](docs/developer-guide.md). ## 🤝 How to Contribute -### Reporting Issues +> **[Maintainer's Note](https://github.com/alibaba/page-agent/issues/349)** + +### Opening Issues - Use the GitHub issue tracker to report bugs or request features - Search existing issues before creating new ones @@ -48,147 +17,24 @@ This is a **monorepo** with npm workspaces containing **4 main packages**: ### Code Contributions -1. **Fork and Clone** - - ```bash - git clone https://github.com/your-username/page-agent.git - cd page-agent - ``` - -2. **Create Feature Branch** - - ```bash - git checkout -b feat/your-feature-name - ``` - -3. **Make Changes** - - Follow existing code style and patterns - - Add tests for new functionality - - Update documentation as needed - -4. **Test Your Changes** - - Build and lint everything. - - Test in our demo website - - Test it on other websites if applicable - - `@TODO: test suite` - -5. **Commit and Push** - - ```bash - git add . - git commit -m "feat: add awesome feature" - git push origin feat/your-feature-name - ``` - -6. **Create Pull Request** - - Provide clear description of changes - - Link related issues - - Include screenshots for UI changes - -## 📝 Code Style - -### General Guidelines - -- Use TypeScript for type safety -- Follow existing naming conventions -- Write meaningful commit messages -- Keep functions small and focused -- Add JSDoc for public APIs +1. Follow existing code style and patterns +2. Update documentation as needed +3. Add JSDoc for public APIs +4. Build and lint everything +5. Test in our demo website, and on other websites if applicable +6. Include screenshots for UI changes ### Vibe Coding with AI -> [Vibe coding](https://en.wikipedia.org/wiki/Vibe_coding) - +- Vibe coding is **NOT** allowed for the core lib or the extension!!! - Vibe coding is **RECOMMENDED** when maintaining **the demo, the website, the UI and tests**. - - We have a [website/AGENTS.md](packages/website/AGENTS.md) for that. -- Vibe coding is **NOT** allowed for the core lib!!! -- NEVER try to vibe coding the MV3 extension!!! It is HELL. +- Make sure your AI references `AGENTS.md` and `website/AGENTS.md` for better quality. - Review anything AI wrote before make a commit. You are the author of anything you commit. NOT AI. -If your AI assistant does not support [AGENTS.md](https://agents.md/). Add an alias for it: - -- claude-code (`CLAUDE.md`) - - ```markdown - @AGENTS.md - ``` - -- antigravity (`.agent/rules/alias.md`) - - ```markdown - --- - trigger: always_on - --- - - @../../AGENTS.md - ``` - -## 🔧 Development Workflows - -### Test With Your Own LLM API - -- Create a `.env` file in the repo root with your LLM API config - - ```env - LLM_MODEL_NAME=gpt-5.2 - LLM_API_KEY=your-api-key - LLM_BASE_URL=https://api.your-llm-provider.com/v1 - ``` - -- **Ollama example** (tested on 0.15 + qwen3:14b, RTX3090 24GB): - - ```env - LLM_BASE_URL="http://localhost:11434/v1" - LLM_API_KEY="NA" - LLM_MODEL_NAME="qwen3:14b" - ``` - - > @see https://alibaba.github.io/page-agent/docs/features/models#ollama for configuration - -- **Restart the dev server** to load new env vars -- If not provided, the demo will use the free testing proxy by default. By using it, you agree to its [terms](https://github.com/alibaba/page-agent/blob/main/docs/terms-and-privacy.md). - -### Extension Development - -```bash -# make sure you ran `npm run build:libs` first -# and every time you changed the core libs -npm run dev -w @page-agent/ext -npm run zip -w @page-agent/ext -``` - -- Update `packages/extension/docs/extension_api.md` for API integration details - -### Testing on Other Websites - -- Start and serve a local `iife` script - - ```bash - npm run dev:demo # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.demo.js - ``` - -- Add a new bookmark - - ```javascript - javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5174/page-agent.demo.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})(); - ``` - -- Click the bookmark on any page to load Page-Agent - -> Warning: AK in your local `.env` will be inlined in the iife script. Be very careful when you distribute the script. - -### Adding Documentation - -Ask an AI to help you add documentation to the `website/` package. Follow the existing style. - -> Our AGENTS.md file and guardrails are designed for this purpose. But please be careful and review anything AI generated. - ## 🚫 What We Don't Accept - Breaking changes and large PRs without prior discussion - Heavy dependencies to core libs -- Contributions without proper testing -- Code that doesn't follow project conventions - Dependencies or code with licenses incompatible with MIT - Bot or AI-generated pull requests without meaningful human involvement @@ -196,12 +42,6 @@ Ask an AI to help you add documentation to the `website/` package. Follow the ex By contributing to this project, you agree that your contributions will be licensed under the MIT License. -> CLA is optional. - -## 💬 Questions? - -- Open a GitHub issue for technical questions -- Check existing documentation and issues first -- Be respectful and constructive in discussions +--- Thank you for helping make PageAgent better! 🎉 diff --git a/README.md b/README.md index 9aa79f6..0edc496 100644 --- a/README.md +++ b/README.md @@ -76,11 +76,11 @@ For more programmatic usage, see [📖 Documentations](https://alibaba.github.io ## 🤝 Contributing -We welcome contributions from the community! Follow our instructions in [CONTRIBUTING.md](CONTRIBUTING.md) for setup and guidelines. +We welcome contributions from the community! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines and [docs/developer-guide.md](docs/developer-guide.md) for local development workflows. -Please read the [maintainer note](https://github.com/alibaba/page-agent/issues/349) and [Code of Conduct](docs/CODE_OF_CONDUCT.md) before opening issues or PRs. +Please read the [maintainer's note](https://github.com/alibaba/page-agent/issues/349) on principles and current state. -Contributions generated entirely by **bots or agents** without substantial human involvement will **not be accepted**. +Contributions generated entirely by **bots or AI** without substantial human involvement will **not be accepted**. ## ⚖️ License @@ -110,8 +110,8 @@ Built something cool with PageAgent? Add it here! Open a PR to share your projec > These are community projects — not maintained or endorsed by us. Use at your own discretion. -| Project | Description | -| ------- | ----------- | +| Project | Description | +| -------- | ----------------------------------------------------------- | | _Yours?_ | [Open a PR](https://github.com/alibaba/page-agent/pulls) 🙌 | --- diff --git a/docs/developer-guide.md b/docs/developer-guide.md new file mode 100644 index 0000000..8e34ce0 --- /dev/null +++ b/docs/developer-guide.md @@ -0,0 +1,117 @@ +# Developer Guide + +This file is for local development workflows. + +For contribution rules and expectations, see [../CONTRIBUTING.md](../CONTRIBUTING.md). + +## 🚀 Quick Start + +### Development Setup + +1. **Prerequisites** + - `macOS` / `Linux` / `WSL` + - `node.js >= 20` with `npm >= 10` + - An editor that supports `ts/eslint/prettier` + - Make sure `eslint`, `prettier` and `commitlint` work well. Un-linted code won't pass the CI. + +2. **Setup** + + ```bash + npm i + npm start # Start demo and documentation site + npm run build # Build libs and website + ``` + +## 📦 Project Structure + +This is a **monorepo** with npm workspaces containing **4 main packages**: + +- **Page Agent** (`packages/page-agent/`) - Main entry with built-in UI Panel, published as `page-agent` on npm +- **Core** (`packages/core/`) - Core agent logic without UI (npm: `@page-agent/core`) +- **Extension** (`packages/extension/`) - Chrome extension for multi-page tasks and browser-level automation +- **Website** (`packages/website/`) - React documentation and landing page. Also as demo and test page for the core lib. private package `@page-agent/website` + +> We use a simplified monorepo solution with `native npm-workspace + ts reference + vite alias`. No fancy tooling. Hoisting is required. +> +> - When developing. Use alias so that we don't have to pre-build. +> - When bundling. Use external and disable ts `paths` alias. +> - When bundling `IIFE` and `Website`. Bundle everything together. + +## 🤖 AGENTS.md Alias + +If your AI assistant does not support [AGENTS.md](https://agents.md/). Add an alias for it: + +- claude-code (`CLAUDE.md`) + + ```markdown + @AGENTS.md + ``` + +- antigravity (`.agent/rules/alias.md`) + + ```markdown + --- + trigger: always_on + --- + + @../../AGENTS.md + ``` + +## 🔧 Development Workflows + +### Test With Your Own LLM API + +- Create a `.env` file in the repo root with your LLM API config + + ```env + LLM_MODEL_NAME=gpt-5.2 + LLM_API_KEY=your-api-key + LLM_BASE_URL=https://api.your-llm-provider.com/v1 + ``` + +- **Ollama example** (tested on 0.15 + qwen3:14b, RTX3090 24GB): + + ```env + LLM_BASE_URL="http://localhost:11434/v1" + LLM_API_KEY="NA" + LLM_MODEL_NAME="qwen3:14b" + ``` + + > @see https://alibaba.github.io/page-agent/docs/features/models#ollama for configuration + +- **Restart the dev server** to load new env vars +- If not provided, the demo will use the free testing proxy by default. By using it, you agree to its [terms](./terms-and-privacy.md). + +### Extension Development + +```bash +# make sure you ran `npm run build:libs` first and every time you changed the core libs +npm run dev -w @page-agent/ext +npm run zip -w @page-agent/ext +``` + +- Update `packages/extension/docs/extension_api.md` for API integration details + +### Testing on Other Websites + +- Start and serve a local `iife` script + + ```bash + npm run dev:demo # Serving IIFE with auto rebuild at http://localhost:5174/page-agent.demo.js + ``` + +- Add a new bookmark + + ```javascript + javascript:(function(){var s=document.createElement('script');s.src=`http://localhost:5174/page-agent.demo.js?t=${Math.random()}`;s.onload=()=>console.log(%27PageAgent ready!%27);document.head.appendChild(s);})(); + ``` + +- Click the bookmark on any page to load Page-Agent + +> Warning: AK in your local `.env` will be inlined in the iife script. Be very careful when you distribute the script. + +### Adding Documentation + +Ask an AI to help you add documentation to the `website/` package. Follow the existing style. + +> Our AGENTS.md file and guardrails are designed for this purpose. But please be careful and review anything AI generated. From a7c9999d8365a707e67db3231739e3ccca93a194 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:21:20 +0800 Subject: [PATCH 18/40] chore: mv security file --- SECURITY.md => docs/SECURITY.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename SECURITY.md => docs/SECURITY.md (100%) diff --git a/SECURITY.md b/docs/SECURITY.md similarity index 100% rename from SECURITY.md rename to docs/SECURITY.md From 52edd78cd46da7cc6d9f7c734407d69b85a70d1b Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:48:52 +0800 Subject: [PATCH 19/40] chore(ext): improve debug logging --- .../src/agent/RemotePageController.background.ts | 4 +--- packages/extension/src/agent/RemotePageController.ts | 4 +--- .../extension/src/agent/TabsController.background.ts | 11 +++++------ packages/extension/src/agent/TabsController.ts | 4 +--- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/extension/src/agent/RemotePageController.background.ts b/packages/extension/src/agent/RemotePageController.background.ts index b75c4cb..8fb89ae 100644 --- a/packages/extension/src/agent/RemotePageController.background.ts +++ b/packages/extension/src/agent/RemotePageController.background.ts @@ -10,9 +10,7 @@ export function handlePageControlMessage( ): true | undefined { const PREFIX = '[RemotePageController.background]' - function debug(...messages: any[]) { - console.debug(`\x1b[90m${PREFIX}\x1b[0m`, ...messages) - } + const debug = console.debug.bind(console, `\x1b[90m${PREFIX}\x1b[0m`) const { action, payload, targetTabId } = message diff --git a/packages/extension/src/agent/RemotePageController.ts b/packages/extension/src/agent/RemotePageController.ts index 3a35ddd..0c49f1b 100644 --- a/packages/extension/src/agent/RemotePageController.ts +++ b/packages/extension/src/agent/RemotePageController.ts @@ -4,9 +4,7 @@ import type { TabsController } from './TabsController' const PREFIX = '[RemotePageController]' -function debug(...messages: any[]) { - console.debug(`\x1b[90m${PREFIX}\x1b[0m`, ...messages) -} +const debug = console.debug.bind(console, `\x1b[90m${PREFIX}\x1b[0m`) function sendMessage(message: { type: 'PAGE_CONTROL' diff --git a/packages/extension/src/agent/TabsController.background.ts b/packages/extension/src/agent/TabsController.background.ts index 43e5ade..60ba212 100644 --- a/packages/extension/src/agent/TabsController.background.ts +++ b/packages/extension/src/agent/TabsController.background.ts @@ -5,9 +5,8 @@ import type { TabAction } from './TabsController' const PREFIX = '[TabsController.background]' -function debug(...messages: any[]) { - console.debug(`\x1b[90m${PREFIX}\x1b[0m`, ...messages) -} +const debug = console.debug.bind(console, `\x1b[90m${PREFIX}\x1b[0m`) +const debugError = console.error.bind(console, `\x1b[91m${PREFIX}\x1b[0m`) export function handleTabControlMessage( message: { type: 'TAB_CONTROL'; action: TabAction; payload: any }, @@ -141,7 +140,7 @@ export function setupTabChangeEvents() { chrome.runtime .sendMessage({ type: 'TAB_CHANGE', action: 'created', payload: { tab } }) .catch((error) => { - debug('onCreated error:', error) + debugError('onCreated error:', error) }) }) @@ -154,7 +153,7 @@ export function setupTabChangeEvents() { payload: { tabId, removeInfo }, }) .catch((error) => { - debug('onRemoved error:', error) + debugError('onRemoved error:', error) }) }) @@ -167,7 +166,7 @@ export function setupTabChangeEvents() { payload: { tabId, changeInfo, tab }, }) .catch((error) => { - debug('onUpdated error:', error) + debugError('onUpdated error:', error) }) }) } diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index 6fe2c1f..5492273 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -2,9 +2,7 @@ import { isContentScriptAllowed } from './RemotePageController' const PREFIX = '[TabsController]' -function debug(...messages: any[]) { - console.debug(`\x1b[90m${PREFIX}\x1b[0m`, ...messages) -} +const debug = console.debug.bind(console, `\x1b[90m${PREFIX}\x1b[0m`) function sendMessage(message: { type: 'TAB_CONTROL' From 312952ec41be0c2fe02fd1d1a2f870249a09b629 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:24:24 +0800 Subject: [PATCH 20/40] fix(ext): multi window errors --- .../src/agent/TabsController.background.ts | 14 ++++++------- .../extension/src/agent/TabsController.ts | 20 +++++++++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/extension/src/agent/TabsController.background.ts b/packages/extension/src/agent/TabsController.background.ts index 60ba212..79705d1 100644 --- a/packages/extension/src/agent/TabsController.background.ts +++ b/packages/extension/src/agent/TabsController.background.ts @@ -19,11 +19,10 @@ export function handleTabControlMessage( case 'get_active_tab': { debug('get_active_tab') chrome.tabs - .query({ active: true, currentWindow: true }) + .query({ active: true }) .then((tabs) => { - const tabId = tabs.length > 0 ? tabs[0].id || null : null - debug('get_active_tab: success', tabId) - sendResponse({ success: true, tabId }) + debug('get_active_tab: success', tabs) + sendResponse({ success: true, tab: tabs[0] }) }) .catch((error) => { sendResponse({ error: error instanceof Error ? error.message : String(error) }) @@ -62,7 +61,7 @@ export function handleTabControlMessage( case 'create_tab_group': { debug('create_tab_group', payload) chrome.tabs - .group({ tabIds: payload.tabIds }) + .group({ tabIds: payload.tabIds, createProperties: { windowId: payload.windowId } }) .then((groupId) => { debug('create_tab_group: success', groupId) sendResponse({ success: true, groupId }) @@ -114,9 +113,9 @@ export function handleTabControlMessage( } case 'get_window_tabs': { - debug('get_window_tabs') + debug('get_window_tabs', payload) chrome.tabs - .query({ currentWindow: true }) + .query({ windowId: payload.windowId }) .then((tabs) => { sendResponse({ success: true, tabs }) }) @@ -133,6 +132,7 @@ export function handleTabControlMessage( } export function setupTabChangeEvents() { + // @note It's normal to catch errors here before `TabsController.init()` console.log('[TabsController.background] setupTabChangeEvents') chrome.tabs.onCreated.addListener((tab) => { diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index 5492273..f8f04ea 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -23,6 +23,7 @@ function sendMessage(message: { export class TabsController extends EventTarget { currentTabId: number | null = null + private windowId: number | null = null private tabs: TabMeta[] = [] private initialTabId: number | null = null private tabGroupId: number | null = null @@ -34,27 +35,34 @@ export class TabsController extends EventTarget { debug('init', task, options) this.task = task + this.windowId = null this.tabs = [] this.currentTabId = null this.tabGroupId = null this.initialTabId = null this.experimentalIncludeAllTabs = experimentalIncludeAllTabs - const result = await sendMessage({ + const activeTabResult = await sendMessage({ type: 'TAB_CONTROL', action: 'get_active_tab', }) - this.initialTabId = result.tabId + this.initialTabId = activeTabResult.tab?.id + this.windowId = activeTabResult.tab?.windowId - if (!this.initialTabId) { - throw new Error('Failed to get initial tab ID') + if (!this.initialTabId || !this.windowId) { + if (activeTabResult.error) { + throw new Error(activeTabResult.error) + } else { + throw new Error('Failed to get active tab') + } } if (experimentalIncludeAllTabs) { const allTabs = await sendMessage({ type: 'TAB_CONTROL', action: 'get_window_tabs', + payload: { windowId: this.windowId }, }) for (const tab of allTabs.tabs as chrome.tabs.Tab[]) { if (tab.id && !tab.pinned && isContentScriptAllowed(tab.url)) { @@ -82,7 +90,7 @@ export class TabsController extends EventTarget { this.currentTabId = this.initialTabId this.tabs.push({ - id: result.tabId, + id: this.initialTabId, isInitial: true, url: info.url, title: info.title, @@ -229,7 +237,7 @@ export class TabsController extends EventTarget { const result = await sendMessage({ type: 'TAB_CONTROL', action: 'create_tab_group', - payload: { tabIds }, + payload: { tabIds, windowId: this.windowId }, }) if (!result?.success) { From cad033d63bd41dfa55315c52d63a6170b18bf148 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:25:04 +0800 Subject: [PATCH 21/40] feat(ext): add `experimentalIncludeAllTabs` UI --- packages/extension/src/agent/useAgent.ts | 2 ++ packages/extension/src/components/ConfigPanel.tsx | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/packages/extension/src/agent/useAgent.ts b/packages/extension/src/agent/useAgent.ts index 97d0a39..c6a31bf 100644 --- a/packages/extension/src/agent/useAgent.ts +++ b/packages/extension/src/agent/useAgent.ts @@ -126,6 +126,7 @@ export function useAgent(): UseAgentResult { maxSteps, systemInstruction, experimentalLlmsTxt, + experimentalIncludeAllTabs, disableNamedToolChoice, ...llmConfig }: ExtConfig) => { @@ -139,6 +140,7 @@ export function useAgent(): UseAgentResult { maxSteps, systemInstruction, experimentalLlmsTxt, + experimentalIncludeAllTabs, disableNamedToolChoice, } await chrome.storage.local.set({ advancedConfig }) diff --git a/packages/extension/src/components/ConfigPanel.tsx b/packages/extension/src/components/ConfigPanel.tsx index 0a0c338..d7a2d9f 100644 --- a/packages/extension/src/components/ConfigPanel.tsx +++ b/packages/extension/src/components/ConfigPanel.tsx @@ -36,6 +36,9 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { const [experimentalLlmsTxt, setExperimentalLlmsTxt] = useState( config?.experimentalLlmsTxt ?? false ) + const [experimentalIncludeAllTabs, setExperimentalIncludeAllTabs] = useState( + config?.experimentalIncludeAllTabs ?? false + ) const [disableNamedToolChoice, setDisableNamedToolChoice] = useState( config?.disableNamedToolChoice ?? false ) @@ -54,6 +57,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { setMaxSteps(config?.maxSteps) setSystemInstruction(config?.systemInstruction ?? '') setExperimentalLlmsTxt(config?.experimentalLlmsTxt ?? false) + setExperimentalIncludeAllTabs(config?.experimentalIncludeAllTabs ?? false) setDisableNamedToolChoice(config?.disableNamedToolChoice ?? false) }, [config]) @@ -100,6 +104,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { maxSteps: maxSteps || undefined, systemInstruction: systemInstruction || undefined, experimentalLlmsTxt, + experimentalIncludeAllTabs, disableNamedToolChoice, }) } finally { @@ -285,6 +290,14 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) { Experimental llms.txt support + + )} From 49b137981cf9f395895e72465003083aadbe3cbf Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:40:16 +0800 Subject: [PATCH 22/40] fix(ext): tab events do not work for content scripts --- .../src/agent/TabsController.background.ts | 57 ++++---- .../extension/src/agent/TabsController.ts | 132 +++++++++++------- .../extension/src/entrypoints/background.ts | 4 +- 3 files changed, 112 insertions(+), 81 deletions(-) diff --git a/packages/extension/src/agent/TabsController.background.ts b/packages/extension/src/agent/TabsController.background.ts index 79705d1..5b4baff 100644 --- a/packages/extension/src/agent/TabsController.background.ts +++ b/packages/extension/src/agent/TabsController.background.ts @@ -6,7 +6,6 @@ import type { TabAction } from './TabsController' const PREFIX = '[TabsController.background]' const debug = console.debug.bind(console, `\x1b[90m${PREFIX}\x1b[0m`) -const debugError = console.error.bind(console, `\x1b[91m${PREFIX}\x1b[0m`) export function handleTabControlMessage( message: { type: 'TAB_CONTROL'; action: TabAction; payload: any }, @@ -131,42 +130,40 @@ export function handleTabControlMessage( } } -export function setupTabChangeEvents() { - // @note It's normal to catch errors here before `TabsController.init()` - console.log('[TabsController.background] setupTabChangeEvents') +const tabEventPorts = new Set() + +function broadcastTabEvent(message: object) { + for (const port of tabEventPorts) { + port.postMessage(message) + } +} + +/** + * Port-based tab events: agents connect via `chrome.runtime.connect({ name: 'tab-events' })` + * and receive tab change events through the port. Works for both extension pages and content scripts. + */ +export function setupTabEventsPort() { + chrome.runtime.onConnect.addListener((port) => { + if (port.name !== 'tab-events') return + + debug('port connected', port.sender?.tab?.id ?? port.sender?.url) + tabEventPorts.add(port) + + port.onDisconnect.addListener(() => { + debug('port disconnected') + tabEventPorts.delete(port) + }) + }) chrome.tabs.onCreated.addListener((tab) => { - debug('onCreated', tab) - chrome.runtime - .sendMessage({ type: 'TAB_CHANGE', action: 'created', payload: { tab } }) - .catch((error) => { - debugError('onCreated error:', error) - }) + broadcastTabEvent({ action: 'created', payload: { tab } }) }) chrome.tabs.onRemoved.addListener((tabId, removeInfo) => { - debug('onRemoved', tabId, removeInfo) - chrome.runtime - .sendMessage({ - type: 'TAB_CHANGE', - action: 'removed', - payload: { tabId, removeInfo }, - }) - .catch((error) => { - debugError('onRemoved error:', error) - }) + broadcastTabEvent({ action: 'removed', payload: { tabId, removeInfo } }) }) chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - debug('onUpdated', tabId, changeInfo) - chrome.runtime - .sendMessage({ - type: 'TAB_CHANGE', - action: 'updated', - payload: { tabId, changeInfo, tab }, - }) - .catch((error) => { - debugError('onUpdated error:', error) - }) + broadcastTabEvent({ action: 'updated', payload: { tabId, changeInfo, tab } }) }) } diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index f8f04ea..b21e7af 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -20,9 +20,13 @@ function sendMessage(message: { * - live in the agent env (extension page or content script) * - no chrome apis. call sw for tab operations */ -export class TabsController extends EventTarget { +export class TabsController { currentTabId: number | null = null + private disposed = false + private port: chrome.runtime.Port | null = null + private portRetries = 0 + private windowId: number | null = null private tabs: TabMeta[] = [] private initialTabId: number | null = null @@ -34,13 +38,21 @@ export class TabsController extends EventTarget { const { includeInitialTab = true, experimentalIncludeAllTabs = false } = options debug('init', task, options) - this.task = task + if (this.disposed) { + throw new Error('TabsController already disposed') + } + + this.currentTabId = null + this.disposed = false + this.port = null + this.portRetries = 0 + this.windowId = null this.tabs = [] - this.currentTabId = null this.tabGroupId = null this.initialTabId = null this.experimentalIncludeAllTabs = experimentalIncludeAllTabs + this.task = task const activeTabResult = await sendMessage({ type: 'TAB_CONTROL', @@ -58,6 +70,8 @@ export class TabsController extends EventTarget { } } + this.connectTabEvents() + if (experimentalIncludeAllTabs) { const allTabs = await sendMessage({ type: 'TAB_CONTROL', @@ -102,51 +116,6 @@ export class TabsController extends EventTarget { } await this.updateCurrentTabId(this.currentTabId) - - const tabChangeHandler = (message: any): void => { - if (message.type !== 'TAB_CHANGE') { - return - } - - if (message.action === 'created') { - const tab = message.payload.tab as chrome.tabs.Tab - const shouldTrack = this.experimentalIncludeAllTabs || tab.groupId === this.tabGroupId - if (shouldTrack && tab.id != null) { - if (!this.tabs.find((t) => t.id === tab.id)) { - this.tabs.push({ id: tab.id, isInitial: false }) - } - this.switchToTab(tab.id) - } - } else if (message.action === 'removed') { - const { tabId } = message.payload as { tabId: number } - const targetTab = this.tabs.find((t) => t.id === tabId) - if (targetTab) { - this.tabs = this.tabs.filter((t) => t.id !== tabId) - if (this.currentTabId === tabId) { - const newCurrentTab = this.tabs[this.tabs.length - 1] || null - if (newCurrentTab) { - this.switchToTab(newCurrentTab.id) - } else { - this.updateCurrentTabId(null) - } - } - } - } else if (message.action === 'updated') { - const { tabId, tab } = message.payload as { tabId: number; tab: chrome.tabs.Tab } - const targetTab = this.tabs.find((t) => t.id === tabId) - if (targetTab) { - targetTab.url = tab.url - targetTab.title = tab.title - targetTab.status = tab.status - } - } - } - - chrome.runtime.onMessage.addListener(tabChangeHandler) - - this.addEventListener('dispose', () => { - chrome.runtime.onMessage.removeListener(tabChangeHandler) - }) } async openNewTab(url: string): Promise { @@ -316,8 +285,73 @@ export class TabsController extends EventTarget { await waitUntil(() => tab.status === 'complete', 4_000) } + /** + * Connect to background SW via port to receive tab change events. + * + * @note Port is 1:1 (runtime.connect → background SW has no frames), + * so onDisconnect fires exactly once and we can safely reconnect. + * Reconnection may miss events during the gap. + * TODO: refresh this.tabs from background after reconnect to stay consistent. + */ + private connectTabEvents() { + this.port = chrome.runtime.connect({ name: 'tab-events' }) + + this.port.onMessage.addListener((message: any) => { + if (this.disposed) return + this.portRetries = 0 + + if (message.action === 'created') { + const tab = message.payload.tab as chrome.tabs.Tab + const shouldTrack = this.experimentalIncludeAllTabs || tab.groupId === this.tabGroupId + if (shouldTrack && tab.id != null) { + if (!this.tabs.find((t) => t.id === tab.id)) { + this.tabs.push({ id: tab.id, isInitial: false }) + } + this.switchToTab(tab.id) + } + } else if (message.action === 'removed') { + const { tabId } = message.payload as { tabId: number } + const targetTab = this.tabs.find((t) => t.id === tabId) + if (targetTab) { + this.tabs = this.tabs.filter((t) => t.id !== tabId) + if (this.currentTabId === tabId) { + const newCurrentTab = this.tabs[this.tabs.length - 1] || null + if (newCurrentTab) { + this.switchToTab(newCurrentTab.id) + } else { + this.updateCurrentTabId(null) + } + } + } + } else if (message.action === 'updated') { + const { tabId, tab } = message.payload as { tabId: number; tab: chrome.tabs.Tab } + const targetTab = this.tabs.find((t) => t.id === tabId) + if (targetTab) { + targetTab.url = tab.url + targetTab.title = tab.title + targetTab.status = tab.status + } + } + }) + + this.port.onDisconnect.addListener(() => { + this.port = null + if (this.disposed) return + if (this.portRetries >= 7) { + console.error(PREFIX, 'tab events port failed after 3 retries, giving up') + return + } + debug('port disconnected, reconnecting...') + this.portRetries++ + this.connectTabEvents() + }) + } + dispose() { - this.dispatchEvent(new Event('dispose')) + debug('dispose') + this.disposed = true + this.port?.disconnect() + this.port = null } } diff --git a/packages/extension/src/entrypoints/background.ts b/packages/extension/src/entrypoints/background.ts index 9c26f96..a83fde3 100644 --- a/packages/extension/src/entrypoints/background.ts +++ b/packages/extension/src/entrypoints/background.ts @@ -1,12 +1,12 @@ import { handlePageControlMessage } from '@/agent/RemotePageController.background' -import { handleTabControlMessage, setupTabChangeEvents } from '@/agent/TabsController.background' +import { handleTabControlMessage, setupTabEventsPort } from '@/agent/TabsController.background' export default defineBackground(() => { console.log('[Background] Service Worker started') // tab change events - setupTabChangeEvents() + setupTabEventsPort() // generate user auth token From 0b4eb6b49a6df4e9827c5bd888173041f03e4144 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:08:09 +0800 Subject: [PATCH 23/40] docs(ext): experimentalIncludeAllTabs --- packages/extension/docs/extension_api.md | 6 ++++++ .../src/pages/docs/features/chrome-extension/page.tsx | 3 +++ 2 files changed, 9 insertions(+) diff --git a/packages/extension/docs/extension_api.md b/packages/extension/docs/extension_api.md index d49272d..d7dc902 100644 --- a/packages/extension/docs/extension_api.md +++ b/packages/extension/docs/extension_api.md @@ -121,6 +121,11 @@ export interface ExecuteConfig { // Include the initial tab where page JS starts. Default: true. includeInitialTab?: boolean + // Control all unpinned tabs in the window instead of only the tab group. + // When enabled, agent sees and can switch to every non-pinned tab. + // Default: false. Experimental. + experimentalIncludeAllTabs?: boolean + onStatusChange?: (status: AgentStatus) => void onActivity?: (activity: AgentActivity) => void onHistoryUpdate?: (history: HistoricalEvent[]) => void @@ -208,6 +213,7 @@ interface ExecuteConfig { model: string apiKey?: string includeInitialTab?: boolean + experimentalIncludeAllTabs?: boolean onStatusChange?: (status: AgentStatus) => void onActivity?: (activity: AgentActivity) => void onHistoryUpdate?: (history: HistoricalEvent[]) => void diff --git a/packages/website/src/pages/docs/features/chrome-extension/page.tsx b/packages/website/src/pages/docs/features/chrome-extension/page.tsx index b97f9d7..acee2a6 100644 --- a/packages/website/src/pages/docs/features/chrome-extension/page.tsx +++ b/packages/website/src/pages/docs/features/chrome-extension/page.tsx @@ -200,6 +200,7 @@ interface ExecuteConfig { apiKey?: string // LLM AK includeInitialTab?: boolean + experimentalIncludeAllTabs?: boolean // Control all unpinned tabs in the window onStatusChange?: (status: AgentStatus) => void onActivity?: (activity: AgentActivity) => void onHistoryUpdate?: (history: HistoricalEvent[]) => void @@ -233,6 +234,7 @@ const result = await window.PAGE_AGENT_EXT.execute( apiKey: 'your-api-key', model: 'gpt-5.2', // includeInitialTab: false, // 设为 false 排除初始标签页 + // experimentalIncludeAllTabs: true, // 控制窗口内所有非固定标签页 onStatusChange: status => console.log('状态变化:', status), onActivity: activity => console.log('活动:', activity), onHistoryUpdate: history => console.log('历史更新:', history) @@ -248,6 +250,7 @@ const result = await window.PAGE_AGENT_EXT.execute( apiKey: 'your-api-key', model: 'gpt-5.2', // includeInitialTab: false, // Set to false to exclude initial tab + // experimentalIncludeAllTabs: true, // Control all unpinned tabs in the window onStatusChange: status => console.log('Status change:', status), onActivity: activity => console.log('Activity:', activity), onHistoryUpdate: history => console.log('History update:', history) From 1eef785a61789c4f407cdd89da94d85c94418d31 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:18:55 +0800 Subject: [PATCH 24/40] fix(ext): tabs deduplication --- packages/extension/src/agent/TabsController.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index b21e7af..b30a409 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -80,7 +80,7 @@ export class TabsController { }) for (const tab of allTabs.tabs as chrome.tabs.Tab[]) { if (tab.id && !tab.pinned && isContentScriptAllowed(tab.url)) { - this.tabs.push({ + this.addTab({ id: tab.id, isInitial: tab.id === this.initialTabId, url: tab.url, @@ -103,7 +103,7 @@ export class TabsController { if (isContentScriptAllowed(info.url) && !info.pinned) { this.currentTabId = this.initialTabId - this.tabs.push({ + this.addTab({ id: this.initialTabId, isInitial: true, url: info.url, @@ -133,7 +133,7 @@ export class TabsController { const tabId = result.tabId as number - this.tabs.push({ + this.addTab({ id: tabId, isInitial: false, }) @@ -229,6 +229,11 @@ export class TabsController { }) } + private addTab(meta: TabMeta) { + if (this.tabs.find((t) => t.id === meta.id)) return + this.tabs.push(meta) + } + async updateCurrentTabId(tabId: number | null) { debug('updateCurrentTabId', tabId) @@ -304,9 +309,7 @@ export class TabsController { const tab = message.payload.tab as chrome.tabs.Tab const shouldTrack = this.experimentalIncludeAllTabs || tab.groupId === this.tabGroupId if (shouldTrack && tab.id != null) { - if (!this.tabs.find((t) => t.id === tab.id)) { - this.tabs.push({ id: tab.id, isInitial: false }) - } + this.addTab({ id: tab.id, isInitial: false }) this.switchToTab(tab.id) } } else if (message.action === 'removed') { From c465fd8aa4fc18313ba1e5ae8a3e8ed84a808b0d Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Mon, 30 Mar 2026 22:29:03 +0800 Subject: [PATCH 25/40] chore(version): bump version to 1.6.3 --- README.md | 4 +-- docs/README-zh.md | 4 +-- package-lock.json | 40 +++++++++++++-------------- package.json | 2 +- packages/core/package.json | 6 ++-- packages/extension/package.json | 10 +++---- packages/llms/package.json | 2 +- packages/mcp/package.json | 2 +- packages/page-agent/package.json | 10 +++---- packages/page-controller/package.json | 2 +- packages/ui/package.json | 2 +- packages/website/package.json | 2 +- packages/website/src/constants.ts | 4 +-- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 0edc496..f7252d5 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ Fastest way to try PageAgent with our free Demo LLM: | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js | ### NPM Installation diff --git a/docs/README-zh.md b/docs/README-zh.md index 0406773..5a3eb54 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -49,8 +49,8 @@ | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js | ### NPM 安装 diff --git a/package-lock.json b/package-lock.json index 2675f70..939e734 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "root", - "version": "1.6.2", + "version": "1.6.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "root", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "workspaces": [ "packages/page-controller", @@ -11799,11 +11799,11 @@ }, "packages/core": { "name": "@page-agent/core", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2", + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3", "chalk": "^5.6.2" }, "devDependencies": { @@ -11815,13 +11815,13 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "1.6.2", + "version": "1.6.3", "hasInstallScript": true, "dependencies": { - "@page-agent/core": "1.6.2", - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2", - "@page-agent/ui": "1.6.2", + "@page-agent/core": "1.6.3", + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3", + "@page-agent/ui": "1.6.3", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, @@ -11858,7 +11858,7 @@ }, "packages/llms": { "name": "@page-agent/llms", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { "chalk": "^5.6.2" @@ -11872,7 +11872,7 @@ }, "packages/mcp": { "name": "@page-agent/mcp", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", @@ -11887,13 +11887,13 @@ } }, "packages/page-agent": { - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { - "@page-agent/core": "1.6.2", - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2", - "@page-agent/ui": "1.6.2", + "@page-agent/core": "1.6.3", + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3", + "@page-agent/ui": "1.6.3", "chalk": "^5.6.2" }, "devDependencies": { @@ -11905,7 +11905,7 @@ }, "packages/page-controller": { "name": "@page-agent/page-controller", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT", "dependencies": { "ai-motion": "^0.4.8" @@ -11913,12 +11913,12 @@ }, "packages/ui": { "name": "@page-agent/ui", - "version": "1.6.2", + "version": "1.6.3", "license": "MIT" }, "packages/website": { "name": "@page-agent/website", - "version": "1.6.2", + "version": "1.6.3", "devDependencies": { "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-separator": "^1.1.8", diff --git a/package.json b/package.json index 14fd8fe..03037d1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "root", "private": true, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "workspaces": [ "packages/page-controller", diff --git a/packages/core/package.json b/packages/core/package.json index 6c750ea..b30afec 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/core", "private": false, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "main": "./dist/esm/page-agent-core.js", "module": "./dist/esm/page-agent-core.js", @@ -44,8 +44,8 @@ }, "dependencies": { "chalk": "^5.6.2", - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2" + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" diff --git a/packages/extension/package.json b/packages/extension/package.json index e40a192..f944ffa 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "scripts": { "dev": "wxt", @@ -37,10 +37,10 @@ "wxt": "^0.20.20" }, "dependencies": { - "@page-agent/core": "1.6.2", - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2", - "@page-agent/ui": "1.6.2", + "@page-agent/core": "1.6.3", + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3", + "@page-agent/ui": "1.6.3", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, diff --git a/packages/llms/package.json b/packages/llms/package.json index 6479db1..9aff1f5 100644 --- a/packages/llms/package.json +++ b/packages/llms/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/llms", - "version": "1.6.2", + "version": "1.6.3", "type": "module", "main": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 6ba3da1..923181f 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/mcp", "private": false, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "bin": { "page-agent-mcp": "src/index.js" diff --git a/packages/page-agent/package.json b/packages/page-agent/package.json index 3f650f2..1229b2c 100644 --- a/packages/page-agent/package.json +++ b/packages/page-agent/package.json @@ -1,7 +1,7 @@ { "name": "page-agent", "private": false, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "main": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js", @@ -44,10 +44,10 @@ "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" }, "dependencies": { - "@page-agent/core": "1.6.2", - "@page-agent/llms": "1.6.2", - "@page-agent/page-controller": "1.6.2", - "@page-agent/ui": "1.6.2", + "@page-agent/core": "1.6.3", + "@page-agent/llms": "1.6.3", + "@page-agent/page-controller": "1.6.3", + "@page-agent/ui": "1.6.3", "chalk": "^5.6.2" }, "peerDependencies": { diff --git a/packages/page-controller/package.json b/packages/page-controller/package.json index 1341693..144447c 100644 --- a/packages/page-controller/package.json +++ b/packages/page-controller/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/page-controller", - "version": "1.6.2", + "version": "1.6.3", "type": "module", "main": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js", diff --git a/packages/ui/package.json b/packages/ui/package.json index e1b5da0..c256bab 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/ui", - "version": "1.6.2", + "version": "1.6.3", "type": "module", "main": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js", diff --git a/packages/website/package.json b/packages/website/package.json index 6ff6349..b571983 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/website", "private": true, - "version": "1.6.2", + "version": "1.6.3", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/packages/website/src/constants.ts b/packages/website/src/constants.ts index cd71d3c..bc32665 100644 --- a/packages/website/src/constants.ts +++ b/packages/website/src/constants.ts @@ -1,8 +1,8 @@ // Demo build (auto-init with demo LLM, for quick testing) export const CDN_DEMO_URL = - 'https://cdn.jsdelivr.net/npm/page-agent@1.6.2/dist/iife/page-agent.demo.js' + 'https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js' export const CDN_DEMO_CN_URL = - 'https://registry.npmmirror.com/page-agent/1.6.2/files/dist/iife/page-agent.demo.js' + 'https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js' // Demo LLM for website testing (homepage quick trial uses flash) export const DEMO_MODEL = 'qwen3.5-flash' From f2b6c9dfd27a3c460318eede9c3e1998b5f80418 Mon Sep 17 00:00:00 2001 From: liuguiyuan <875079152@qq.com> Date: Tue, 31 Mar 2026 00:57:44 +0800 Subject: [PATCH 26/40] fix: use hasAttribute with known aria list for interactive candidate detection Replace broken el.hasAttribute("aria-") with a curated list of 27 aria attributes checked via hasAttribute. Each check is O(1). WAI-ARIA 1.2 defines ~50 aria attributes total per MDN. Of these ~27 appear on interactive elements such as buttons, inputs, sliders, and dialogs. The remaining ~20 are structural container attributes like aria-live, aria-colcount, and aria-rowspan that only appear on non-interactive containers. Checking them would not change results. --- .../page-controller/src/dom/dom_tree/index.js | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/page-controller/src/dom/dom_tree/index.js b/packages/page-controller/src/dom/dom_tree/index.js index 782ad58..9166612 100644 --- a/packages/page-controller/src/dom/dom_tree/index.js +++ b/packages/page-controller/src/dom/dom_tree/index.js @@ -1143,6 +1143,43 @@ export default ( * @param {HTMLElement} element - The element to check. * @returns {boolean} Whether the element is an interactive candidate. */ + const INTERACTIVE_ARIA_ATTRS = [ + 'aria-label', + 'aria-labelledby', + 'aria-describedby', + 'aria-expanded', + 'aria-checked', + 'aria-selected', + 'aria-pressed', + 'aria-hidden', + 'aria-haspopup', + 'aria-controls', + 'aria-owns', + 'aria-current', + 'aria-disabled', + 'aria-live', + 'aria-modal', + 'aria-activedescendant', + 'aria-valuenow', + 'aria-valuetext', + 'aria-valuemax', + 'aria-valuemin', + 'aria-autocomplete', + 'aria-invalid', + 'aria-required', + 'aria-level', + 'aria-sort', + 'aria-orientation', + 'aria-multiline', + ] + + function hasAriaAttribute(el) { + for (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) { + if (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true + } + return false + } + function isInteractiveCandidate(element) { if (!element || element.nodeType !== Node.ELEMENT_NODE) return false @@ -1167,7 +1204,7 @@ export default ( element.hasAttribute('onclick') || element.hasAttribute('role') || element.hasAttribute('tabindex') || - element.hasAttribute('aria-') || + hasAriaAttribute(element) || element.hasAttribute('data-action') || element.getAttribute('contenteditable') === 'true' From 6d46719fe83ac76e024a7b466a4c63b2dcf3cfb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:21:07 +0000 Subject: [PATCH 27/40] chore(deps): bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [actions/configure-pages](https://github.com/actions/configure-pages) and [actions/deploy-pages](https://github.com/actions/deploy-pages). Updates `actions/configure-pages` from 5 to 6 - [Release notes](https://github.com/actions/configure-pages/releases) - [Commits](https://github.com/actions/configure-pages/compare/v5...v6) Updates `actions/deploy-pages` from 4 to 5 - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](https://github.com/actions/deploy-pages/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/configure-pages dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/deploy-pages dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/deploy-demo.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml index c4e41a1..dc4ab55 100644 --- a/.github/workflows/deploy-demo.yml +++ b/.github/workflows/deploy-demo.yml @@ -28,7 +28,7 @@ jobs: run: npm run build:website - name: Setup Pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@v6 - name: Upload artifact uses: actions/upload-pages-artifact@v4 @@ -37,4 +37,4 @@ jobs: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 From 46d6c02c9575bd9a69435320a029e0a289e3d043 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:21:25 +0000 Subject: [PATCH 28/40] chore(deps): bump @modelcontextprotocol/sdk Bumps the production-dependencies group with 1 update: [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk). Updates `@modelcontextprotocol/sdk` from 1.27.1 to 1.29.0 - [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases) - [Commits](https://github.com/modelcontextprotocol/typescript-sdk/compare/v1.27.1...v1.29.0) --- updated-dependencies: - dependency-name: "@modelcontextprotocol/sdk" dependency-version: 1.29.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- packages/mcp/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 939e734..e1499e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1819,9 +1819,9 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.27.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", - "integrity": "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -11875,7 +11875,7 @@ "version": "1.6.3", "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.27.1", + "@modelcontextprotocol/sdk": "^1.29.0", "ws": "^8.20.0", "zod": "^4.3.5" }, diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 923181f..cbaec05 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -28,7 +28,7 @@ "node": ">=20" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.27.1", + "@modelcontextprotocol/sdk": "^1.29.0", "ws": "^8.20.0", "zod": "^4.3.5" } From 784627a7c180cb07d801ab3e58027a5f9981a6bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:22:53 +0000 Subject: [PATCH 29/40] chore(deps-dev): bump the development-dependencies group with 3 updates Bumps the development-dependencies group with 3 updates: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint), [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) and [simple-icons](https://github.com/simple-icons/simple-icons). Updates `typescript-eslint` from 8.57.2 to 8.58.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint) Updates `lucide-react` from 1.0.1 to 1.7.0 - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/commits/1.7.0/packages/lucide-react) Updates `simple-icons` from 16.13.0 to 16.14.0 - [Release notes](https://github.com/simple-icons/simple-icons/releases) - [Commits](https://github.com/simple-icons/simple-icons/compare/16.13.0...16.14.0) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: lucide-react dependency-version: 1.7.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: simple-icons dependency-version: 16.14.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 172 ++++++++++++++++---------------- package.json | 2 +- packages/extension/package.json | 4 +- packages/website/package.json | 4 +- 4 files changed, 91 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index 939e734..05b3df3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "lint-staged": "^16.4.0", "prettier": "^3.8.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.2", + "typescript-eslint": "^8.58.0", "unplugin-dts": "^1.0.0-beta.6", "vite": "^7.3.1", "vite-bundle-analyzer": "^1.3.6", @@ -3893,20 +3893,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/type-utils": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3916,9 +3916,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.2", + "@typescript-eslint/parser": "^8.58.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -3932,16 +3932,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3" }, "engines": { @@ -3953,18 +3953,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.2", - "@typescript-eslint/types": "^8.57.2", + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "engines": { @@ -3975,18 +3975,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3997,9 +3997,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, "license": "MIT", "engines": { @@ -4010,21 +4010,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4035,13 +4035,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", "dev": true, "license": "MIT", "engines": { @@ -4053,21 +4053,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4077,20 +4077,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4101,17 +4101,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -8296,9 +8296,9 @@ } }, "node_modules/lucide-react": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.0.1.tgz", - "integrity": "sha512-lih7tKEczCYOQjVEzpFuxEuNzlwf+1yhvlMlEkGWJM3va8Pugv8bYXc/pRtcjPncaP7k84X0Pt/71ufxvqEPtQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.7.0.tgz", + "integrity": "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg==", "dev": true, "license": "ISC", "peerDependencies": { @@ -10114,9 +10114,9 @@ } }, "node_modules/simple-icons": { - "version": "16.13.0", - "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.13.0.tgz", - "integrity": "sha512-N4AMZvFERU5YLEtUudtUesiM2H4O5xQ9qfS3K0oOV5II5KVtxOUAlmZ7KqBgiTSGBgCVkuLD/Z9dJKBtnI3kKQ==", + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-16.14.0.tgz", + "integrity": "sha512-2Nvs3jJpCfMWQerD4zdv91g/MpnWn81a7uhyAC0reuhrjmS2MtSmwIKwewOJR6Xe97ZmfltDntCDqKJIBawQOw==", "dev": true, "funding": [ { @@ -10549,9 +10549,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -10683,16 +10683,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz", + "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2" + "@typescript-eslint/eslint-plugin": "8.58.0", + "@typescript-eslint/parser": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10703,7 +10703,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/ufo": { @@ -11839,13 +11839,13 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "idb": "^8.0.3", - "lucide-react": "^1.0.1", + "lucide-react": "^1.7.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.13.0", + "simple-icons": "^16.14.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", @@ -11929,13 +11929,13 @@ "@types/react-dom": "^19.2.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.0.1", + "lucide-react": "^1.7.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.13.0", + "simple-icons": "^16.14.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", diff --git a/package.json b/package.json index 03037d1..b8f3a24 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "lint-staged": "^16.4.0", "prettier": "^3.8.0", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.2", + "typescript-eslint": "^8.58.0", "unplugin-dts": "^1.0.0-beta.6", "vite": "^7.3.1", "vite-plugin-css-injected-by-js": "^4.0.1", diff --git a/packages/extension/package.json b/packages/extension/package.json index f944ffa..aee4f70 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -23,13 +23,13 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "idb": "^8.0.3", - "lucide-react": "^1.0.1", + "lucide-react": "^1.7.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.13.0", + "simple-icons": "^16.14.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", diff --git a/packages/website/package.json b/packages/website/package.json index b571983..d784c19 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -19,13 +19,13 @@ "@types/react-dom": "^19.2.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.0.1", + "lucide-react": "^1.7.0", "motion": "^12.38.0", "next-themes": "^0.4.6", "react": "^19.2.4", "react-dom": "^19.2.4", "rough-notation": "^0.5.1", - "simple-icons": "^16.13.0", + "simple-icons": "^16.14.0", "sonner": "^2.0.7", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.1.14", From 32d6f0c74b7813ba012d5c5c199d8326cc86197f Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 17:41:49 +0800 Subject: [PATCH 30/40] fix(controller): click action robust --- packages/page-controller/src/actions.ts | 58 ++++++++++++++++--------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 92c7388..80fc73f 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -42,19 +42,20 @@ let lastClickedElement: HTMLElement | null = null function blurLastClickedElement() { if (lastClickedElement) { + lastClickedElement.dispatchEvent(new PointerEvent('pointerout', { bubbles: true })) + lastClickedElement.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false })) + lastClickedElement.dispatchEvent(new MouseEvent('mouseout', { bubbles: true })) + lastClickedElement.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false })) lastClickedElement.blur() - lastClickedElement.dispatchEvent( - new MouseEvent('mouseout', { bubbles: true, cancelable: true }) - ) - lastClickedElement.dispatchEvent( - new MouseEvent('mouseleave', { bubbles: false, cancelable: true }) - ) lastClickedElement = null } } /** - * Simulate a click on the element + * Simulate a full click following W3C Pointer Events + UI Events spec order: + * pointerover/enter → mouseover/enter → pointerdown → mousedown → [focus] → + * pointerup → mouseup → click + * * @private Internal method, subject to change at any time. */ export async function clickElement(element: HTMLElement) { @@ -63,7 +64,6 @@ export async function clickElement(element: HTMLElement) { lastClickedElement = element await scrollIntoViewIfNeeded(element) - // Scroll the iframe element itself into view if needed const frame = element.ownerDocument.defaultView?.frameElement if (frame) await scrollIntoViewIfNeeded(frame) @@ -72,23 +72,41 @@ export async function clickElement(element: HTMLElement) { await waitFor(0.1) - // hover it - element.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true, cancelable: true })) - element.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true })) + const rect = element.getBoundingClientRect() + const x = rect.left + rect.width / 2 + const y = rect.top + rect.height / 2 + const pointerOpts = { + bubbles: true, + cancelable: true, + clientX: x, + clientY: y, + pointerType: 'mouse' as const, + } + const mouseOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, button: 0 } - // dispatch a sequence of events to ensure all listeners are triggered - element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true })) + // Hover — pointer events first, then mouse events (spec order) + element.dispatchEvent(new PointerEvent('pointerover', pointerOpts)) + element.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false })) + element.dispatchEvent(new MouseEvent('mouseover', mouseOpts)) + element.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false })) - // focus it to ensure it gets the click event - element.focus() + // Press + element.dispatchEvent(new PointerEvent('pointerdown', pointerOpts)) + element.dispatchEvent(new MouseEvent('mousedown', mouseOpts)) - element.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true })) - element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })) + // Focus is not part of the standard "undefined and varies between user agents". + // Browsers implicitly focus focusable elements on mousedown as an internal behavior. + element.focus({ preventScroll: true }) - // dispatch a click event - // element.click() + // Release + element.dispatchEvent(new PointerEvent('pointerup', pointerOpts)) + element.dispatchEvent(new MouseEvent('mouseup', mouseOpts)) - await waitFor(0.2) // Wait to ensure click event processing completes + // Click — element.click() triggers default behaviors (e.g. navigation, + // form submission) that dispatchEvent(new MouseEvent('click')) may not. + element.click() + + await waitFor(0.2) } /** From 8eee3b27e27066038bd649804b35928c9e0f3877 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 19:59:57 +0800 Subject: [PATCH 31/40] feat(controller): fix `SimulatorMast` mem leak; add passthrough events --- .../page-controller/src/mask/SimulatorMask.ts | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/page-controller/src/mask/SimulatorMask.ts b/packages/page-controller/src/mask/SimulatorMask.ts index eb13eb6..41cbdb4 100644 --- a/packages/page-controller/src/mask/SimulatorMask.ts +++ b/packages/page-controller/src/mask/SimulatorMask.ts @@ -5,7 +5,7 @@ import { isPageDark } from './checkDarkMode' import styles from './SimulatorMask.module.css' import cursorStyles from './cursor.module.css' -export class SimulatorMask { +export class SimulatorMask extends EventTarget { shown: boolean = false wrapper = document.createElement('div') motion: Motion | null = null @@ -19,6 +19,8 @@ export class SimulatorMask { #targetCursorY = 0 constructor() { + super() + this.wrapper.id = 'page-agent-runtime_simulator-mask' this.wrapper.className = styles.wrapper this.wrapper.setAttribute('data-browser-use-ignore', 'true') @@ -74,13 +76,34 @@ export class SimulatorMask { this.#moveCursorToTarget() - window.addEventListener('PageAgent::MovePointerTo', (event: Event) => { + // global events + // @note Mask should be isolated from the rest of the code. + // Global events are easier to manage and cleanup. + + const movePointerToListener = (event: Event) => { const { x, y } = (event as CustomEvent).detail this.setCursorPosition(x, y) - }) - - window.addEventListener('PageAgent::ClickPointer', (event: Event) => { + } + const clickPointerListener = () => { this.triggerClickAnimation() + } + const enablePassThroughListener = () => { + this.wrapper.style.pointerEvents = 'none' + } + const disablePassThroughListener = () => { + this.wrapper.style.pointerEvents = 'auto' + } + + window.addEventListener('PageAgent::MovePointerTo', movePointerToListener) + window.addEventListener('PageAgent::ClickPointer', clickPointerListener) + window.addEventListener('PageAgent::EnablePassThrough', enablePassThroughListener) + window.addEventListener('PageAgent::DisablePassThrough', disablePassThroughListener) + + this.addEventListener('dispose', () => { + window.removeEventListener('PageAgent::MovePointerTo', movePointerToListener) + window.removeEventListener('PageAgent::ClickPointer', clickPointerListener) + window.removeEventListener('PageAgent::EnablePassThrough', enablePassThroughListener) + window.removeEventListener('PageAgent::DisablePassThrough', disablePassThroughListener) }) } @@ -177,7 +200,9 @@ export class SimulatorMask { } dispose() { + console.log('dispose SimulatorMask') this.motion?.dispose() this.wrapper.remove() + this.dispatchEvent(new Event('dispose')) } } From 296459924abef45c55b4ae1d6c07e35fbc486de2 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:02:39 +0800 Subject: [PATCH 32/40] feat(controller): enhance click action with `elementFromPoint` --- .../page-controller/src/PageController.ts | 1 + packages/page-controller/src/actions.ts | 46 +++++++++++++------ packages/page-controller/src/utils/index.ts | 14 +++++- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/packages/page-controller/src/PageController.ts b/packages/page-controller/src/PageController.ts index a8392ae..2439691 100644 --- a/packages/page-controller/src/PageController.ts +++ b/packages/page-controller/src/PageController.ts @@ -218,6 +218,7 @@ export class PageController extends EventTarget { * Clean up all element highlights */ async cleanUpHighlights(): Promise { + console.log('[PageController] cleanUpHighlights') dom.cleanUpHighlights() } diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 80fc73f..3198bc3 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -4,6 +4,9 @@ */ import type { InteractiveElementDomNode } from './dom/dom_tree/type' import { + clickPointer, + disablePassThrough, + enablePassThrough, getNativeValueSetter, isHTMLElement, isInputElement, @@ -68,43 +71,56 @@ export async function clickElement(element: HTMLElement) { if (frame) await scrollIntoViewIfNeeded(frame) await movePointerToElement(element) - window.dispatchEvent(new CustomEvent('PageAgent::ClickPointer')) + await clickPointer() await waitFor(0.1) const rect = element.getBoundingClientRect() const x = rect.left + rect.width / 2 const y = rect.top + rect.height / 2 + + // Hit-test to find the deepest element at click coordinates, matching + // real browser behavior where events target the innermost element. + // @note This may hit a element in the blacklist + // TODO: This is a temporary workaround. Should have been handled during dom extraction. + const doc = element.ownerDocument + await enablePassThrough() + const hitTarget = doc.elementFromPoint(x, y) + await disablePassThrough() + const target = + hitTarget instanceof HTMLElement && element.contains(hitTarget) ? hitTarget : element + const pointerOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, - pointerType: 'mouse' as const, + pointerType: 'mouse', } const mouseOpts = { bubbles: true, cancelable: true, clientX: x, clientY: y, button: 0 } // Hover — pointer events first, then mouse events (spec order) - element.dispatchEvent(new PointerEvent('pointerover', pointerOpts)) - element.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false })) - element.dispatchEvent(new MouseEvent('mouseover', mouseOpts)) - element.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false })) + target.dispatchEvent(new PointerEvent('pointerover', pointerOpts)) + target.dispatchEvent(new PointerEvent('pointerenter', { ...pointerOpts, bubbles: false })) + target.dispatchEvent(new MouseEvent('mouseover', mouseOpts)) + target.dispatchEvent(new MouseEvent('mouseenter', { ...mouseOpts, bubbles: false })) // Press - element.dispatchEvent(new PointerEvent('pointerdown', pointerOpts)) - element.dispatchEvent(new MouseEvent('mousedown', mouseOpts)) + target.dispatchEvent(new PointerEvent('pointerdown', pointerOpts)) + target.dispatchEvent(new MouseEvent('mousedown', mouseOpts)) - // Focus is not part of the standard "undefined and varies between user agents". - // Browsers implicitly focus focusable elements on mousedown as an internal behavior. + // Focus is not part of the standard pointer/mouse event sequence + // "undefined and varies between user agents". + // We focus the original element (nearest focusable ancestor), not the hit-test target, matching browser behavior. element.focus({ preventScroll: true }) // Release - element.dispatchEvent(new PointerEvent('pointerup', pointerOpts)) - element.dispatchEvent(new MouseEvent('mouseup', mouseOpts)) + target.dispatchEvent(new PointerEvent('pointerup', pointerOpts)) + target.dispatchEvent(new MouseEvent('mouseup', mouseOpts)) - // Click — element.click() triggers default behaviors (e.g. navigation, - // form submission) that dispatchEvent(new MouseEvent('click')) may not. - element.click() + // Click — activation behavior (navigation, form submit, etc.) triggers + // via bubbling from target up to the interactive ancestor. + target.click() await waitFor(0.2) } diff --git a/packages/page-controller/src/utils/index.ts b/packages/page-controller/src/utils/index.ts index 7f651a2..97b8b89 100644 --- a/packages/page-controller/src/utils/index.ts +++ b/packages/page-controller/src/utils/index.ts @@ -48,7 +48,7 @@ export async function waitFor(seconds: number): Promise { await new Promise((resolve) => setTimeout(resolve, seconds * 1000)) } -// ======= dom utils ======= +// ======= mask events ======= export async function movePointerToElement(element: HTMLElement) { const rect = element.getBoundingClientRect() @@ -60,3 +60,15 @@ export async function movePointerToElement(element: HTMLElement) { await waitFor(0.3) } + +export async function clickPointer() { + window.dispatchEvent(new CustomEvent('PageAgent::ClickPointer')) +} + +export async function enablePassThrough() { + window.dispatchEvent(new CustomEvent('PageAgent::EnablePassThrough')) +} + +export async function disablePassThrough() { + window.dispatchEvent(new CustomEvent('PageAgent::DisablePassThrough')) +} From 2b20b48dffbdd105e7d433538e60b453410b5378 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:27:04 +0800 Subject: [PATCH 33/40] chore(controller): reuse pointer xy --- packages/page-controller/src/actions.ts | 10 +++++----- packages/page-controller/src/utils/index.ts | 16 +++++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/page-controller/src/actions.ts b/packages/page-controller/src/actions.ts index 3198bc3..8a86fa7 100644 --- a/packages/page-controller/src/actions.ts +++ b/packages/page-controller/src/actions.ts @@ -70,15 +70,15 @@ export async function clickElement(element: HTMLElement) { const frame = element.ownerDocument.defaultView?.frameElement if (frame) await scrollIntoViewIfNeeded(frame) - await movePointerToElement(element) - await clickPointer() - - await waitFor(0.1) - const rect = element.getBoundingClientRect() const x = rect.left + rect.width / 2 const y = rect.top + rect.height / 2 + await movePointerToElement(element, x, y) + await clickPointer() + + await waitFor(0.1) + // Hit-test to find the deepest element at click coordinates, matching // real browser behavior where events target the innermost element. // @note This may hit a element in the blacklist diff --git a/packages/page-controller/src/utils/index.ts b/packages/page-controller/src/utils/index.ts index 97b8b89..885357d 100644 --- a/packages/page-controller/src/utils/index.ts +++ b/packages/page-controller/src/utils/index.ts @@ -50,13 +50,19 @@ export async function waitFor(seconds: number): Promise { // ======= mask events ======= -export async function movePointerToElement(element: HTMLElement) { - const rect = element.getBoundingClientRect() +/** + * Move the visual pointer to a position within an element. + * @param x - x coordinate in the element's document viewport + * @param y - y coordinate in the element's document viewport + */ +export async function movePointerToElement(element: HTMLElement, x: number, y: number) { const offset = getIframeOffset(element) - const x = rect.left + rect.width / 2 + offset.x - const y = rect.top + rect.height / 2 + offset.y - window.dispatchEvent(new CustomEvent('PageAgent::MovePointerTo', { detail: { x, y } })) + window.dispatchEvent( + new CustomEvent('PageAgent::MovePointerTo', { + detail: { x: x + offset.x, y: y + offset.y }, + }) + ) await waitFor(0.3) } From 6823e04ca9e57789debeb6c3363f1f4b7c12f426 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:45:12 +0800 Subject: [PATCH 34/40] chore(version): bump version to 1.7.0 --- README.md | 4 +-- docs/README-zh.md | 4 +-- package-lock.json | 40 +++++++++++++-------------- package.json | 2 +- packages/core/package.json | 6 ++-- packages/extension/package.json | 10 +++---- packages/llms/package.json | 2 +- packages/mcp/package.json | 2 +- packages/page-agent/package.json | 10 +++---- packages/page-controller/package.json | 2 +- packages/ui/package.json | 2 +- packages/website/package.json | 2 +- packages/website/src/constants.ts | 4 +-- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index f7252d5..05824f4 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,8 @@ Fastest way to try PageAgent with our free Demo LLM: | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.7.0/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.7.0/files/dist/iife/page-agent.demo.js | ### NPM Installation diff --git a/docs/README-zh.md b/docs/README-zh.md index 5a3eb54..1a025b8 100644 --- a/docs/README-zh.md +++ b/docs/README-zh.md @@ -49,8 +49,8 @@ | Mirrors | URL | | ------- | ---------------------------------------------------------------------------------- | -| Global | https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js | -| China | https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js | +| Global | https://cdn.jsdelivr.net/npm/page-agent@1.7.0/dist/iife/page-agent.demo.js | +| China | https://registry.npmmirror.com/page-agent/1.7.0/files/dist/iife/page-agent.demo.js | ### NPM 安装 diff --git a/package-lock.json b/package-lock.json index 6c47f44..3799cd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "root", - "version": "1.6.3", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "root", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "workspaces": [ "packages/page-controller", @@ -11799,11 +11799,11 @@ }, "packages/core": { "name": "@page-agent/core", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "dependencies": { - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3", + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0", "chalk": "^5.6.2" }, "devDependencies": { @@ -11815,13 +11815,13 @@ }, "packages/extension": { "name": "@page-agent/ext", - "version": "1.6.3", + "version": "1.7.0", "hasInstallScript": true, "dependencies": { - "@page-agent/core": "1.6.3", - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3", - "@page-agent/ui": "1.6.3", + "@page-agent/core": "1.7.0", + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0", + "@page-agent/ui": "1.7.0", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, @@ -11858,7 +11858,7 @@ }, "packages/llms": { "name": "@page-agent/llms", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "dependencies": { "chalk": "^5.6.2" @@ -11872,7 +11872,7 @@ }, "packages/mcp": { "name": "@page-agent/mcp", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", @@ -11887,13 +11887,13 @@ } }, "packages/page-agent": { - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "dependencies": { - "@page-agent/core": "1.6.3", - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3", - "@page-agent/ui": "1.6.3", + "@page-agent/core": "1.7.0", + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0", + "@page-agent/ui": "1.7.0", "chalk": "^5.6.2" }, "devDependencies": { @@ -11905,7 +11905,7 @@ }, "packages/page-controller": { "name": "@page-agent/page-controller", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT", "dependencies": { "ai-motion": "^0.4.8" @@ -11913,12 +11913,12 @@ }, "packages/ui": { "name": "@page-agent/ui", - "version": "1.6.3", + "version": "1.7.0", "license": "MIT" }, "packages/website": { "name": "@page-agent/website", - "version": "1.6.3", + "version": "1.7.0", "devDependencies": { "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-separator": "^1.1.8", diff --git a/package.json b/package.json index b8f3a24..1aa2b4b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "root", "private": true, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "workspaces": [ "packages/page-controller", diff --git a/packages/core/package.json b/packages/core/package.json index b30afec..455f2c5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/core", "private": false, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "main": "./dist/esm/page-agent-core.js", "module": "./dist/esm/page-agent-core.js", @@ -44,8 +44,8 @@ }, "dependencies": { "chalk": "^5.6.2", - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3" + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" diff --git a/packages/extension/package.json b/packages/extension/package.json index aee4f70..1d129e3 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/ext", "private": true, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "scripts": { "dev": "wxt", @@ -37,10 +37,10 @@ "wxt": "^0.20.20" }, "dependencies": { - "@page-agent/core": "1.6.3", - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3", - "@page-agent/ui": "1.6.3", + "@page-agent/core": "1.7.0", + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0", + "@page-agent/ui": "1.7.0", "ai-motion": "^0.4.8", "chalk": "^5.6.2" }, diff --git a/packages/llms/package.json b/packages/llms/package.json index 9aff1f5..befe627 100644 --- a/packages/llms/package.json +++ b/packages/llms/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/llms", - "version": "1.6.3", + "version": "1.7.0", "type": "module", "main": "./dist/lib/page-agent-llms.js", "module": "./dist/lib/page-agent-llms.js", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index cbaec05..c184c9a 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/mcp", "private": false, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "bin": { "page-agent-mcp": "src/index.js" diff --git a/packages/page-agent/package.json b/packages/page-agent/package.json index 1229b2c..fb40751 100644 --- a/packages/page-agent/package.json +++ b/packages/page-agent/package.json @@ -1,7 +1,7 @@ { "name": "page-agent", "private": false, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "main": "./dist/esm/page-agent.js", "module": "./dist/esm/page-agent.js", @@ -44,10 +44,10 @@ "postpublish": "node -e \"['README.md','LICENSE'].forEach(f=>{try{require('fs').unlinkSync(f)}catch{}})\"" }, "dependencies": { - "@page-agent/core": "1.6.3", - "@page-agent/llms": "1.6.3", - "@page-agent/page-controller": "1.6.3", - "@page-agent/ui": "1.6.3", + "@page-agent/core": "1.7.0", + "@page-agent/llms": "1.7.0", + "@page-agent/page-controller": "1.7.0", + "@page-agent/ui": "1.7.0", "chalk": "^5.6.2" }, "peerDependencies": { diff --git a/packages/page-controller/package.json b/packages/page-controller/package.json index 144447c..2b1c31f 100644 --- a/packages/page-controller/package.json +++ b/packages/page-controller/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/page-controller", - "version": "1.6.3", + "version": "1.7.0", "type": "module", "main": "./dist/lib/page-controller.js", "module": "./dist/lib/page-controller.js", diff --git a/packages/ui/package.json b/packages/ui/package.json index c256bab..3a3af26 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@page-agent/ui", - "version": "1.6.3", + "version": "1.7.0", "type": "module", "main": "./dist/lib/page-agent-ui.js", "module": "./dist/lib/page-agent-ui.js", diff --git a/packages/website/package.json b/packages/website/package.json index d784c19..37e99b1 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,7 +1,7 @@ { "name": "@page-agent/website", "private": true, - "version": "1.6.3", + "version": "1.7.0", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/packages/website/src/constants.ts b/packages/website/src/constants.ts index bc32665..d050458 100644 --- a/packages/website/src/constants.ts +++ b/packages/website/src/constants.ts @@ -1,8 +1,8 @@ // Demo build (auto-init with demo LLM, for quick testing) export const CDN_DEMO_URL = - 'https://cdn.jsdelivr.net/npm/page-agent@1.6.3/dist/iife/page-agent.demo.js' + 'https://cdn.jsdelivr.net/npm/page-agent@1.7.0/dist/iife/page-agent.demo.js' export const CDN_DEMO_CN_URL = - 'https://registry.npmmirror.com/page-agent/1.6.3/files/dist/iife/page-agent.demo.js' + 'https://registry.npmmirror.com/page-agent/1.7.0/files/dist/iife/page-agent.demo.js' // Demo LLM for website testing (homepage quick trial uses flash) export const DEMO_MODEL = 'qwen3.5-flash' From 0402a6be030c6c90b1a0e1e9607ed3bc2f90992c Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Tue, 31 Mar 2026 21:04:53 +0800 Subject: [PATCH 35/40] fix(tabs): error message typo --- packages/extension/src/agent/TabsController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension/src/agent/TabsController.ts b/packages/extension/src/agent/TabsController.ts index b30a409..9d77ad5 100644 --- a/packages/extension/src/agent/TabsController.ts +++ b/packages/extension/src/agent/TabsController.ts @@ -341,7 +341,7 @@ export class TabsController { this.port = null if (this.disposed) return if (this.portRetries >= 7) { - console.error(PREFIX, 'tab events port failed after 3 retries, giving up') + console.error(PREFIX, 'tab events port failed after 7 retries, giving up') return } debug('port disconnected, reconnecting...') From d0de8ad83838646b5c4c43681ddd423ca9b5279e Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:30:58 +0800 Subject: [PATCH 36/40] docs(website): add qwen3.6-plus to models page --- packages/website/src/pages/docs/features/models/page.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/website/src/pages/docs/features/models/page.tsx b/packages/website/src/pages/docs/features/models/page.tsx index f427b0d..53242ec 100644 --- a/packages/website/src/pages/docs/features/models/page.tsx +++ b/packages/website/src/pages/docs/features/models/page.tsx @@ -9,6 +9,7 @@ const BASELINE = new Set([ 'claude-haiku-4.5', 'gemini-3-flash', 'deepseek-3.2', + 'qwen3.6-plus', 'qwen3.5-plus', 'qwen3.5-flash', ]) @@ -16,6 +17,7 @@ const BASELINE = new Set([ // Models grouped by brand, newest first const MODEL_GROUPS: Record = { Qwen: [ + 'qwen3.6-plus', 'qwen3.5-plus', 'qwen3.5-flash', 'qwen3-coder-next', @@ -181,7 +183,7 @@ const pageAgent = new PageAgent({

Date: Thu, 2 Apr 2026 12:25:09 +0800 Subject: [PATCH 37/40] fix: extract currentScript outside setTimeout to avoid null pointer --- packages/page-agent/src/demo.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/page-agent/src/demo.ts b/packages/page-agent/src/demo.ts index af6d668..516dd6f 100644 --- a/packages/page-agent/src/demo.ts +++ b/packages/page-agent/src/demo.ts @@ -17,9 +17,10 @@ const DEMO_MODEL = 'qwen3.5-plus' const DEMO_BASE_URL = 'https://page-ag-testing-ohftxirgbn.cn-shanghai.fcapp.run' const DEMO_API_KEY = 'NA' +const currentScript = document.currentScript as HTMLScriptElement | null + // in case document.x is not ready yet setTimeout(() => { - const currentScript = document.currentScript as HTMLScriptElement | null let config: PageAgentConfig if (currentScript) { From ec08b05da109180f7012c085d57d361929390281 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:34:57 +0800 Subject: [PATCH 38/40] feat(ext): add `systemInstruction` to ExecuteConfig Expose a serializable `systemInstruction` string field on the page-facing ExecuteConfig, mapped to `instructions.system` when creating MultiPageAgent. Functions cannot cross the postMessage boundary, so this flat string field replaces the object form. Closes #359 --- packages/extension/docs/extension_api.md | 7 +++++++ packages/extension/src/entrypoints/content.ts | 6 +++++- packages/extension/src/entrypoints/main-world.ts | 7 +++++++ .../src/pages/docs/features/chrome-extension/page.tsx | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/extension/docs/extension_api.md b/packages/extension/docs/extension_api.md index d7dc902..1586660 100644 --- a/packages/extension/docs/extension_api.md +++ b/packages/extension/docs/extension_api.md @@ -118,6 +118,10 @@ export interface ExecuteConfig { model: string apiKey?: string + // Global system-level instructions for the agent. + // Equivalent to AgentConfig.instructions.system. + systemInstruction?: string + // Include the initial tab where page JS starts. Default: true. includeInitialTab?: boolean @@ -212,6 +216,9 @@ interface ExecuteConfig { baseURL: string model: string apiKey?: string + + systemInstruction?: string + includeInitialTab?: boolean experimentalIncludeAllTabs?: boolean onStatusChange?: (status: AgentStatus) => void diff --git a/packages/extension/src/entrypoints/content.ts b/packages/extension/src/entrypoints/content.ts index e06dd1f..1bcfc8a 100644 --- a/packages/extension/src/entrypoints/content.ts +++ b/packages/extension/src/entrypoints/content.ts @@ -70,11 +70,15 @@ async function exposeAgentToPage() { try { const { task, config } = payload + const { systemInstruction, ...agentConfig } = config // Dispose old instance before creating new one multiPageAgent?.dispose() - multiPageAgent = new MultiPageAgent(config) + multiPageAgent = new MultiPageAgent({ + ...agentConfig, + instructions: systemInstruction ? { system: systemInstruction } : undefined, + }) // events diff --git a/packages/extension/src/entrypoints/main-world.ts b/packages/extension/src/entrypoints/main-world.ts index c7946e8..b401beb 100644 --- a/packages/extension/src/entrypoints/main-world.ts +++ b/packages/extension/src/entrypoints/main-world.ts @@ -7,6 +7,12 @@ export interface ExecuteConfig { model: string apiKey?: string + /** + * Global system-level instructions for the agent. + * Equivalent to `AgentConfig.instructions.system`. + */ + systemInstruction?: string + /** * Whether to include the initial tab (that holds this main world script) in the task. * @default true @@ -89,6 +95,7 @@ export default defineUnlistedScript(() => { baseURL: config.baseURL, model: config.model, apiKey: config.apiKey, + systemInstruction: config.systemInstruction, includeInitialTab: config.includeInitialTab, experimentalIncludeAllTabs: config.experimentalIncludeAllTabs, }, diff --git a/packages/website/src/pages/docs/features/chrome-extension/page.tsx b/packages/website/src/pages/docs/features/chrome-extension/page.tsx index acee2a6..8ae0ea2 100644 --- a/packages/website/src/pages/docs/features/chrome-extension/page.tsx +++ b/packages/website/src/pages/docs/features/chrome-extension/page.tsx @@ -199,6 +199,7 @@ interface ExecuteConfig { model: string // Model name apiKey?: string // LLM AK + systemInstruction?: string // Global system-level instructions includeInitialTab?: boolean experimentalIncludeAllTabs?: boolean // Control all unpinned tabs in the window onStatusChange?: (status: AgentStatus) => void From 3efef0ec42c9210c22a18a0ee32656328c1759d3 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:33:27 +0800 Subject: [PATCH 39/40] fix(controller): clean up `INTERACTIVE_ARIA_ATTRS` --- .../page-controller/src/dom/dom_tree/index.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/page-controller/src/dom/dom_tree/index.js b/packages/page-controller/src/dom/dom_tree/index.js index 9166612..ccfdd1b 100644 --- a/packages/page-controller/src/dom/dom_tree/index.js +++ b/packages/page-controller/src/dom/dom_tree/index.js @@ -1144,36 +1144,22 @@ export default ( * @returns {boolean} Whether the element is an interactive candidate. */ const INTERACTIVE_ARIA_ATTRS = [ - 'aria-label', - 'aria-labelledby', - 'aria-describedby', 'aria-expanded', 'aria-checked', 'aria-selected', 'aria-pressed', - 'aria-hidden', 'aria-haspopup', 'aria-controls', 'aria-owns', - 'aria-current', - 'aria-disabled', - 'aria-live', - 'aria-modal', 'aria-activedescendant', 'aria-valuenow', 'aria-valuetext', 'aria-valuemax', 'aria-valuemin', 'aria-autocomplete', - 'aria-invalid', - 'aria-required', - 'aria-level', - 'aria-sort', - 'aria-orientation', - 'aria-multiline', ] - function hasAriaAttribute(el) { + function hasInteractiveAria(el) { for (let i = 0; i < INTERACTIVE_ARIA_ATTRS.length; i++) { if (el.hasAttribute(INTERACTIVE_ARIA_ATTRS[i])) return true } @@ -1204,7 +1190,7 @@ export default ( element.hasAttribute('onclick') || element.hasAttribute('role') || element.hasAttribute('tabindex') || - hasAriaAttribute(element) || + hasInteractiveAria(element) || element.hasAttribute('data-action') || element.getAttribute('contenteditable') === 'true' From bde630f55dee1c90828c81d9942e0ab5980d57e6 Mon Sep 17 00:00:00 2001 From: Simon <10131203+gaomeng1900@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:38:02 +0800 Subject: [PATCH 40/40] chore(controller): add @edit mark --- packages/page-controller/src/dom/dom_tree/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/page-controller/src/dom/dom_tree/index.js b/packages/page-controller/src/dom/dom_tree/index.js index ccfdd1b..5f57ff7 100644 --- a/packages/page-controller/src/dom/dom_tree/index.js +++ b/packages/page-controller/src/dom/dom_tree/index.js @@ -18,6 +18,7 @@ * @edit improve `sampleRect`, filter out rects with 0 area * @edit exclude aria-hidden elements * @edit make sure attributes exist for interactive candidates. + * @edit fix "aria-*" attributes check */ export default ( @@ -1143,6 +1144,8 @@ export default ( * @param {HTMLElement} element - The element to check. * @returns {boolean} Whether the element is an interactive candidate. */ + + // @edit fix "aria-*" attributes check const INTERACTIVE_ARIA_ATTRS = [ 'aria-expanded', 'aria-checked',