weixin-devtools-mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +375 -0
- package/build/index.js +542 -0
- package/build/server.js +200 -0
- package/build/tools/ToolDefinition.js +52 -0
- package/build/tools/assert.js +245 -0
- package/build/tools/connection.js +670 -0
- package/build/tools/console.js +192 -0
- package/build/tools/diagnose.js +348 -0
- package/build/tools/index.js +80 -0
- package/build/tools/input.js +255 -0
- package/build/tools/navigate.js +310 -0
- package/build/tools/network.js +1111 -0
- package/build/tools/page.js +150 -0
- package/build/tools/screenshot.js +47 -0
- package/build/tools/snapshot.js +45 -0
- package/build/tools.js +2131 -0
- package/package.json +58 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输入交互工具
|
|
3
|
+
* 负责页面元素的点击、填写等交互操作
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { defineTool } from './ToolDefinition.js';
|
|
7
|
+
import { clickElement, inputText, getElementValue, setFormControl } from '../tools.js';
|
|
8
|
+
/**
|
|
9
|
+
* 点击页面元素
|
|
10
|
+
*/
|
|
11
|
+
export const clickTool = defineTool({
|
|
12
|
+
name: 'click',
|
|
13
|
+
description: '点击指定uid的页面元素',
|
|
14
|
+
schema: z.object({
|
|
15
|
+
uid: z.string().describe('页面快照中元素的唯一标识符'),
|
|
16
|
+
dblClick: z.boolean().optional().default(false).describe('是否为双击,默认false'),
|
|
17
|
+
}),
|
|
18
|
+
annotations: {
|
|
19
|
+
audience: ['developers'],
|
|
20
|
+
},
|
|
21
|
+
handler: async (request, response, context) => {
|
|
22
|
+
const { uid, dblClick } = request.params;
|
|
23
|
+
if (!context.currentPage) {
|
|
24
|
+
throw new Error('请先获取当前页面');
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const options = { uid, dblClick };
|
|
28
|
+
await clickElement(context.currentPage, context.elementMap, options);
|
|
29
|
+
const action = dblClick ? '双击' : '点击';
|
|
30
|
+
response.appendResponseLine(`${action}元素成功`);
|
|
31
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
32
|
+
// 点击后可能页面发生变化,建议包含快照
|
|
33
|
+
response.setIncludeSnapshot(true);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
37
|
+
response.appendResponseLine(`点击元素失败: ${errorMessage}`);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* 向元素输入文本
|
|
44
|
+
*/
|
|
45
|
+
export const inputTextTool = defineTool({
|
|
46
|
+
name: 'input_text',
|
|
47
|
+
description: '向input/textarea元素输入文本',
|
|
48
|
+
schema: z.object({
|
|
49
|
+
uid: z.string().describe('页面快照中元素的唯一标识符'),
|
|
50
|
+
text: z.string().describe('要输入的文本内容'),
|
|
51
|
+
clear: z.boolean().optional().default(false).describe('是否先清空元素内容,默认false'),
|
|
52
|
+
append: z.boolean().optional().default(false).describe('是否追加到现有内容,默认false'),
|
|
53
|
+
}),
|
|
54
|
+
annotations: {
|
|
55
|
+
audience: ['developers'],
|
|
56
|
+
},
|
|
57
|
+
handler: async (request, response, context) => {
|
|
58
|
+
const { uid, text, clear, append } = request.params;
|
|
59
|
+
if (!context.currentPage) {
|
|
60
|
+
throw new Error('请先获取当前页面');
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const options = { uid, text, clear, append };
|
|
64
|
+
await inputText(context.currentPage, context.elementMap, options);
|
|
65
|
+
let action = '输入文本';
|
|
66
|
+
if (clear)
|
|
67
|
+
action = '清空并输入文本';
|
|
68
|
+
if (append)
|
|
69
|
+
action = '追加文本';
|
|
70
|
+
response.appendResponseLine(`${action}成功`);
|
|
71
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
72
|
+
response.appendResponseLine(`内容: ${text}`);
|
|
73
|
+
// 输入后页面可能发生变化
|
|
74
|
+
response.setIncludeSnapshot(true);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
78
|
+
response.appendResponseLine(`输入文本失败: ${errorMessage}`);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* 获取元素值
|
|
85
|
+
*/
|
|
86
|
+
export const getValueTool = defineTool({
|
|
87
|
+
name: 'get_value',
|
|
88
|
+
description: '获取元素的值或文本内容',
|
|
89
|
+
schema: z.object({
|
|
90
|
+
uid: z.string().describe('页面快照中元素的唯一标识符'),
|
|
91
|
+
attribute: z.string().optional().describe('要获取的属性名,不指定则获取value或text'),
|
|
92
|
+
}),
|
|
93
|
+
annotations: {
|
|
94
|
+
audience: ['developers'],
|
|
95
|
+
},
|
|
96
|
+
handler: async (request, response, context) => {
|
|
97
|
+
const { uid, attribute } = request.params;
|
|
98
|
+
if (!context.currentPage) {
|
|
99
|
+
throw new Error('请先获取当前页面');
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const options = { uid, attribute };
|
|
103
|
+
const value = await getElementValue(context.currentPage, context.elementMap, options);
|
|
104
|
+
response.appendResponseLine(`获取元素值成功`);
|
|
105
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
106
|
+
if (attribute) {
|
|
107
|
+
response.appendResponseLine(`属性: ${attribute}`);
|
|
108
|
+
}
|
|
109
|
+
response.appendResponseLine(`值: ${value}`);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
113
|
+
response.appendResponseLine(`获取元素值失败: ${errorMessage}`);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* 设置表单控件值
|
|
120
|
+
*/
|
|
121
|
+
export const setFormControlTool = defineTool({
|
|
122
|
+
name: 'set_form_control',
|
|
123
|
+
description: '设置表单控件的值(如picker、switch、slider等)',
|
|
124
|
+
schema: z.object({
|
|
125
|
+
uid: z.string().describe('页面快照中元素的唯一标识符'),
|
|
126
|
+
value: z.any().describe('要设置的值'),
|
|
127
|
+
trigger: z.string().optional().default('change').describe('触发的事件类型,默认为change'),
|
|
128
|
+
}),
|
|
129
|
+
annotations: {
|
|
130
|
+
audience: ['developers'],
|
|
131
|
+
},
|
|
132
|
+
handler: async (request, response, context) => {
|
|
133
|
+
const { uid, value, trigger } = request.params;
|
|
134
|
+
if (!context.currentPage) {
|
|
135
|
+
throw new Error('请先获取当前页面');
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const options = { uid, value, trigger };
|
|
139
|
+
await setFormControl(context.currentPage, context.elementMap, options);
|
|
140
|
+
response.appendResponseLine(`设置表单控件成功`);
|
|
141
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
142
|
+
response.appendResponseLine(`值: ${JSON.stringify(value)}`);
|
|
143
|
+
response.appendResponseLine(`事件: ${trigger}`);
|
|
144
|
+
// 设置后页面可能发生变化
|
|
145
|
+
response.setIncludeSnapshot(true);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
149
|
+
response.appendResponseLine(`设置表单控件失败: ${errorMessage}`);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* 选择器选择选项(picker专用)
|
|
156
|
+
*/
|
|
157
|
+
export const selectPickerTool = defineTool({
|
|
158
|
+
name: 'select_picker',
|
|
159
|
+
description: '选择picker控件的选项',
|
|
160
|
+
schema: z.object({
|
|
161
|
+
uid: z.string().describe('picker元素的唯一标识符'),
|
|
162
|
+
value: z.union([z.number(), z.string(), z.array(z.any())]).describe('选项值,可以是索引、文本或多选数组'),
|
|
163
|
+
}),
|
|
164
|
+
annotations: {
|
|
165
|
+
audience: ['developers'],
|
|
166
|
+
},
|
|
167
|
+
handler: async (request, response, context) => {
|
|
168
|
+
const { uid, value } = request.params;
|
|
169
|
+
if (!context.currentPage) {
|
|
170
|
+
throw new Error('请先获取当前页面');
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const options = { uid, value, trigger: 'change' };
|
|
174
|
+
await setFormControl(context.currentPage, context.elementMap, options);
|
|
175
|
+
response.appendResponseLine(`选择picker选项成功`);
|
|
176
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
177
|
+
response.appendResponseLine(`选项: ${JSON.stringify(value)}`);
|
|
178
|
+
// 选择后页面可能发生变化
|
|
179
|
+
response.setIncludeSnapshot(true);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
183
|
+
response.appendResponseLine(`选择picker选项失败: ${errorMessage}`);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
/**
|
|
189
|
+
* 切换开关状态(switch专用)
|
|
190
|
+
*/
|
|
191
|
+
export const toggleSwitchTool = defineTool({
|
|
192
|
+
name: 'toggle_switch',
|
|
193
|
+
description: '切换switch开关的状态',
|
|
194
|
+
schema: z.object({
|
|
195
|
+
uid: z.string().describe('switch元素的唯一标识符'),
|
|
196
|
+
checked: z.boolean().describe('开关状态,true为开启,false为关闭'),
|
|
197
|
+
}),
|
|
198
|
+
annotations: {
|
|
199
|
+
audience: ['developers'],
|
|
200
|
+
},
|
|
201
|
+
handler: async (request, response, context) => {
|
|
202
|
+
const { uid, checked } = request.params;
|
|
203
|
+
if (!context.currentPage) {
|
|
204
|
+
throw new Error('请先获取当前页面');
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
const options = { uid, value: checked, trigger: 'change' };
|
|
208
|
+
await setFormControl(context.currentPage, context.elementMap, options);
|
|
209
|
+
response.appendResponseLine(`切换开关状态成功`);
|
|
210
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
211
|
+
response.appendResponseLine(`状态: ${checked ? '开启' : '关闭'}`);
|
|
212
|
+
// 切换后页面可能发生变化
|
|
213
|
+
response.setIncludeSnapshot(true);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
217
|
+
response.appendResponseLine(`切换开关状态失败: ${errorMessage}`);
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* 设置滑块值(slider专用)
|
|
224
|
+
*/
|
|
225
|
+
export const setSliderTool = defineTool({
|
|
226
|
+
name: 'set_slider',
|
|
227
|
+
description: '设置slider滑块的值',
|
|
228
|
+
schema: z.object({
|
|
229
|
+
uid: z.string().describe('slider元素的唯一标识符'),
|
|
230
|
+
value: z.number().describe('滑块值'),
|
|
231
|
+
}),
|
|
232
|
+
annotations: {
|
|
233
|
+
audience: ['developers'],
|
|
234
|
+
},
|
|
235
|
+
handler: async (request, response, context) => {
|
|
236
|
+
const { uid, value } = request.params;
|
|
237
|
+
if (!context.currentPage) {
|
|
238
|
+
throw new Error('请先获取当前页面');
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const options = { uid, value, trigger: 'change' };
|
|
242
|
+
await setFormControl(context.currentPage, context.elementMap, options);
|
|
243
|
+
response.appendResponseLine(`设置滑块值成功`);
|
|
244
|
+
response.appendResponseLine(`UID: ${uid}`);
|
|
245
|
+
response.appendResponseLine(`值: ${value}`);
|
|
246
|
+
// 设置后页面可能发生变化
|
|
247
|
+
response.setIncludeSnapshot(true);
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
251
|
+
response.appendResponseLine(`设置滑块值失败: ${errorMessage}`);
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
});
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 页面导航工具
|
|
3
|
+
* 提供小程序页面跳转、返回、Tab切换等导航功能
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { defineTool } from './ToolDefinition.js';
|
|
7
|
+
import { navigateToPage, navigateBack, switchTab, getCurrentPageInfo, reLaunch } from '../tools.js';
|
|
8
|
+
/**
|
|
9
|
+
* 跳转到指定页面
|
|
10
|
+
*/
|
|
11
|
+
export const navigateToTool = defineTool({
|
|
12
|
+
name: 'navigate_to',
|
|
13
|
+
description: '跳转到指定页面',
|
|
14
|
+
schema: z.object({
|
|
15
|
+
url: z.string().describe('目标页面路径'),
|
|
16
|
+
params: z.record(z.string(), z.any()).optional().describe('页面参数(查询参数)'),
|
|
17
|
+
waitForLoad: z.boolean().optional().default(true).describe('是否等待页面加载完成,默认true'),
|
|
18
|
+
timeout: z.number().optional().default(10000).describe('等待超时时间(毫秒),默认10000ms'),
|
|
19
|
+
}),
|
|
20
|
+
annotations: {
|
|
21
|
+
audience: ['developers'],
|
|
22
|
+
},
|
|
23
|
+
handler: async (request, response, context) => {
|
|
24
|
+
const { url, params, waitForLoad, timeout } = request.params;
|
|
25
|
+
if (!context.miniProgram) {
|
|
26
|
+
throw new Error('请先连接到微信开发者工具');
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const options = {
|
|
30
|
+
url,
|
|
31
|
+
params,
|
|
32
|
+
waitForLoad,
|
|
33
|
+
timeout
|
|
34
|
+
};
|
|
35
|
+
await navigateToPage(context.miniProgram, options);
|
|
36
|
+
response.appendResponseLine(`页面跳转成功`);
|
|
37
|
+
response.appendResponseLine(`目标页面: ${url}`);
|
|
38
|
+
if (params && Object.keys(params).length > 0) {
|
|
39
|
+
response.appendResponseLine(`参数: ${JSON.stringify(params)}`);
|
|
40
|
+
}
|
|
41
|
+
// 页面跳转后,更新当前页面信息
|
|
42
|
+
try {
|
|
43
|
+
context.currentPage = await context.miniProgram.currentPage();
|
|
44
|
+
response.appendResponseLine(`当前页面已更新`);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
response.appendResponseLine(`警告: 无法更新当前页面信息`);
|
|
48
|
+
}
|
|
49
|
+
// 页面跳转后建议获取新快照
|
|
50
|
+
response.setIncludeSnapshot(true);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
54
|
+
response.appendResponseLine(`页面跳转失败: ${errorMessage}`);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* 返回上一页或指定层数
|
|
61
|
+
*/
|
|
62
|
+
export const navigateBackTool = defineTool({
|
|
63
|
+
name: 'navigate_back',
|
|
64
|
+
description: '返回上一页或指定层数',
|
|
65
|
+
schema: z.object({
|
|
66
|
+
delta: z.number().optional().default(1).describe('返回层数,默认1'),
|
|
67
|
+
waitForLoad: z.boolean().optional().default(true).describe('是否等待页面加载完成,默认true'),
|
|
68
|
+
timeout: z.number().optional().default(5000).describe('等待超时时间(毫秒),默认5000ms'),
|
|
69
|
+
}),
|
|
70
|
+
annotations: {
|
|
71
|
+
audience: ['developers'],
|
|
72
|
+
},
|
|
73
|
+
handler: async (request, response, context) => {
|
|
74
|
+
const { delta, waitForLoad, timeout } = request.params;
|
|
75
|
+
if (!context.miniProgram) {
|
|
76
|
+
throw new Error('请先连接到微信开发者工具');
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const options = {
|
|
80
|
+
delta,
|
|
81
|
+
waitForLoad,
|
|
82
|
+
timeout
|
|
83
|
+
};
|
|
84
|
+
await navigateBack(context.miniProgram, options);
|
|
85
|
+
response.appendResponseLine(`页面返回成功`);
|
|
86
|
+
response.appendResponseLine(`返回层数: ${delta}`);
|
|
87
|
+
// 页面返回后,更新当前页面信息
|
|
88
|
+
try {
|
|
89
|
+
context.currentPage = await context.miniProgram.currentPage();
|
|
90
|
+
response.appendResponseLine(`当前页面已更新`);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
response.appendResponseLine(`警告: 无法更新当前页面信息`);
|
|
94
|
+
}
|
|
95
|
+
// 页面返回后建议获取新快照
|
|
96
|
+
response.setIncludeSnapshot(true);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
100
|
+
response.appendResponseLine(`页面返回失败: ${errorMessage}`);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* 切换到指定Tab页
|
|
107
|
+
*/
|
|
108
|
+
export const switchTabTool = defineTool({
|
|
109
|
+
name: 'switch_tab',
|
|
110
|
+
description: '切换到指定Tab页',
|
|
111
|
+
schema: z.object({
|
|
112
|
+
url: z.string().describe('Tab页路径'),
|
|
113
|
+
waitForLoad: z.boolean().optional().default(true).describe('是否等待页面加载完成,默认true'),
|
|
114
|
+
timeout: z.number().optional().default(5000).describe('等待超时时间(毫秒),默认5000ms'),
|
|
115
|
+
}),
|
|
116
|
+
annotations: {
|
|
117
|
+
audience: ['developers'],
|
|
118
|
+
},
|
|
119
|
+
handler: async (request, response, context) => {
|
|
120
|
+
const { url, waitForLoad, timeout } = request.params;
|
|
121
|
+
if (!context.miniProgram) {
|
|
122
|
+
throw new Error('请先连接到微信开发者工具');
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const options = {
|
|
126
|
+
url,
|
|
127
|
+
waitForLoad,
|
|
128
|
+
timeout
|
|
129
|
+
};
|
|
130
|
+
await switchTab(context.miniProgram, options);
|
|
131
|
+
response.appendResponseLine(`Tab切换成功`);
|
|
132
|
+
response.appendResponseLine(`目标Tab: ${url}`);
|
|
133
|
+
// Tab切换后,更新当前页面信息
|
|
134
|
+
try {
|
|
135
|
+
context.currentPage = await context.miniProgram.currentPage();
|
|
136
|
+
response.appendResponseLine(`当前页面已更新`);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
response.appendResponseLine(`警告: 无法更新当前页面信息`);
|
|
140
|
+
}
|
|
141
|
+
// Tab切换后建议获取新快照
|
|
142
|
+
response.setIncludeSnapshot(true);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
146
|
+
response.appendResponseLine(`Tab切换失败: ${errorMessage}`);
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
/**
|
|
152
|
+
* 重新启动到指定页面
|
|
153
|
+
*/
|
|
154
|
+
export const reLaunchTool = defineTool({
|
|
155
|
+
name: 'relaunch',
|
|
156
|
+
description: '重新启动小程序并跳转到指定页面',
|
|
157
|
+
schema: z.object({
|
|
158
|
+
url: z.string().describe('目标页面路径'),
|
|
159
|
+
params: z.record(z.string(), z.any()).optional().describe('页面参数(查询参数)'),
|
|
160
|
+
waitForLoad: z.boolean().optional().default(true).describe('是否等待页面加载完成,默认true'),
|
|
161
|
+
timeout: z.number().optional().default(10000).describe('等待超时时间(毫秒),默认10000ms'),
|
|
162
|
+
}),
|
|
163
|
+
annotations: {
|
|
164
|
+
audience: ['developers'],
|
|
165
|
+
},
|
|
166
|
+
handler: async (request, response, context) => {
|
|
167
|
+
const { url, params, waitForLoad, timeout } = request.params;
|
|
168
|
+
if (!context.miniProgram) {
|
|
169
|
+
throw new Error('请先连接到微信开发者工具');
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const options = {
|
|
173
|
+
url,
|
|
174
|
+
params,
|
|
175
|
+
waitForLoad,
|
|
176
|
+
timeout
|
|
177
|
+
};
|
|
178
|
+
await reLaunch(context.miniProgram, options);
|
|
179
|
+
response.appendResponseLine(`重新启动成功`);
|
|
180
|
+
response.appendResponseLine(`目标页面: ${url}`);
|
|
181
|
+
if (params && Object.keys(params).length > 0) {
|
|
182
|
+
response.appendResponseLine(`参数: ${JSON.stringify(params)}`);
|
|
183
|
+
}
|
|
184
|
+
// 重新启动后,更新当前页面信息
|
|
185
|
+
try {
|
|
186
|
+
context.currentPage = await context.miniProgram.currentPage();
|
|
187
|
+
response.appendResponseLine(`当前页面已更新`);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
response.appendResponseLine(`警告: 无法更新当前页面信息`);
|
|
191
|
+
}
|
|
192
|
+
// 重新启动后建议获取新快照
|
|
193
|
+
response.setIncludeSnapshot(true);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
197
|
+
response.appendResponseLine(`重新启动失败: ${errorMessage}`);
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
/**
|
|
203
|
+
* 获取当前页面信息
|
|
204
|
+
*/
|
|
205
|
+
export const getPageInfoTool = defineTool({
|
|
206
|
+
name: 'get_page_info',
|
|
207
|
+
description: '获取当前页面的详细信息',
|
|
208
|
+
schema: z.object({}),
|
|
209
|
+
annotations: {
|
|
210
|
+
audience: ['developers'],
|
|
211
|
+
},
|
|
212
|
+
handler: async (request, response, context) => {
|
|
213
|
+
if (!context.miniProgram) {
|
|
214
|
+
throw new Error('请先连接到微信开发者工具');
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const pageInfo = await getCurrentPageInfo(context.miniProgram);
|
|
218
|
+
response.appendResponseLine(`页面信息获取成功`);
|
|
219
|
+
response.appendResponseLine(`路径: ${pageInfo.path}`);
|
|
220
|
+
if (pageInfo.title) {
|
|
221
|
+
response.appendResponseLine(`标题: ${pageInfo.title}`);
|
|
222
|
+
}
|
|
223
|
+
if (pageInfo.query && Object.keys(pageInfo.query).length > 0) {
|
|
224
|
+
response.appendResponseLine(`查询参数: ${JSON.stringify(pageInfo.query)}`);
|
|
225
|
+
}
|
|
226
|
+
response.appendResponseLine('');
|
|
227
|
+
response.appendResponseLine('完整信息:');
|
|
228
|
+
response.appendResponseLine(JSON.stringify(pageInfo, null, 2));
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
232
|
+
response.appendResponseLine(`获取页面信息失败: ${errorMessage}`);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
/**
|
|
238
|
+
* 重定向到指定页面(替换当前页面)
|
|
239
|
+
*/
|
|
240
|
+
export const redirectToTool = defineTool({
|
|
241
|
+
name: 'redirect_to',
|
|
242
|
+
description: '重定向到指定页面(关闭当前页面并跳转)',
|
|
243
|
+
schema: z.object({
|
|
244
|
+
url: z.string().describe('目标页面路径'),
|
|
245
|
+
params: z.record(z.string(), z.any()).optional().describe('页面参数(查询参数)'),
|
|
246
|
+
waitForLoad: z.boolean().optional().default(true).describe('是否等待页面加载完成,默认true'),
|
|
247
|
+
timeout: z.number().optional().default(10000).describe('等待超时时间(毫秒),默认10000ms'),
|
|
248
|
+
}),
|
|
249
|
+
annotations: {
|
|
250
|
+
audience: ['developers'],
|
|
251
|
+
},
|
|
252
|
+
handler: async (request, response, context) => {
|
|
253
|
+
const { url, params, waitForLoad, timeout } = request.params;
|
|
254
|
+
if (!context.miniProgram) {
|
|
255
|
+
throw new Error('请先连接到微信开发者工具');
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
// 构建完整的URL
|
|
259
|
+
let fullUrl = url;
|
|
260
|
+
if (params && Object.keys(params).length > 0) {
|
|
261
|
+
const queryString = Object.entries(params)
|
|
262
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
|
|
263
|
+
.join('&');
|
|
264
|
+
fullUrl += (url.includes('?') ? '&' : '?') + queryString;
|
|
265
|
+
}
|
|
266
|
+
// 执行重定向
|
|
267
|
+
await context.miniProgram.redirectTo(fullUrl);
|
|
268
|
+
// 等待页面加载完成
|
|
269
|
+
if (waitForLoad) {
|
|
270
|
+
const startTime = Date.now();
|
|
271
|
+
while (Date.now() - startTime < timeout) {
|
|
272
|
+
try {
|
|
273
|
+
const currentPage = await context.miniProgram.currentPage();
|
|
274
|
+
if (currentPage) {
|
|
275
|
+
const currentPath = await currentPage.path;
|
|
276
|
+
// 检查是否已经重定向到目标页面
|
|
277
|
+
if (currentPath.includes(url.split('?')[0])) {
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
// 继续等待
|
|
284
|
+
}
|
|
285
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
response.appendResponseLine(`页面重定向成功`);
|
|
289
|
+
response.appendResponseLine(`目标页面: ${url}`);
|
|
290
|
+
if (params && Object.keys(params).length > 0) {
|
|
291
|
+
response.appendResponseLine(`参数: ${JSON.stringify(params)}`);
|
|
292
|
+
}
|
|
293
|
+
// 重定向后,更新当前页面信息
|
|
294
|
+
try {
|
|
295
|
+
context.currentPage = await context.miniProgram.currentPage();
|
|
296
|
+
response.appendResponseLine(`当前页面已更新`);
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
response.appendResponseLine(`警告: 无法更新当前页面信息`);
|
|
300
|
+
}
|
|
301
|
+
// 重定向后建议获取新快照
|
|
302
|
+
response.setIncludeSnapshot(true);
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
306
|
+
response.appendResponseLine(`页面重定向失败: ${errorMessage}`);
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
});
|