@opentiny/next-sdk 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/{SimulatorMask-BHVXyogh-CARX3Rff.js → SimulatorMask-BHVXyogh-CKmEDsYG.js} +1 -1
  2. package/dist/{index-R_HIbfUX.js → index-CHMa2zG4.js} +1065 -1042
  3. package/dist/index.js +1 -1
  4. package/dist/page-tools/a11y/config.d.ts +6 -3
  5. package/dist/page-tools/a11y/constants.d.ts +20 -0
  6. package/dist/page-tools/a11y/utils.d.ts +14 -0
  7. package/dist/page-tools/constants.d.ts +4 -2
  8. package/dist/page-tools/context.d.ts +2 -0
  9. package/dist/page-tools/handlers/hover.d.ts +9 -0
  10. package/dist/page-tools/schema.d.ts +3 -3
  11. package/dist/page-tools/utils/dom.d.ts +8 -2
  12. package/dist/runtime.js +19 -172
  13. package/package.json +6 -1
  14. package/WebMcpClient.ts +0 -505
  15. package/WebMcpServer.ts +0 -447
  16. package/agent/AgentModelProvider.ts +0 -932
  17. package/agent/type.ts +0 -91
  18. package/agent/utils/generateReActPrompt.ts +0 -71
  19. package/agent/utils/getAISDKTools.ts +0 -34
  20. package/agent/utils/getBuiltinMcpTools.ts +0 -86
  21. package/agent/utils/parseReActAction.ts +0 -34
  22. package/core.ts +0 -26
  23. package/index.ts +0 -91
  24. package/page-tools/a11y/build.ts +0 -74
  25. package/page-tools/a11y/config.ts +0 -465
  26. package/page-tools/a11y/constants.ts +0 -131
  27. package/page-tools/a11y/search.ts +0 -127
  28. package/page-tools/a11y/types.ts +0 -105
  29. package/page-tools/a11y/utils.ts +0 -239
  30. package/page-tools/a11y/vnode.ts +0 -439
  31. package/page-tools/a11y-tree.ts +0 -14
  32. package/page-tools/bridge.ts +0 -722
  33. package/page-tools/configs/console-cloud.ts +0 -172
  34. package/page-tools/constants.ts +0 -12
  35. package/page-tools/context.ts +0 -50
  36. package/page-tools/effects.ts +0 -345
  37. package/page-tools/handlers/browserState.ts +0 -12
  38. package/page-tools/handlers/click.ts +0 -30
  39. package/page-tools/handlers/executeJavascript.ts +0 -22
  40. package/page-tools/handlers/fill.ts +0 -65
  41. package/page-tools/handlers/scroll.ts +0 -66
  42. package/page-tools/handlers/searchTree.ts +0 -27
  43. package/page-tools/handlers/select.ts +0 -39
  44. package/page-tools/initialize-builtin-WebMCP.ts +0 -20
  45. package/page-tools/page-agent-highlight/index.ts +0 -245
  46. package/page-tools/page-agent-mask/SimulatorMask.module.css +0 -14
  47. package/page-tools/page-agent-mask/SimulatorMask.ts +0 -299
  48. package/page-tools/page-agent-mask/checkDarkMode.ts +0 -181
  49. package/page-tools/page-agent-mask/cursor-border.svg +0 -3
  50. package/page-tools/page-agent-mask/cursor-fill.svg +0 -5
  51. package/page-tools/page-agent-mask/cursor.module.css +0 -70
  52. package/page-tools/page-agent-mask/hauwei.svg +0 -25
  53. package/page-tools/page-agent-prompt.md +0 -139
  54. package/page-tools/page-agent-tool-event.ts +0 -113
  55. package/page-tools/page-agent-tool.ts +0 -207
  56. package/page-tools/page-state-cache.ts +0 -78
  57. package/page-tools/schema.ts +0 -52
  58. package/page-tools/tool-config.ts +0 -100
  59. package/page-tools/utils/dom.ts +0 -158
  60. package/page-tools/utils/scroll.ts +0 -58
  61. package/remoter/QrCode.ts +0 -54
  62. package/remoter/createRemoter.ts +0 -957
  63. package/remoter/svgs/chat.svg +0 -43
  64. package/remoter/svgs/icon-copy.svg +0 -25
  65. package/remoter/svgs/link.svg +0 -28
  66. package/remoter/svgs/logo.svg +0 -45
  67. package/remoter/svgs/qrcode.svg +0 -35
  68. package/remoter/svgs/scan.svg +0 -21
  69. package/remoter/tooltips.ts +0 -260
  70. package/runtime.html +0 -39
  71. package/runtime.ts +0 -44
  72. package/script/utils.ts +0 -26
  73. package/skills/index.ts +0 -287
  74. package/test/page-tools/a11y/build.test.ts +0 -638
  75. package/test/page-tools/a11y/config.test.ts +0 -370
  76. package/test/page-tools/configs/console-cloud.test.ts +0 -168
  77. package/test/page-tools/page-agent-highlight.test.ts +0 -110
  78. package/test/page-tools/page-agent-tool-dispatch.test.ts +0 -208
  79. package/test/page-tools/page-agent-tool.test.ts +0 -102
  80. package/test/page-tools/tool-config.test.ts +0 -112
  81. package/test/page-tools/utils/dom.test.ts +0 -122
  82. package/tsconfig.json +0 -16
  83. package/utils/builtinProxy.ts +0 -144
  84. package/utils/env.ts +0 -13
  85. package/utils/uuid.ts +0 -10
  86. package/vite.config.runtime.ts +0 -22
  87. package/vite.config.ts +0 -63
  88. package/vitest.config.ts +0 -10
@@ -1,100 +0,0 @@
1
- /**
2
- * tool-config.ts
3
- *
4
- * registerPageAgentTool 的完整运行期配置:顶层选项(enableHighlight 等)+ 统一无障碍配置(a11yConfig)。
5
- * 两者合并到同一个配置对象里,提供唯一一套运行期读写 API(getPageAgentToolConfig/setPageAgentToolConfig):
6
- * 注册时初始化一次,之后可随时读取/修改,无需分别记住两套 get/set 函数。
7
- */
8
-
9
- import type { A11yConfig, ResolvedA11yConfig } from './a11y/config'
10
- import { DEFAULT_A11Y_CONFIG, mergeA11yConfig, mergeA11yConfigs } from './a11y/config'
11
-
12
- export interface PageAgentToolConfig {
13
- /** 是否启用元素高亮 */
14
- enableHighlight: boolean
15
- /** 是否在工具调用后移除遮罩, 默认值为 true 移除 */
16
- removeMaskAfterToolCall?: boolean
17
- /**
18
- * 统一无障碍配置:按角色(roles)、状态(states:selected/disabled/error/warning 等)自定义规则,
19
- * 以及白名单/黑名单/自定义暴露属性/弹窗选择器。已与默认配置合并(数组类字段是拼接结果)。
20
- */
21
- a11yConfig: ResolvedA11yConfig
22
- }
23
-
24
- /**
25
- * 用于初始化(registerPageAgentTool 的入参)或运行期 setPageAgentToolConfig 的补丁对象:
26
- * enableHighlight 为覆盖式更新;a11yConfig 为拼接式合并(数组类字段追加,不丢已有规则,语义见 a11y/config.ts)。
27
- */
28
- export interface PageAgentToolConfigPatch {
29
- /** 是否启用元素高亮 */
30
- enableHighlight?: boolean
31
- /** 是否在工具调用后移除遮罩, 默认值为 true 移除 */
32
- removeMaskAfterToolCall?: boolean
33
- /** 是否在工具调用后移除遮罩 */
34
- /** 统一无障碍配置,会与当前生效的 a11yConfig 按数组拼接合并 */
35
- a11yConfig?: A11yConfig
36
- }
37
-
38
- /** registerPageAgentTool(options) 的入参类型,与运行期补丁 {@link PageAgentToolConfigPatch} 完全一致 */
39
- export type PageAgentToolOptions = PageAgentToolConfigPatch
40
-
41
- /** 默认生效的完整工具配置 */
42
- export const DEFAULT_PAGE_AGENT_TOOL_CONFIG: PageAgentToolConfig = {
43
- enableHighlight: false,
44
- removeMaskAfterToolCall: true,
45
- a11yConfig: DEFAULT_A11Y_CONFIG
46
- }
47
-
48
- declare global {
49
- interface Window {
50
- /** 运行期唯一生效的 page-agent-tool 完整配置(已与默认值合并),可通过 getPageAgentToolConfig/setPageAgentToolConfig 读写 */
51
- __webmcpcli_toolConfig?: PageAgentToolConfig
52
- }
53
- }
54
-
55
- /** 读取当前生效的完整工具配置(已与默认值合并)。未初始化时返回默认配置 */
56
- export function getPageAgentToolConfig(): PageAgentToolConfig {
57
- if (typeof window !== 'undefined' && window.__webmcpcli_toolConfig) {
58
- return window.__webmcpcli_toolConfig
59
- }
60
- return {
61
- enableHighlight: DEFAULT_PAGE_AGENT_TOOL_CONFIG.enableHighlight,
62
- removeMaskAfterToolCall: DEFAULT_PAGE_AGENT_TOOL_CONFIG.removeMaskAfterToolCall,
63
- a11yConfig: mergeA11yConfig()
64
- }
65
- }
66
-
67
- function resolvePatch(patch: PageAgentToolConfigPatch, base: PageAgentToolConfig): PageAgentToolConfig {
68
- return {
69
- enableHighlight: patch.enableHighlight ?? base.enableHighlight,
70
- removeMaskAfterToolCall: patch.removeMaskAfterToolCall ?? base.removeMaskAfterToolCall,
71
- a11yConfig: mergeA11yConfigs(base.a11yConfig, patch.a11yConfig ?? {})
72
- }
73
- }
74
-
75
- /**
76
- * 更新当前生效配置。
77
- * - patch 为对象时:enableHighlight 覆盖式更新;a11yConfig 与当前配置按数组拼接合并(不丢已有规则)
78
- * - patch 为函数时:入参为当前生效配置,返回值直接与默认配置合并(而不是再与 current 相加)。
79
- * 这样函数体内可以对 current.a11yConfig 做任意过滤/裁剪(如按条件"移除"某条旧规则),
80
- * 返回值即为最终生效的配置,不会因为再与 current 相加而让被过滤掉的旧规则"复活"
81
- * - options.mode = 'replace' 时(仅影响对象类型的 patch):不与"当前生效配置"合并,而是与默认配置重新合并
82
- * 返回合并后的最新完整配置,并写回运行期存储供 buildBrowserStateResponse/buildA11yTree 等读取。
83
- */
84
- export function setPageAgentToolConfig(
85
- patch: PageAgentToolConfigPatch | ((current: PageAgentToolConfig) => PageAgentToolConfigPatch),
86
- options?: { mode?: 'merge' | 'replace' }
87
- ): PageAgentToolConfig {
88
- const mode = options?.mode ?? 'merge'
89
- const current = getPageAgentToolConfig()
90
-
91
- const next =
92
- typeof patch === 'function'
93
- ? resolvePatch(patch(current), DEFAULT_PAGE_AGENT_TOOL_CONFIG)
94
- : resolvePatch(patch, mode === 'replace' ? DEFAULT_PAGE_AGENT_TOOL_CONFIG : current)
95
-
96
- if (typeof window !== 'undefined') {
97
- window.__webmcpcli_toolConfig = next
98
- }
99
- return next
100
- }
@@ -1,158 +0,0 @@
1
- import { extractSelectors } from '../a11y/config'
2
- import { getPageAgentToolConfig } from '../tool-config'
3
-
4
- // ─── 辅助:Shadow DOM 事件穿透 ───────────────────────────────────────────
5
- // 外部包 inputTextElement/selectOptionElement 派发的合成事件 composed:false,
6
- // 无法穿透 shadow boundary,导致事件委托框架(如 React)收不到 shadow 内元素的
7
- // input/change 事件。这里对 shadow DOM 内元素补发 composed:true 事件。
8
- export function isInShadowDom(el: Element): boolean {
9
- return el.getRootNode() instanceof ShadowRoot
10
- }
11
-
12
- export function dispatchComposedEvents(el: Element, ...types: string[]) {
13
- for (const type of types) {
14
- el.dispatchEvent(new Event(type, { bubbles: true, composed: true }))
15
- }
16
- }
17
-
18
- // ─── 辅助:穿透 Shadow DOM 的查询 ─────────────────────────────────────────
19
- export function deepQuerySelectorAll(selector: string, root: Document | Element | ShadowRoot = document): Element[] {
20
- const elements = Array.from(root.querySelectorAll(selector))
21
-
22
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null)
23
- let currentNode: Node | null = walker.currentNode
24
- while (currentNode) {
25
- if ((currentNode as Element).shadowRoot) {
26
- elements.push(...deepQuerySelectorAll(selector, (currentNode as Element).shadowRoot!))
27
- }
28
- currentNode = walker.nextNode()
29
- }
30
- return elements
31
- }
32
-
33
- // ─── 辅助:等待 DOM 变更稳定 ────────────────────────────────────────────
34
- // click/fill/select 操作后,框架(Angular/React/Vue)可能异步插入校验错误、
35
- // 条件渲染选项等动态内容。用 MutationObserver 监听 DOM 变更,等待变更平息后
36
- // 再构建 A11y 树,确保动态插入的内容(如 ng-star-inserted 校验提示)被捕获。
37
- export function waitForDomSettled(timeout = 600, settleTime = 150): Promise<void> {
38
- return new Promise<void>((resolve) => {
39
- let settled = false
40
- let settleTimer: ReturnType<typeof setTimeout> | undefined
41
- const finish = () => {
42
- if (settled) return
43
- settled = true
44
- observer.disconnect()
45
- if (settleTimer) clearTimeout(settleTimer)
46
- resolve()
47
- }
48
- // 每次有 DOM 变更时重置 settle 计时器;变更平息 settleTime 后视为稳定
49
- const observer = new MutationObserver(() => {
50
- if (settleTimer) clearTimeout(settleTimer)
51
- settleTimer = setTimeout(finish, settleTime)
52
- })
53
- // 若无任何变更,settleTime 后直接结束
54
- settleTimer = setTimeout(finish, settleTime)
55
- // 超时保护:timeout 后强制结束,避免无限等待
56
- setTimeout(finish, timeout)
57
- observer.observe(document.body, {
58
- childList: true,
59
- subtree: true,
60
- attributes: true,
61
- attributeFilter: ['class', 'style', 'hidden'],
62
- })
63
- })
64
- }
65
-
66
- // ─── 辅助:检测页面级模态弹窗/遮罩层 ────────────────────────────────────
67
- // 仅检测真正阻塞交互的模态弹窗(确认框、提交对话框等),
68
- // 不检测顶部通知横幅、站内消息等非模态提示,避免误报导致 AI 循环
69
- export function detectPageDialog(): string {
70
- const seen = new Set<Element>()
71
- const dialogs: string[] = []
72
- // 仅匹配明确的模态弹窗选择器,避免宽泛子串匹配误报
73
- // 统一取 getPageAgentToolConfig().a11yConfig.dialogSelectors(已含默认值 + 用户配置)
74
- const selectors = getPageAgentToolConfig().a11yConfig.dialogSelectors
75
-
76
- for (const selector of selectors) {
77
- try {
78
- for (const el of deepQuerySelectorAll(selector)) {
79
- if (seen.has(el)) continue
80
- // 跳过 SDK 自身遮罩
81
- if (el.id?.includes('page-agent-runtime')) continue
82
- if (el.closest('#page-agent-runtime_simulator-mask')) continue
83
-
84
- const rect = el.getBoundingClientRect()
85
- if (rect.width < 50 || rect.height < 50) continue
86
- const style = window.getComputedStyle(el as HTMLElement)
87
- if (style.display === 'none' || style.visibility === 'hidden') continue
88
-
89
- // 模态性验证:必须是 fixed/absolute 且 z-index 较高
90
- const isFixed = style.position === 'fixed' || style.position === 'absolute'
91
- const zIndex = parseInt(style.zIndex || '0', 10)
92
- if (!isFixed || zIndex < 100) continue
93
-
94
- // 必须覆盖视口中心区域(真正的模态弹窗会遮挡页面中心)
95
- const vw = window.innerWidth
96
- const vh = window.innerHeight
97
- const coversCenter = rect.left < vw * 0.6 && rect.right > vw * 0.4 &&
98
- rect.top < vh * 0.6 && rect.bottom > vh * 0.4
99
- if (!coversCenter) continue
100
-
101
- seen.add(el)
102
- const text = (el.textContent || '').trim().replace(/\s+/g, ' ')
103
- if (text.length > 5) {
104
- // 提取弹窗内的可交互按钮,帮助 AI 快速决策
105
- const btns = el.querySelectorAll('button, [role="button"], a')
106
- const btnTexts = Array.from(btns)
107
- .map(b => (b.textContent || '').trim())
108
- .filter(t => t.length > 0 && t.length < 20)
109
- .slice(0, 5)
110
- const btnInfo = btnTexts.length ? ` [可操作按钮: ${btnTexts.join(' / ')}]` : ''
111
- dialogs.push(`${text.substring(0, 300)}${btnInfo}`)
112
- }
113
- }
114
- } catch {
115
- // 忽略选择器异常
116
- }
117
- }
118
-
119
- if (dialogs.length === 0) return ''
120
- return `\n[页面弹窗检测] 检测到 ${dialogs.length} 个模态弹窗,请优先处理:\n${dialogs.map((d, i) => `${i + 1}. ${d}`).join('\n')}\n`
121
- }
122
-
123
- // ─── 辅助:检测页面可见的表单校验错误 ──────────────────────────────────
124
- // 操作后自动扫描页面中的校验错误提示,提取文本并提醒 AI,
125
- // 避免 AI 卡住时不知道是因为有校验错误未处理
126
- export function detectValidationErrors(): string {
127
- const seen = new Set<Element>()
128
- const errors: string[] = []
129
- // 校验错误选择器:ARIA 标准 + 主流 UI 框架(可配置)
130
- // 统一取 getPageAgentToolConfig().a11yConfig.states.error(已含默认值 + 用户配置)
131
- const selectors = extractSelectors(getPageAgentToolConfig().a11yConfig.states.error)
132
-
133
- for (const selector of selectors) {
134
- try {
135
- for (const el of deepQuerySelectorAll(selector)) {
136
- if (seen.has(el)) continue
137
- // 跳过嵌套在已收集的错误元素内的子元素,避免重复
138
- if (Array.from(seen).some(s => s.contains(el))) continue
139
-
140
- const rect = el.getBoundingClientRect()
141
- if (rect.width < 1 || rect.height < 1) continue
142
- const style = window.getComputedStyle(el as HTMLElement)
143
- if (style.display === 'none' || style.visibility === 'hidden') continue
144
-
145
- const text = (el.textContent || '').trim().replace(/\s+/g, ' ')
146
- if (text.length > 2 && text.length < 200) {
147
- seen.add(el)
148
- errors.push(text)
149
- }
150
- }
151
- } catch {
152
- // 忽略选择器异常
153
- }
154
- }
155
-
156
- if (errors.length === 0) return ''
157
- return `\n[校验提示] 检测到 ${errors.length} 个表单校验错误,请先修复后再继续:\n${errors.map((e, i) => `${i + 1}. ${e}`).join('\n')}\n`
158
- }
@@ -1,58 +0,0 @@
1
- // ─── 辅助:获取滚动目标的当前位置信息(仿 page-agent getPageInfo)────────
2
- // 同时支持 window(文档滚动)和任意 Element(容器滚动)
3
- export function getScrollInfo(target: Window | Element = window) {
4
- if (target === window) {
5
- const pageHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
6
- const pageWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth)
7
- const scrollY = window.scrollY
8
- const scrollX = window.scrollX
9
- const pixelsBelow = Math.max(0, pageHeight - (window.innerHeight + scrollY))
10
- const pixelsRight = Math.max(0, pageWidth - (window.innerWidth + scrollX))
11
- return {
12
- scrollY, scrollX,
13
- pixelsAbove: scrollY, pixelsBelow,
14
- pixelsLeft: scrollX, pixelsRight,
15
- pagesAbove: window.innerHeight > 0 ? scrollY / window.innerHeight : 0,
16
- pagesBelow: window.innerHeight > 0 ? pixelsBelow / window.innerHeight : 0,
17
- atTop: scrollY <= 1,
18
- atBottom: pixelsBelow <= 1,
19
- atLeft: scrollX <= 1,
20
- atRight: pixelsRight <= 1,
21
- }
22
- } else {
23
- const el = target as Element
24
- const scrollTop = el.scrollTop
25
- const scrollLeft = el.scrollLeft
26
- const pixelsBelow = el.scrollHeight - el.clientHeight - scrollTop
27
- const pixelsRight = el.scrollWidth - el.clientWidth - scrollLeft
28
- return {
29
- scrollY: scrollTop, scrollX: scrollLeft,
30
- pixelsAbove: scrollTop, pixelsBelow: Math.max(0, pixelsBelow),
31
- pixelsLeft: scrollLeft, pixelsRight: Math.max(0, pixelsRight),
32
- pagesAbove: el.clientHeight > 0 ? scrollTop / el.clientHeight : 0,
33
- pagesBelow: el.clientHeight > 0 ? Math.max(0, pixelsBelow) / el.clientHeight : 0,
34
- atTop: scrollTop <= 1,
35
- atBottom: pixelsBelow <= 1,
36
- atLeft: scrollLeft <= 1,
37
- atRight: pixelsRight <= 1,
38
- }
39
- }
40
- }
41
-
42
- // 等待 smooth scroll 结束:优先监听 scrollend,超时兜底(边界无位移时 scrollend 可能不触发)
43
- export function waitForScrollEnd(target: Window | Element, timeout = 2000): Promise<void> {
44
- return new Promise((resolve) => {
45
- let settled = false
46
- const el = target === window ? document : (target as Element)
47
- const finish = () => {
48
- if (settled) return
49
- settled = true
50
- el.removeEventListener('scrollend', onScrollEnd)
51
- clearTimeout(timer)
52
- resolve()
53
- }
54
- const onScrollEnd = () => finish()
55
- const timer = setTimeout(finish, timeout)
56
- el.addEventListener('scrollend', onScrollEnd, { once: true })
57
- })
58
- }
package/remoter/QrCode.ts DELETED
@@ -1,54 +0,0 @@
1
- import QRCodePck from 'qrcode'
2
-
3
- /** QrCode 类的配置信息 */
4
- export type QrCodeOption = ConstructorParameters<typeof QrCode>[1]
5
-
6
- /**
7
- * 二维码工具类,根据传入的value,生成相应的二维码,并输出到 <canvas> 或 <img>上。
8
- * @example
9
- * const qr= new QrCode('https://www.baidu.com', { size: 100 })
10
- *
11
- * qr.toCanvas(canvasDom)
12
- * qr.toImage(imgDom)
13
- */
14
- export class QrCode {
15
- private value: string
16
- private size: number
17
- private margin: number
18
- private color: string
19
- private bgColor: string
20
-
21
- constructor(value: string, { size = 200, margin = 4, color = '#000', bgColor = '#fff' }) {
22
- this.value = value
23
- this.size = size
24
- this.margin = margin
25
- this.color = color
26
- this.bgColor = bgColor
27
- }
28
-
29
- get qrCodeOption() {
30
- return {
31
- width: this.size,
32
- margin: this.margin,
33
- color: {
34
- dark: this.color, // 前景色
35
- light: this.bgColor // 背景色
36
- }
37
- }
38
- }
39
-
40
- /** 生成二维码的 Data URL(base64 图片) */
41
- async toDataURL(): Promise<string> {
42
- return QRCodePck.toDataURL(this.value, this.qrCodeOption)
43
- }
44
-
45
- /** 渲染二维码到指定的 canvas 元素 */
46
- async toCanvas(canvas: HTMLCanvasElement): Promise<void> {
47
- return QRCodePck.toCanvas(canvas, this.value, this.qrCodeOption)
48
- }
49
-
50
- /** 渲染二维码到指定的 img 元素 */
51
- async toImage(img: HTMLImageElement): Promise<void> {
52
- img.src = await this.toDataURL()
53
- }
54
- }