@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,172 +0,0 @@
1
- /**
2
- * 云控制台(consoleCloud)专用 PageAgentToolOptions。
3
- *
4
- * 控制台基于 Tiny3(ti3-*)+ Angular,大量自定义组件缺少 role / aria-*:
5
- * - Tab:`.ti3-tab-li` 无 role=tab,选中靠 `.ti3-tab-active`
6
- * - 下拉:`.ti3-select-dominator-container` / `.selected-label` 无 combobox 语义
7
- * - 图标按钮:仅有 `cf-uba` / 子节点 `title`,无 aria-label
8
- * - 服务列表侧栏、区域选择等用 class 表达选中态
9
- *
10
- * 书写约定:优先 selector;仅当需要计算样式等复杂判断时再用 match。
11
- * (roles 的 selector 为自身 matches;states 的 selector 为 closest)
12
- */
13
-
14
- import { defineA11yConfig } from '../a11y/config'
15
- import type { PageAgentToolOptions } from '../tool-config'
16
-
17
- /** 云控制台 page-agent-tool 预设配置 */
18
- export const consoleCloudPageAgentToolOptions: PageAgentToolOptions = {
19
- enableHighlight: false,
20
- a11yConfig: defineA11yConfig({
21
- roles: [
22
- // Tiny3 Tabs:真正可聚焦/可点击的是内部 .ti3-tabs-text(tabindex=0)
23
- { role: 'tablist', selector: 'ul.ti3-tabs' },
24
- { role: 'tab', selector: '.ti3-tabs-text' },
25
- { role: 'tabpanel', selector: ['ti-tab.ti3-tab-pane', '.ti3-tab-pane'] },
26
-
27
- // 自定义下拉 / 区域选择触发器
28
- {
29
- role: 'combobox',
30
- selector: [
31
- '.ti3-select-dominator-container',
32
- '.selected-label',
33
- '.sort-select',
34
- '.service-select',
35
- '.region-select',
36
- '[cf-uba="searchableRegion..open"]'
37
- ]
38
- },
39
-
40
- // 图标型 / 无语义按钮
41
- {
42
- role: 'button',
43
- selector: [
44
- '.modules-service-list-menu-service-icon-container',
45
- '.ti3-btn-only-icon-noborder',
46
- '.ti3-select-dominator-dropdown-btn',
47
- '.modules-right-sidebar-icon-item-wrapper',
48
- '.modules-right-sidebar-hide-state-plugin',
49
- '.components-service-list-container-service-list-input-service-close',
50
- '.modules-searchable-region-region-panel-close',
51
- '.modules-searchable-region-region-panel-search-btn',
52
- '[cf-uba="rightSidebar..hideBtn"]',
53
- // Tiny3 图标组件:帮助中心固定/全屏/关闭等(ti-icon / tp-icon 无原生 button 语义)
54
- '.ti-global-help-panel-header-icon',
55
- 'ti-icon[name]',
56
- 'tp-icon[name]',
57
- // 无 name 的箭头/操作图标(如 latest news 区 common-icon 展开箭头)
58
- 'tp-icon.common-icon',
59
- 'ti-icon.common-icon',
60
- 'ti-icon.ti3-icon-full-screen',
61
- 'ti-icon.ti3-icon-close',
62
- 'tp-icon.ti3-icon-full-screen',
63
- 'tp-icon.ti3-icon-close'
64
- ]
65
- },
66
-
67
- // 服务列表侧栏分类 / 顶栏菜单项
68
- {
69
- role: 'menuitem',
70
- selector: [
71
- '.components-service-list-left-box-sidebar-visit-panel > li',
72
- '.modules-menus-menu-item',
73
- '.components-menu-wrapper-menu-text'
74
- ]
75
- },
76
-
77
- // 区域筛选项 / 下拉选项
78
- {
79
- role: 'option',
80
- selector: [
81
- '.region-selector-item',
82
- '.modules-searchable-region-project-item-region-item',
83
- '.modules-searchable-region-region-panel-recent-region-item',
84
- '.ti3-multiselect-box-cell'
85
- ]
86
- }
87
- ],
88
- states: {
89
- // 选中态:挂在容器 class 上,用 selector + closest 即可命中内部交互节点
90
- selected: [
91
- { selector: 'li.ti3-tab-li.ti3-tab-active' },
92
- // Tiny3 按钮组(计费模式等):ti3-active 在 .ti3-btn-item-container 上,不在 button 上
93
- { selector: '.ti3-btn-item-container.ti3-active' },
94
- { selector: '.components-service-list-left-box-active' },
95
- {
96
- selector: [
97
- '.modules-searchable-region-project-item-region-item-selected',
98
- '.components-search-content-search-select-search-select-selected'
99
- ]
100
- }
101
- ],
102
- hasPopup: [
103
- {
104
- selector: [
105
- '.ti3-select-dominator-container',
106
- '.selected-label',
107
- '.sort-select',
108
- '.service-select',
109
- '.region-select',
110
- '[cf-uba="searchableRegion..open"]',
111
- '[cf-uba="serviceList..open"]',
112
- '[cf-uba="userinfo"]'
113
- ]
114
- }
115
- ],
116
- disabled: [{ selector: '.ti3-disabled' }],
117
- // 展开态:需结合计算样式,选择器表达不了「可见」
118
- expanded: [
119
- {
120
- match: (el) => {
121
- try {
122
- if (
123
- !el.matches(
124
- '.modules-layout-module-sidebar-panel, .modules-searchable-region-region-panel, .ti3-dropdown-container'
125
- )
126
- ) {
127
- return false
128
- }
129
- const style = window.getComputedStyle(el as HTMLElement)
130
- return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'
131
- } catch {
132
- return false
133
- }
134
- }
135
- }
136
- ]
137
- },
138
- // exposedAttributes 输出属性 token;带 name 的 ti-icon/tp-icon 可交互性由 roles/whitelist 中 ti-icon[name] 等规则判定。
139
- exposedAttributes: ['cf-uba', 'data-qa-id', 'name'],
140
- whitelist: [
141
- '.modules-service-list-menu-service-icon-container',
142
- '.ti3-tabs-text',
143
- '[cf-uba="cloudShell"]',
144
- '[cf-uba="messageBox"]',
145
- '[cf-uba="helpFeedback"]',
146
- '[cf-uba="globalMessage"]',
147
- '[cf-uba="rightSidebar..hideBtn"]',
148
- // 帮助中心等区域的 ti-icon / tp-icon 图标按钮
149
- '.ti-global-help-panel-header-icon',
150
- 'ti-icon[name]',
151
- 'tp-icon[name]',
152
- 'tp-icon.common-icon',
153
- 'ti-icon.common-icon',
154
- 'ti-icon.ti3-icon-full-screen'
155
- ],
156
- blacklist: ['noscript', 'pan-gu', '#J_header'],
157
- dialogSelectors: [
158
- '[class*="ti3-modal"]',
159
- '[class*="ti3-message-box"]',
160
- '[class*="drawer"]',
161
- '.modules-layout-module-sidebar-panel'
162
- ]
163
- })
164
- }
165
-
166
- /** 判断当前页面是否应使用云控制台(consoleCloud)预设 */
167
- export function isConsoleCloudHost(
168
- hostname: string = typeof location !== 'undefined' ? location.hostname : ''
169
- ): boolean {
170
- // 要求 console 前为域名边界(开头或 `.`),避免误匹配 xconsole.huaweicloud.com
171
- return /(^|\.)console\.huaweicloud\.com$/i.test(hostname)
172
- }
@@ -1,12 +0,0 @@
1
- /** 校验错误默认选择器:ARIA 标准 + 主流 UI 框架(唯一来源为 a11y/constants.ts,此处重新导出保持旧路径可用) */
2
- export { DEFAULT_ERROR_SELECTORS, DEFAULT_DIALOG_SELECTORS } from './a11y/constants'
3
-
4
- /** registerPageAgentTool(options) 的入参类型,定义见 tool-config.ts(与运行期 setPageAgentToolConfig 的补丁类型一致) */
5
- export type { PageAgentToolOptions } from './tool-config'
6
-
7
- declare global {
8
- interface Window {
9
- /** 指定网站可覆盖该函数,在每次 getBrowserState 之前调用,常用于配合 setPageAgentToolConfig 动态调整当前页面的配置 */
10
- __webmcpcli_beforeGetBrowserState?: (() => void) | null
11
- }
12
- }
@@ -1,50 +0,0 @@
1
- import type { PageController } from '@page-agent/page-controller'
2
- import type { PageStateCache } from './page-state-cache'
3
- import type { RefMap } from './a11y-tree'
4
-
5
- export type PageAgentToolContentResult = {
6
- content: Array<{ type: 'text'; text: string }>
7
- }
8
-
9
- export type PageAgentToolErrorResult = PageAgentToolContentResult & {
10
- isError: true
11
- error: string
12
- }
13
-
14
- export async function createActionErrorResult(
15
- message: string,
16
- buildBrowserStateResponse: ActionContext['buildBrowserStateResponse']
17
- ): Promise<PageAgentToolErrorResult> {
18
- try {
19
- const browserState = await buildBrowserStateResponse('full')
20
- return {
21
- isError: true,
22
- error: message,
23
- content: [{ type: 'text', text: `${message}\n\n${browserState.content[0].text}` }]
24
- }
25
- } catch (error) {
26
- return {
27
- isError: true,
28
- error: message,
29
- content: [
30
- {
31
- type: 'text',
32
- text: `${message}\n\n获取最新浏览器状态失败: ${error instanceof Error ? error.message : String(error)}`
33
- }
34
- ]
35
- }
36
- }
37
- }
38
-
39
- export interface ActionContext {
40
- pageController: PageController
41
- stateCache: PageStateCache
42
- getRefMap: () => RefMap
43
- setRefMap: (map: RefMap) => void
44
- buildBrowserStateResponse: (
45
- mode?: 'full' | 'diff' | 'both'
46
- ) => Promise<{ content: Array<{ type: 'text'; text: string }> }>
47
- refreshOnStaleRef: (action: string, index: number) => Promise<{ content: Array<{ type: 'text'; text: string }> }>
48
- errContent: (msg: string) => Promise<{ content: Array<{ type: 'text'; text: string }> }>
49
- actionError: (msg: string) => Promise<PageAgentToolErrorResult>
50
- }
@@ -1,345 +0,0 @@
1
- /**
2
- * page-tools/effects - 页面工具调用提示效果模块(框架无关)
3
- *
4
- * 作用:
5
- * - 在调用通过 withPageTools 注册的页面工具时,显示页面级的调用状态提示
6
- * - 以左下角小 tip 形式展示“当前正在调用的工具”文案,尽量不打扰用户操作
7
- * - 纯 DOM + CSS 实现,不依赖 Vue/React 等框架
8
- */
9
-
10
- export type ToolInvokeEffectConfig = {
11
- /**
12
- * 自定义提示文案,默认使用“工具标题 || 工具名称”
13
- * 例如:"正在为你整理订单数据"
14
- */
15
- label?: string
16
- }
17
-
18
- type RuntimeEffectConfig = {
19
- label: string
20
- }
21
-
22
- let overlayElement: HTMLDivElement | null = null
23
- let labelElement: HTMLDivElement | null = null
24
- let styleElement: HTMLStyleElement | null = null
25
- let activeCount = 0
26
-
27
- import { isDomAvailable } from '../utils/env'
28
-
29
- const BODY_GLOW_CLASS = 'next-sdk-tool-body-glow'
30
-
31
- function ensureDomReady() {
32
- return isDomAvailable()
33
- }
34
-
35
- function ensureStyleElement() {
36
- if (!ensureDomReady()) return
37
- if (styleElement) return
38
-
39
- const style = document.createElement('style')
40
- style.textContent = `
41
- .${BODY_GLOW_CLASS} {
42
- position: relative;
43
- }
44
-
45
- .next-sdk-tool-overlay {
46
- position: fixed;
47
- inset: 0;
48
- z-index: 999999;
49
- pointer-events: none;
50
- display: flex;
51
- align-items: flex-end;
52
- justify-content: flex-start;
53
- padding: 0 0 18px 18px;
54
- background: transparent;
55
- animation: next-sdk-overlay-fade-in 260ms ease-out;
56
- }
57
-
58
- .next-sdk-tool-overlay--exit {
59
- animation: next-sdk-overlay-fade-out 220ms ease-in forwards;
60
- }
61
-
62
- .next-sdk-tool-overlay__glow-ring {
63
- display: none;
64
- }
65
-
66
- .next-sdk-tool-overlay__panel {
67
- position: relative;
68
- min-width: min(320px, 78vw);
69
- max-width: min(420px, 82vw);
70
- padding: 10px 14px;
71
- border-radius: 999px;
72
- background:
73
- linear-gradient(135deg, rgba(15, 23, 42, 0.9), rgba(17, 24, 39, 0.9)),
74
- radial-gradient(circle at top left, rgba(96, 165, 250, 0.25), transparent 55%),
75
- radial-gradient(circle at bottom right, rgba(45, 212, 191, 0.22), transparent 60%);
76
- box-shadow:
77
- 0 12px 28px rgba(15, 23, 42, 0.78),
78
- 0 0 0 1px rgba(148, 163, 184, 0.26);
79
- display: flex;
80
- align-items: center;
81
- gap: 10px;
82
- pointer-events: none;
83
- transform-origin: center;
84
- animation: next-sdk-panel-pop-in 260ms cubic-bezier(0.18, 0.89, 0.32, 1.28);
85
- color: #e5e7eb;
86
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
87
- }
88
-
89
- .next-sdk-tool-overlay__indicator {
90
- width: 26px;
91
- height: 26px;
92
- border-radius: 999px;
93
- background: radial-gradient(circle at 30% 10%, #f9fafb, #93c5fd);
94
- box-shadow:
95
- 0 0 0 1px rgba(191, 219, 254, 0.6),
96
- 0 8px 18px rgba(37, 99, 235, 0.8),
97
- 0 0 28px rgba(56, 189, 248, 0.9);
98
- position: relative;
99
- flex-shrink: 0;
100
- display: flex;
101
- align-items: center;
102
- justify-content: center;
103
- overflow: hidden;
104
- }
105
-
106
- .next-sdk-tool-overlay__indicator-orbit {
107
- position: absolute;
108
- inset: 2px;
109
- border-radius: inherit;
110
- border: 1px solid rgba(248, 250, 252, 0.6);
111
- box-sizing: border-box;
112
- opacity: 0.9;
113
- }
114
-
115
- .next-sdk-tool-overlay__indicator-orbit::before {
116
- content: '';
117
- position: absolute;
118
- width: 6px;
119
- height: 6px;
120
- border-radius: 999px;
121
- background: #f9fafb;
122
- box-shadow:
123
- 0 0 12px rgba(248, 250, 252, 0.9),
124
- 0 0 24px rgba(250, 249, 246, 0.9);
125
- top: 0;
126
- left: 50%;
127
- transform: translate(-50%, -50%);
128
- transform-origin: 50% 18px;
129
- animation: next-sdk-indicator-orbit 1.4s linear infinite;
130
- }
131
-
132
- .next-sdk-tool-overlay__indicator-core {
133
- width: 14px;
134
- height: 14px;
135
- border-radius: inherit;
136
- background: radial-gradient(circle at 30% 20%, #f9fafb, #bfdbfe);
137
- box-shadow:
138
- 0 0 12px rgba(248, 250, 252, 0.9),
139
- 0 0 32px rgba(191, 219, 254, 0.8);
140
- opacity: 0.96;
141
- }
142
-
143
- .next-sdk-tool-overlay__content {
144
- display: flex;
145
- flex-direction: column;
146
- gap: 1px;
147
- min-width: 0;
148
- }
149
-
150
- .next-sdk-tool-overlay__title {
151
- font-size: 11px;
152
- letter-spacing: 0.08em;
153
- text-transform: uppercase;
154
- color: rgba(156, 163, 175, 0.96);
155
- display: flex;
156
- align-items: center;
157
- gap: 6px;
158
- }
159
-
160
- .next-sdk-tool-overlay__title-dot {
161
- width: 6px;
162
- height: 6px;
163
- border-radius: 999px;
164
- background: #22c55e;
165
- box-shadow:
166
- 0 0 8px rgba(34, 197, 94, 0.9),
167
- 0 0 14px rgba(22, 163, 74, 0.9);
168
- }
169
-
170
- .next-sdk-tool-overlay__label {
171
- font-size: 12px;
172
- font-weight: 500;
173
- color: #e5e7eb;
174
- white-space: nowrap;
175
- text-overflow: ellipsis;
176
- overflow: hidden;
177
- }
178
-
179
- @keyframes next-sdk-overlay-fade-in {
180
- from { opacity: 0; }
181
- to { opacity: 1; }
182
- }
183
-
184
- @keyframes next-sdk-overlay-fade-out {
185
- from { opacity: 1; }
186
- to { opacity: 0; }
187
- }
188
-
189
- @keyframes next-sdk-indicator-orbit {
190
- from {
191
- transform: translate(-50%, -50%) rotate(0deg) translateY(0);
192
- }
193
- to {
194
- transform: translate(-50%, -50%) rotate(360deg) translateY(0);
195
- }
196
- }
197
-
198
- @keyframes next-sdk-panel-pop-in {
199
- 0% {
200
- opacity: 0;
201
- transform: scale(0.92) translateY(10px);
202
- }
203
- 100% {
204
- opacity: 1;
205
- transform: scale(1) translateY(0);
206
- }
207
- }
208
- `
209
-
210
- document.head.appendChild(style)
211
- styleElement = style
212
- }
213
-
214
- function ensureOverlayElement() {
215
- if (!ensureDomReady()) return
216
- if (overlayElement) return
217
-
218
- ensureStyleElement()
219
-
220
- const overlay = document.createElement('div')
221
- overlay.className = 'next-sdk-tool-overlay'
222
-
223
- const glowRing = document.createElement('div')
224
- glowRing.className = 'next-sdk-tool-overlay__glow-ring'
225
-
226
- const panel = document.createElement('div')
227
- panel.className = 'next-sdk-tool-overlay__panel'
228
-
229
- const indicator = document.createElement('div')
230
- indicator.className = 'next-sdk-tool-overlay__indicator'
231
-
232
- const indicatorOrbit = document.createElement('div')
233
- indicatorOrbit.className = 'next-sdk-tool-overlay__indicator-orbit'
234
-
235
- const indicatorCore = document.createElement('div')
236
- indicatorCore.className = 'next-sdk-tool-overlay__indicator-core'
237
-
238
- const content = document.createElement('div')
239
- content.className = 'next-sdk-tool-overlay__content'
240
-
241
- const titleRow = document.createElement('div')
242
- titleRow.className = 'next-sdk-tool-overlay__title'
243
- titleRow.textContent = 'AI 正在调用页面工具'
244
-
245
- const titleDot = document.createElement('span')
246
- titleDot.className = 'next-sdk-tool-overlay__title-dot'
247
-
248
- const label = document.createElement('div')
249
- label.className = 'next-sdk-tool-overlay__label'
250
-
251
- titleRow.prepend(titleDot)
252
- content.appendChild(titleRow)
253
- content.appendChild(label)
254
-
255
- indicator.appendChild(indicatorOrbit)
256
- indicator.appendChild(indicatorCore)
257
- panel.appendChild(indicator)
258
- panel.appendChild(content)
259
- overlay.appendChild(glowRing)
260
- overlay.appendChild(panel)
261
-
262
- document.body.appendChild(overlay)
263
-
264
- overlayElement = overlay
265
- labelElement = label
266
- }
267
-
268
- function updateOverlay(config: RuntimeEffectConfig) {
269
- if (!ensureDomReady()) return
270
- ensureOverlayElement()
271
- if (!overlayElement || !labelElement) return
272
- overlayElement.classList.remove('next-sdk-tool-overlay--exit')
273
- labelElement.textContent = config.label
274
- }
275
-
276
- function removeOverlayWithAnimation() {
277
- if (!overlayElement) return
278
- overlayElement.classList.add('next-sdk-tool-overlay--exit')
279
- const localOverlay = overlayElement
280
- let handled = false
281
- let timerId: ReturnType<typeof setTimeout> | undefined
282
- const handle = () => {
283
- if (handled) return
284
- handled = true
285
- if (timerId !== undefined) {
286
- clearTimeout(timerId)
287
- timerId = undefined
288
- }
289
- if (localOverlay.parentNode) {
290
- localOverlay.parentNode.removeChild(localOverlay)
291
- }
292
- if (overlayElement === localOverlay) {
293
- overlayElement = null
294
- labelElement = null
295
- }
296
- localOverlay.removeEventListener('animationend', handle)
297
- }
298
- localOverlay.addEventListener('animationend', handle)
299
- // 兜底:若 animationend 未触发(如 prefers-reduced-motion 或样式被覆盖),确保清理
300
- timerId = setTimeout(handle, 500)
301
- }
302
-
303
- /**
304
- * 在页面上显示工具调用提示效果。
305
- * - 若当前已有其他工具在执行,仅更新文案,不重复创建 DOM
306
- * - 会增加 activeCount 计数,需配对调用 hideToolInvokeEffect
307
- */
308
- export function showToolInvokeEffect(config: RuntimeEffectConfig) {
309
- if (!ensureDomReady()) return
310
- activeCount += 1
311
- updateOverlay(config)
312
- }
313
-
314
- /**
315
- * 隐藏工具调用提示效果。
316
- * - 使用引用计数:只有当所有调用结束后才真正移除 Overlay
317
- */
318
- export function hideToolInvokeEffect() {
319
- if (!ensureDomReady() || activeCount <= 0) return
320
- activeCount -= 1
321
- if (activeCount === 0) {
322
- removeOverlayWithAnimation()
323
- }
324
- }
325
-
326
- /**
327
- * 将 RouteConfig 中的 invokeEffect 配置编译成运行时效果配置。
328
- * - boolean / undefined:关闭或开启默认文案
329
- * - 对象:允许自定义 label
330
- */
331
- export function resolveRuntimeEffectConfig(
332
- toolName: string,
333
- toolTitle: string | undefined,
334
- value: boolean | ToolInvokeEffectConfig | undefined
335
- ): RuntimeEffectConfig | undefined {
336
- if (!value) return undefined
337
- const baseLabel = toolTitle || toolName
338
- if (typeof value === 'boolean') {
339
- return value ? { label: baseLabel } : undefined
340
- }
341
- return {
342
- label: value.label || baseLabel
343
- }
344
- }
345
-
@@ -1,12 +0,0 @@
1
- import type { ActionContext } from '../context'
2
-
3
- export async function handleBrowserState(args: any, ctx: ActionContext) {
4
- if (window.__webmcpcli_beforeGetBrowserState) {
5
- try {
6
- window.__webmcpcli_beforeGetBrowserState()
7
- } catch (e) {
8
- console.warn('__webmcpcli_beforeGetBrowserState error:', e)
9
- }
10
- }
11
- return ctx.buildBrowserStateResponse(args.responseMode ?? 'diff')
12
- }
@@ -1,30 +0,0 @@
1
- import { clickElement } from '@page-agent/page-controller'
2
- import { waitForDomSettled } from '../utils/dom'
3
- import type { ActionContext } from '../context'
4
-
5
- export async function handleClick(args: any, ctx: ActionContext) {
6
- const mode = args.responseMode ?? 'diff'
7
- if (args.index === undefined) return ctx.actionError('点击结果: 缺少元素索引')
8
- const el = ctx.getRefMap().get(args.index)
9
- if (!el) {
10
- return ctx.actionError(
11
- `点击失败: ref 索引 ${args.index} 已失效(页面可能已刷新),已自动重新加载页面状态,请使用新的 ref 索引重试。`
12
- )
13
- }
14
-
15
- // 若 ref 指向 shadow host,解析其内部真正的可点击元素
16
- let targetEl = el as HTMLElement
17
- if (el.shadowRoot && !(el instanceof HTMLButtonElement) && !(el instanceof HTMLAnchorElement)) {
18
- const innerClickable = el.shadowRoot.querySelector(
19
- 'button, a, [role="button"], [role="link"]'
20
- ) as HTMLElement | null
21
- if (innerClickable) {
22
- targetEl = innerClickable
23
- }
24
- }
25
- await clickElement(targetEl)
26
- // 等待框架异步插入的校验错误/条件渲染内容稳定后再采集状态
27
- await waitForDomSettled()
28
- // 操作成功后自动返回 diff/both/full
29
- return ctx.buildBrowserStateResponse(mode)
30
- }
@@ -1,22 +0,0 @@
1
- import type { ActionContext } from '../context'
2
-
3
- export async function handleExecuteJavascript(args: any, ctx: ActionContext) {
4
- if (!args.script) return ctx.errContent('脚本执行异常: 缺少javascript代码')
5
- // eslint-disable-next-line no-new-func
6
- // 方式1:将脚本包裹在 async IIFE 中执行,允许 return 语句
7
- let result = await new Function(`return (async () => { ${args.script} })()`)()
8
- // 方式2:若 result 为 undefined(脚本没有 return),降级尝试以表达式方式求值
9
- // 场景:Agent 写了 "Array.from(...).map(...)" 但没有 return 关键字
10
- if (result === undefined) {
11
- try {
12
- // eslint-disable-next-line no-new-func
13
- result = await new Function(`return (async () => (${args.script}))()`)()
14
- } catch {
15
- // 表达式求值也失败(如含 await/let/const 等语句),保持 undefined
16
- }
17
- }
18
- await ctx.pageController.hideMask()
19
- return {
20
- content: [{ type: 'text' as const, text: `脚本执行结果: ${JSON.stringify(result)}` }]
21
- }
22
- }