cicy-desktop 1.0.8

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 (66) hide show
  1. package/.github/workflows/build.yml +85 -0
  2. package/.kiro/steering/dev-workflow.md +166 -0
  3. package/AGENTS.md +247 -0
  4. package/CLAUDE.md +162 -0
  5. package/DOCKER.md +85 -0
  6. package/Dockerfile +46 -0
  7. package/README.md +720 -0
  8. package/TODO-anti-detection.md +326 -0
  9. package/bin/cicy +176 -0
  10. package/bin/preinstall.sh +32 -0
  11. package/copy-to-desktop.sh +26 -0
  12. package/docs/AUTOMATION-API.md +342 -0
  13. package/docs/REQUEST_MONITORING.md +435 -0
  14. package/docs/REST-API-FEATURE.md +155 -0
  15. package/docs/REST-API.md +319 -0
  16. package/docs/feature-distributed-multi-agent.md +555 -0
  17. package/docs/yaml.md +255 -0
  18. package/electron-mcp-fixed.command +134 -0
  19. package/electron-mcp-simple.command +135 -0
  20. package/electron-mcp.command +92 -0
  21. package/generate-openapi.js +158 -0
  22. package/jest.config.js +10 -0
  23. package/jest.setup.global.js +13 -0
  24. package/jest.teardown.global.js +7 -0
  25. package/package.json +75 -0
  26. package/service.sh +164 -0
  27. package/src/config.js +8 -0
  28. package/src/extension/inject.js +135 -0
  29. package/src/main-old.js +837 -0
  30. package/src/main.js +403 -0
  31. package/src/preload-rpc.js +4 -0
  32. package/src/server/args-parser.js +37 -0
  33. package/src/server/electron-setup.js +33 -0
  34. package/src/server/express-app.js +166 -0
  35. package/src/server/logging.js +58 -0
  36. package/src/server/mcp-server.js +53 -0
  37. package/src/server/tool-registry.js +77 -0
  38. package/src/server/ui-routes.js +81 -0
  39. package/src/swagger-ui.html +41 -0
  40. package/src/tools/account-tools.js +194 -0
  41. package/src/tools/automation-tools.js +297 -0
  42. package/src/tools/cdp-tools.js +444 -0
  43. package/src/tools/clipboard-tools.js +180 -0
  44. package/src/tools/download-tools.js +57 -0
  45. package/src/tools/exec-js.js +297 -0
  46. package/src/tools/exec-tools.js +139 -0
  47. package/src/tools/file-tools.js +212 -0
  48. package/src/tools/hook-chatgpt.js +489 -0
  49. package/src/tools/hook-gemini.js +454 -0
  50. package/src/tools/index.js +19 -0
  51. package/src/tools/ipc-bridge.js +31 -0
  52. package/src/tools/ping.js +60 -0
  53. package/src/tools/r-reset.js +28 -0
  54. package/src/tools/screenshot-tools.js +28 -0
  55. package/src/tools/system-tools.js +531 -0
  56. package/src/tools/window-tools.js +882 -0
  57. package/src/ui.html +914 -0
  58. package/src/utils/auth.js +81 -0
  59. package/src/utils/cdp-utils.js +8 -0
  60. package/src/utils/download-manager.js +41 -0
  61. package/src/utils/process-utils.js +185 -0
  62. package/src/utils/snapshot-utils.js +56 -0
  63. package/src/utils/window-monitor.js +605 -0
  64. package/src/utils/window-state.js +137 -0
  65. package/src/utils/window-utils.js +336 -0
  66. package/update-desktop.sh +33 -0
@@ -0,0 +1,444 @@
1
+ const { BrowserWindow, clipboard } = require("electron");
2
+ const { z } = require("zod");
3
+ const { sendCDP } = require("../utils/cdp-utils");
4
+
5
+ function registerTools(registerTool) {
6
+ registerTool(
7
+ "cdp_click",
8
+ "使用 Chrome DevTools Protocol 点击页面指定坐标",
9
+ z.object({
10
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
11
+ x: z.number().describe("X 坐标"),
12
+ y: z.number().describe("Y 坐标"),
13
+ button: z.enum(["left", "right", "middle"]).optional().default("left").describe("鼠标按钮"),
14
+ }),
15
+ async ({ win_id, x, y, button }) => {
16
+ try {
17
+ const win = BrowserWindow.fromId(win_id);
18
+ if (!win) throw new Error(`Window ${win_id} not found`);
19
+
20
+ await sendCDP(win.webContents, "Input.dispatchMouseEvent", {
21
+ type: "mousePressed",
22
+ x,
23
+ y,
24
+ button,
25
+ clickCount: 1,
26
+ });
27
+
28
+ await sendCDP(win.webContents, "Input.dispatchMouseEvent", {
29
+ type: "mouseReleased",
30
+ x,
31
+ y,
32
+ button,
33
+ clickCount: 1,
34
+ });
35
+
36
+ return { content: [{ type: "text", text: `Clicked at (${x}, ${y})` }] };
37
+ } catch (error) {
38
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
39
+ }
40
+ },
41
+ { tag: "Input" }
42
+ );
43
+
44
+ registerTool(
45
+ "cdp_dblclick",
46
+ "使用 Chrome DevTools Protocol 双击页面指定坐标",
47
+ z.object({
48
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
49
+ x: z.number().describe("X 坐标"),
50
+ y: z.number().describe("Y 坐标"),
51
+ button: z.enum(["left", "right", "middle"]).optional().default("left").describe("鼠标按钮"),
52
+ }),
53
+ async ({ win_id, x, y, button }) => {
54
+ try {
55
+ const win = BrowserWindow.fromId(win_id);
56
+ if (!win) throw new Error(`Window ${win_id} not found`);
57
+
58
+ await sendCDP(win.webContents, "Input.dispatchMouseEvent", {
59
+ type: "mousePressed",
60
+ x,
61
+ y,
62
+ button,
63
+ clickCount: 2,
64
+ });
65
+
66
+ await sendCDP(win.webContents, "Input.dispatchMouseEvent", {
67
+ type: "mouseReleased",
68
+ x,
69
+ y,
70
+ button,
71
+ clickCount: 2,
72
+ });
73
+
74
+ return { content: [{ type: "text", text: `Double clicked at (${x}, ${y})` }] };
75
+ } catch (error) {
76
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
77
+ }
78
+ },
79
+ { tag: "Input" }
80
+ );
81
+
82
+ registerTool(
83
+ "cdp_press_key",
84
+ "使用 CDP 按下指定按键",
85
+ z.object({
86
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
87
+ key: z.string().describe("按键名称,如 'Enter', 'Backspace', 'a', 'A'"),
88
+ }),
89
+ async ({ win_id, key }) => {
90
+ try {
91
+ const win = BrowserWindow.fromId(win_id);
92
+ if (!win) throw new Error(`Window ${win_id} not found`);
93
+
94
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
95
+ type: "keyDown",
96
+ key,
97
+ });
98
+
99
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
100
+ type: "keyUp",
101
+ key,
102
+ });
103
+
104
+ return { content: [{ type: "text", text: `Pressed key: ${key}` }] };
105
+ } catch (error) {
106
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
107
+ }
108
+ },
109
+ { tag: "Input" }
110
+ );
111
+
112
+ registerTool(
113
+ "cdp_press_enter",
114
+ "使用 CDP 按下回车键",
115
+ z.object({
116
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
117
+ }),
118
+ async ({ win_id }) => {
119
+ try {
120
+ const win = BrowserWindow.fromId(win_id);
121
+ if (!win) throw new Error(`Window ${win_id} not found`);
122
+
123
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
124
+ type: "keyDown",
125
+ key: "Enter",
126
+ });
127
+
128
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
129
+ type: "keyUp",
130
+ key: "Enter",
131
+ });
132
+
133
+ return { content: [{ type: "text", text: "Pressed Enter" }] };
134
+ } catch (error) {
135
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
136
+ }
137
+ },
138
+ { tag: "Input" }
139
+ );
140
+
141
+ registerTool(
142
+ "cdp_press_backspace",
143
+ "使用 CDP 按下退格键",
144
+ z.object({
145
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
146
+ }),
147
+ async ({ win_id }) => {
148
+ try {
149
+ const win = BrowserWindow.fromId(win_id);
150
+ if (!win) throw new Error(`Window ${win_id} not found`);
151
+
152
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
153
+ type: "keyDown",
154
+ key: "Backspace",
155
+ });
156
+
157
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
158
+ type: "keyUp",
159
+ key: "Backspace",
160
+ });
161
+
162
+ return { content: [{ type: "text", text: "Pressed Backspace" }] };
163
+ } catch (error) {
164
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
165
+ }
166
+ },
167
+ { tag: "Input" }
168
+ );
169
+
170
+ registerTool(
171
+ "cdp_press_copy",
172
+ "使用 CDP 执行复制操作 (Ctrl+C)",
173
+ z.object({
174
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
175
+ }),
176
+ async ({ win_id }) => {
177
+ try {
178
+ const win = BrowserWindow.fromId(win_id);
179
+ if (!win) throw new Error(`Window ${win_id} not found`);
180
+
181
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
182
+ type: "keyDown",
183
+ key: "c",
184
+ modifiers: 2,
185
+ });
186
+
187
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
188
+ type: "keyUp",
189
+ key: "c",
190
+ modifiers: 2,
191
+ });
192
+
193
+ return { content: [{ type: "text", text: "Pressed Ctrl+C" }] };
194
+ } catch (error) {
195
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
196
+ }
197
+ },
198
+ { tag: "Input" }
199
+ );
200
+
201
+ registerTool(
202
+ "cdp_press_paste",
203
+ "执行粘贴操作,支持多种方法",
204
+ z.object({
205
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
206
+ method: z
207
+ .enum(["sendInputEvent", "cdp", "js"])
208
+ .optional()
209
+ .default("sendInputEvent")
210
+ .describe("粘贴方法: sendInputEvent(推荐), cdp(CDP按键), js(JavaScript事件)"),
211
+ }),
212
+ async ({ win_id, method }) => {
213
+ try {
214
+ const win = BrowserWindow.fromId(win_id);
215
+ if (!win) throw new Error(`Window ${win_id} not found`);
216
+
217
+ if (method === "sendInputEvent") {
218
+ // Method 1: Electron sendInputEvent (推荐 - 触发真实事件)
219
+ win.webContents.sendInputEvent({
220
+ type: "keyDown",
221
+ keyCode: "V",
222
+ modifiers: ["control"],
223
+ });
224
+ win.webContents.sendInputEvent({
225
+ type: "char",
226
+ keyCode: "V",
227
+ modifiers: ["control"],
228
+ });
229
+ win.webContents.sendInputEvent({
230
+ type: "keyUp",
231
+ keyCode: "V",
232
+ modifiers: ["control"],
233
+ });
234
+ return { content: [{ type: "text", text: "Paste via sendInputEvent" }] };
235
+ } else if (method === "cdp") {
236
+ // Method 2: CDP dispatchKeyEvent (底层 - 不触发paste事件)
237
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
238
+ type: "keyDown",
239
+ key: "v",
240
+ modifiers: 2,
241
+ });
242
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
243
+ type: "keyUp",
244
+ key: "v",
245
+ modifiers: 2,
246
+ });
247
+ return {
248
+ content: [{ type: "text", text: "Paste via CDP (may not trigger paste event)" }],
249
+ };
250
+ } else if (method === "js") {
251
+ // Method 3: JavaScript ClipboardEvent (完全控制)
252
+ const text = clipboard.readText();
253
+ const image = clipboard.readImage();
254
+
255
+ if (!image.isEmpty()) {
256
+ // Paste image
257
+ const buffer = image.toPNG();
258
+ const base64 = buffer.toString("base64");
259
+ await win.webContents.executeJavaScript(`
260
+ (async function() {
261
+ const base64 = ${JSON.stringify(base64)};
262
+ const blob = await fetch('data:image/png;base64,' + base64).then(r => r.blob());
263
+ const file = new File([blob], 'image.png', { type: 'image/png' });
264
+
265
+ const dt = new DataTransfer();
266
+ dt.items.add(file);
267
+
268
+ const event = new ClipboardEvent('paste', {
269
+ clipboardData: dt,
270
+ bubbles: true,
271
+ cancelable: true
272
+ });
273
+
274
+ document.activeElement?.dispatchEvent(event) || document.dispatchEvent(event);
275
+ return 'Image pasted';
276
+ })();
277
+ `);
278
+ return { content: [{ type: "text", text: "Paste image via JS event" }] };
279
+ } else {
280
+ // Paste text
281
+ await win.webContents.executeJavaScript(`
282
+ (function() {
283
+ const text = ${JSON.stringify(text)};
284
+ const dt = new DataTransfer();
285
+ dt.setData('text/plain', text);
286
+
287
+ const event = new ClipboardEvent('paste', {
288
+ clipboardData: dt,
289
+ bubbles: true,
290
+ cancelable: true
291
+ });
292
+
293
+ document.activeElement?.dispatchEvent(event) || document.dispatchEvent(event);
294
+ return 'Text pasted';
295
+ })();
296
+ `);
297
+ return { content: [{ type: "text", text: "Paste text via JS event" }] };
298
+ }
299
+ }
300
+ } catch (error) {
301
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
302
+ }
303
+ },
304
+ { tag: "Input" }
305
+ );
306
+
307
+ registerTool(
308
+ "cdp_press_selectall",
309
+ "使用 CDP 执行全选操作 (Ctrl+A)",
310
+ z.object({
311
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
312
+ }),
313
+ async ({ win_id }) => {
314
+ try {
315
+ const win = BrowserWindow.fromId(win_id);
316
+ if (!win) throw new Error(`Window ${win_id} not found`);
317
+
318
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
319
+ type: "keyDown",
320
+ key: "a",
321
+ modifiers: 2,
322
+ });
323
+
324
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
325
+ type: "keyUp",
326
+ key: "a",
327
+ modifiers: 2,
328
+ });
329
+
330
+ return { content: [{ type: "text", text: "Pressed Ctrl+A" }] };
331
+ } catch (error) {
332
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
333
+ }
334
+ },
335
+ { tag: "Input" }
336
+ );
337
+
338
+ registerTool(
339
+ "cdp_press_cut",
340
+ "使用 CDP 执行剪切操作 (Ctrl+X)",
341
+ z.object({
342
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
343
+ }),
344
+ async ({ win_id }) => {
345
+ try {
346
+ const win = BrowserWindow.fromId(win_id);
347
+ if (!win) throw new Error(`Window ${win_id} not found`);
348
+
349
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
350
+ type: "keyDown",
351
+ key: "x",
352
+ modifiers: 2,
353
+ });
354
+
355
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
356
+ type: "keyUp",
357
+ key: "x",
358
+ modifiers: 2,
359
+ });
360
+
361
+ return { content: [{ type: "text", text: "Pressed Ctrl+X" }] };
362
+ } catch (error) {
363
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
364
+ }
365
+ },
366
+ { tag: "Input" }
367
+ );
368
+
369
+ registerTool(
370
+ "cdp_type_text",
371
+ "使用 CDP 输入文本",
372
+ z.object({
373
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
374
+ text: z.string().describe("要输入的文本"),
375
+ }),
376
+ async ({ win_id, text }) => {
377
+ try {
378
+ const win = BrowserWindow.fromId(win_id);
379
+ if (!win) throw new Error(`Window ${win_id} not found`);
380
+
381
+ await sendCDP(win.webContents, "Input.insertText", { text });
382
+
383
+ return { content: [{ type: "text", text: `Typed: ${text}` }] };
384
+ } catch (error) {
385
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
386
+ }
387
+ },
388
+ { tag: "Input" }
389
+ );
390
+
391
+ registerTool(
392
+ "cdp_scroll",
393
+ "使用 CDP 滚动页面",
394
+ z.object({
395
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
396
+ x: z.number().optional().default(0).describe("水平滚动距离"),
397
+ y: z.number().describe("垂直滚动距离"),
398
+ }),
399
+ async ({ win_id, x, y }) => {
400
+ try {
401
+ const win = BrowserWindow.fromId(win_id);
402
+ if (!win) throw new Error(`Window ${win_id} not found`);
403
+
404
+ await sendCDP(win.webContents, "Input.dispatchMouseEvent", {
405
+ type: "mouseWheel",
406
+ x: 0,
407
+ y: 0,
408
+ deltaX: x,
409
+ deltaY: y,
410
+ });
411
+
412
+ return { content: [{ type: "text", text: `Scrolled: x=${x}, y=${y}` }] };
413
+ } catch (error) {
414
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
415
+ }
416
+ },
417
+ { tag: "Input" }
418
+ );
419
+
420
+ registerTool(
421
+ "cdp_sendcmd",
422
+ "使用 CDP 发送任意 Chrome DevTools Protocol 命令",
423
+ z.object({
424
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
425
+ method: z.string().describe("CDP 方法名,如 'Page.navigate', 'Runtime.evaluate'"),
426
+ params: z.record(z.any()).optional().default({}).describe("CDP 参数对象"),
427
+ }),
428
+ async ({ win_id, method, params }) => {
429
+ try {
430
+ const win = BrowserWindow.fromId(win_id);
431
+ if (!win) throw new Error(`Window ${win_id} not found`);
432
+
433
+ const result = await sendCDP(win.webContents, method, params);
434
+
435
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
436
+ } catch (error) {
437
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
438
+ }
439
+ },
440
+ { tag: "CDP" }
441
+ );
442
+ }
443
+
444
+ module.exports = registerTools;
@@ -0,0 +1,180 @@
1
+ const { clipboard, BrowserWindow } = require("electron");
2
+ const { z } = require("zod");
3
+ const { sendCDP } = require("../utils/cdp-utils");
4
+
5
+ function registerTools(registerTool) {
6
+ registerTool(
7
+ "clipboard_write_text",
8
+ "Write text to system clipboard",
9
+ z.object({
10
+ text: z.string().describe("Text to write to clipboard"),
11
+ }),
12
+ async ({ text }) => {
13
+ try {
14
+ clipboard.writeText(text);
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: `Text written to clipboard: ${text.substring(0, 50)}${text.length > 50 ? "..." : ""}`,
20
+ },
21
+ ],
22
+ };
23
+ } catch (error) {
24
+ return {
25
+ content: [{ type: "text", text: `Error: ${error.message}` }],
26
+ isError: true,
27
+ };
28
+ }
29
+ },
30
+ { tag: "Clipboard" }
31
+ );
32
+
33
+ registerTool(
34
+ "clipboard_read_text",
35
+ "Read text from system clipboard",
36
+ z.object({}),
37
+ async () => {
38
+ try {
39
+ const text = clipboard.readText();
40
+ return {
41
+ content: [{ type: "text", text: `Clipboard text: ${text}` }],
42
+ };
43
+ } catch (error) {
44
+ return {
45
+ content: [{ type: "text", text: `Error: ${error.message}` }],
46
+ isError: true,
47
+ };
48
+ }
49
+ },
50
+ { tag: "Clipboard" }
51
+ );
52
+
53
+ registerTool(
54
+ "clipboard_write_image",
55
+ "Write image to system clipboard from base64 data",
56
+ z.object({
57
+ base64: z.string().describe("Base64 encoded image data"),
58
+ }),
59
+ async ({ base64 }) => {
60
+ try {
61
+ const { nativeImage } = require("electron");
62
+ const image = nativeImage.createFromDataURL(`data:image/png;base64,${base64}`);
63
+ clipboard.writeImage(image);
64
+ const size = image.getSize();
65
+ return {
66
+ content: [
67
+ { type: "text", text: `Image written to clipboard: ${size.width}x${size.height}` },
68
+ ],
69
+ };
70
+ } catch (error) {
71
+ return {
72
+ content: [{ type: "text", text: `Error: ${error.message}` }],
73
+ isError: true,
74
+ };
75
+ }
76
+ },
77
+ { tag: "Clipboard" }
78
+ );
79
+ registerTool(
80
+ "test_paste_methods",
81
+ "测试三种粘贴方法,返回哪些方法有效",
82
+ z.object({
83
+ win_id: z.number().optional().default(1).describe("窗口 ID"),
84
+ }),
85
+ async ({ win_id }) => {
86
+ try {
87
+ const win = BrowserWindow.fromId(win_id);
88
+ if (!win) throw new Error(`Window ${win_id} not found`);
89
+
90
+ // Inject test listener
91
+ await win.webContents.executeJavaScript(`
92
+ window.__pasteTestResults = {
93
+ sendInputEvent: false,
94
+ cdp: false,
95
+ js: false,
96
+ count: 0
97
+ };
98
+
99
+ const listener = (e) => {
100
+ window.__pasteTestResults.count++;
101
+ const text = e.clipboardData?.getData('text/plain') || '';
102
+ if (text.includes('TEST_SENDINPUT')) {
103
+ window.__pasteTestResults.sendInputEvent = true;
104
+ } else if (text.includes('TEST_CDP')) {
105
+ window.__pasteTestResults.cdp = true;
106
+ } else if (text.includes('TEST_JS')) {
107
+ window.__pasteTestResults.js = true;
108
+ }
109
+ };
110
+
111
+ document.removeEventListener('paste', listener);
112
+ document.addEventListener('paste', listener);
113
+ 'Listener installed';
114
+ `);
115
+
116
+ const results = [];
117
+
118
+ // Test 1: sendInputEvent
119
+ clipboard.writeText("TEST_SENDINPUT");
120
+ win.webContents.sendInputEvent({ type: "keyDown", keyCode: "V", modifiers: ["control"] });
121
+ win.webContents.sendInputEvent({ type: "char", keyCode: "V", modifiers: ["control"] });
122
+ win.webContents.sendInputEvent({ type: "keyUp", keyCode: "V", modifiers: ["control"] });
123
+ await new Promise((resolve) => setTimeout(resolve, 500));
124
+
125
+ // Test 2: CDP
126
+ clipboard.writeText("TEST_CDP");
127
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
128
+ type: "keyDown",
129
+ key: "v",
130
+ modifiers: 2,
131
+ });
132
+ await sendCDP(win.webContents, "Input.dispatchKeyEvent", {
133
+ type: "keyUp",
134
+ key: "v",
135
+ modifiers: 2,
136
+ });
137
+ await new Promise((resolve) => setTimeout(resolve, 500));
138
+
139
+ // Test 3: JS
140
+ clipboard.writeText("TEST_JS");
141
+ await win.webContents.executeJavaScript(`
142
+ const text = 'TEST_JS';
143
+ const dt = new DataTransfer();
144
+ dt.setData('text/plain', text);
145
+ const event = new ClipboardEvent('paste', {
146
+ clipboardData: dt,
147
+ bubbles: true,
148
+ cancelable: true
149
+ });
150
+ document.dispatchEvent(event);
151
+ `);
152
+ await new Promise((resolve) => setTimeout(resolve, 500));
153
+
154
+ // Get results
155
+ const testResults = await win.webContents.executeJavaScript("window.__pasteTestResults");
156
+
157
+ const report = [
158
+ `Paste events detected: ${testResults.count}`,
159
+ `✅ sendInputEvent: ${testResults.sendInputEvent ? "WORKS" : "FAILED"}`,
160
+ `${testResults.cdp ? "✅" : "❌"} CDP: ${testResults.cdp ? "WORKS" : "FAILED"}`,
161
+ `✅ JavaScript: ${testResults.js ? "WORKS" : "FAILED"}`,
162
+ "",
163
+ "Recommended method: " +
164
+ (testResults.sendInputEvent
165
+ ? "sendInputEvent"
166
+ : testResults.js
167
+ ? "js"
168
+ : "none working"),
169
+ ].join("\n");
170
+
171
+ return { content: [{ type: "text", text: report }] };
172
+ } catch (error) {
173
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
174
+ }
175
+ },
176
+ { tag: "Test" }
177
+ );
178
+ }
179
+
180
+ module.exports = registerTools;
@@ -0,0 +1,57 @@
1
+ const { z } = require("zod");
2
+ const downloadManager = require("../utils/download-manager");
3
+
4
+ module.exports = (registerTool) => {
5
+ // 获取下载列表
6
+ registerTool(
7
+ "get_downloads",
8
+ "获取所有下载记录",
9
+ z.object({}),
10
+ async () => {
11
+ try {
12
+ const downloads = downloadManager.getAllDownloads();
13
+ return { content: [{ type: "text", text: JSON.stringify(downloads, null, 2) }] };
14
+ } catch (error) {
15
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
16
+ }
17
+ },
18
+ { tag: "Network" }
19
+ );
20
+
21
+ // 获取单个下载信息
22
+ registerTool(
23
+ "get_download",
24
+ "获取指定下载的详细信息",
25
+ z.object({
26
+ id: z.number().describe("下载ID"),
27
+ }),
28
+ async ({ id }) => {
29
+ try {
30
+ const download = downloadManager.getDownload(id);
31
+ if (!download) {
32
+ return { content: [{ type: "text", text: `Download ${id} not found` }], isError: true };
33
+ }
34
+ return { content: [{ type: "text", text: JSON.stringify(download, null, 2) }] };
35
+ } catch (error) {
36
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
37
+ }
38
+ },
39
+ { tag: "Network" }
40
+ );
41
+
42
+ // 清空下载记录
43
+ registerTool(
44
+ "clear_downloads",
45
+ "清空所有下载记录",
46
+ z.object({}),
47
+ async () => {
48
+ try {
49
+ downloadManager.clearDownloads();
50
+ return { content: [{ type: "text", text: "All downloads cleared" }] };
51
+ } catch (error) {
52
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
53
+ }
54
+ },
55
+ { tag: "Network" }
56
+ );
57
+ };