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,297 @@
1
+ const { BrowserWindow } = require("electron");
2
+ const { z } = require("zod");
3
+
4
+ function registerTools(registerTool) {
5
+ // 点击元素
6
+ registerTool(
7
+ "electron_click",
8
+ "点击页面上的元素(通过CSS选择器)",
9
+ z.object({
10
+ win_id: z.number().optional().default(1).describe("窗口ID"),
11
+ selector: z.string().describe("CSS选择器,例如:button[aria-label='close']"),
12
+ waitTimeout: z.number().optional().default(5000).describe("等待元素出现的超时时间(毫秒)"),
13
+ }),
14
+ async ({ win_id, selector, waitTimeout }) => {
15
+ try {
16
+ const win = BrowserWindow.fromId(win_id);
17
+ if (!win) throw new Error(`Window ${win_id} not found`);
18
+
19
+ const result = await win.webContents.executeJavaScript(`
20
+ (async () => {
21
+ const selector = ${JSON.stringify(selector)};
22
+ const timeout = ${waitTimeout};
23
+ const startTime = Date.now();
24
+
25
+ while (Date.now() - startTime < timeout) {
26
+ const element = document.querySelector(selector);
27
+ if (element) {
28
+ element.click();
29
+ return { success: true, message: 'Element clicked' };
30
+ }
31
+ await new Promise(resolve => setTimeout(resolve, 100));
32
+ }
33
+
34
+ throw new Error('Element not found: ' + selector);
35
+ })()
36
+ `);
37
+
38
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
39
+ } catch (error) {
40
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
41
+ }
42
+ },
43
+ { tag: "Automation" }
44
+ );
45
+
46
+ // 输入文字
47
+ registerTool(
48
+ "electron_type",
49
+ "在页面元素中输入文字(通过CSS选择器)",
50
+ z.object({
51
+ win_id: z.number().optional().default(1).describe("窗口ID"),
52
+ selector: z.string().describe("CSS选择器,例如:input[name='username']"),
53
+ text: z.string().describe("要输入的文字"),
54
+ clear: z.boolean().optional().default(true).describe("输入前是否清空原有内容"),
55
+ waitTimeout: z.number().optional().default(5000).describe("等待元素出现的超时时间(毫秒)"),
56
+ }),
57
+ async ({ win_id, selector, text, clear, waitTimeout }) => {
58
+ try {
59
+ const win = BrowserWindow.fromId(win_id);
60
+ if (!win) throw new Error(`Window ${win_id} not found`);
61
+
62
+ const result = await win.webContents.executeJavaScript(`
63
+ (async () => {
64
+ const selector = ${JSON.stringify(selector)};
65
+ const text = ${JSON.stringify(text)};
66
+ const clear = ${clear};
67
+ const timeout = ${waitTimeout};
68
+ const startTime = Date.now();
69
+
70
+ while (Date.now() - startTime < timeout) {
71
+ const element = document.querySelector(selector);
72
+ if (element) {
73
+ if (clear) element.value = '';
74
+ element.value = text;
75
+ element.dispatchEvent(new Event('input', { bubbles: true }));
76
+ element.dispatchEvent(new Event('change', { bubbles: true }));
77
+ return { success: true, message: 'Text typed' };
78
+ }
79
+ await new Promise(resolve => setTimeout(resolve, 100));
80
+ }
81
+
82
+ throw new Error('Element not found: ' + selector);
83
+ })()
84
+ `);
85
+
86
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
87
+ } catch (error) {
88
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
89
+ }
90
+ },
91
+ { tag: "Automation" }
92
+ );
93
+
94
+ // 获取页面内容
95
+ registerTool(
96
+ "electron_get_content",
97
+ "获取页面的HTML内容或文本内容",
98
+ z.object({
99
+ win_id: z.number().optional().default(1).describe("窗口ID"),
100
+ selector: z.string().optional().describe("CSS选择器,不指定则获取整个页面"),
101
+ type: z.enum(["html", "text"]).optional().default("text").describe("返回类型:html或text"),
102
+ }),
103
+ async ({ win_id, selector, type }) => {
104
+ try {
105
+ const win = BrowserWindow.fromId(win_id);
106
+ if (!win) throw new Error(`Window ${win_id} not found`);
107
+
108
+ const result = await win.webContents.executeJavaScript(`
109
+ (() => {
110
+ const selector = ${JSON.stringify(selector)};
111
+ const type = ${JSON.stringify(type)};
112
+
113
+ const element = selector ? document.querySelector(selector) : document.body;
114
+ if (!element) throw new Error('Element not found: ' + selector);
115
+
116
+ return type === 'html' ? element.innerHTML : element.innerText;
117
+ })()
118
+ `);
119
+
120
+ return { content: [{ type: "text", text: result }] };
121
+ } catch (error) {
122
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
123
+ }
124
+ },
125
+ { tag: "Automation" }
126
+ );
127
+
128
+ // 窗口截图
129
+ registerTool(
130
+ "electron_screenshot",
131
+ "截取窗口的屏幕截图",
132
+ z.object({
133
+ win_id: z.number().optional().default(1).describe("窗口ID"),
134
+ format: z.enum(["png", "jpeg"]).optional().default("png").describe("图片格式"),
135
+ }),
136
+ async ({ win_id, format }) => {
137
+ try {
138
+ const win = BrowserWindow.fromId(win_id);
139
+ if (!win) throw new Error(`Window ${win_id} not found`);
140
+
141
+ const image = await win.webContents.capturePage();
142
+ const buffer = format === "png" ? image.toPNG() : image.toJPEG(80);
143
+ const base64 = buffer.toString("base64");
144
+
145
+ return {
146
+ content: [
147
+ {
148
+ type: "text",
149
+ text: JSON.stringify({
150
+ format,
151
+ size: buffer.length,
152
+ base64: `data:image/${format};base64,${base64}`,
153
+ }),
154
+ },
155
+ ],
156
+ };
157
+ } catch (error) {
158
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
159
+ }
160
+ },
161
+ { tag: "Automation" }
162
+ );
163
+
164
+ // 等待元素
165
+ registerTool(
166
+ "electron_wait_for",
167
+ "等待页面元素出现",
168
+ z.object({
169
+ win_id: z.number().optional().default(1).describe("窗口ID"),
170
+ selector: z.string().describe("CSS选择器"),
171
+ timeout: z.number().optional().default(10000).describe("超时时间(毫秒)"),
172
+ }),
173
+ async ({ win_id, selector, timeout }) => {
174
+ try {
175
+ const win = BrowserWindow.fromId(win_id);
176
+ if (!win) throw new Error(`Window ${win_id} not found`);
177
+
178
+ const result = await win.webContents.executeJavaScript(`
179
+ (async () => {
180
+ const selector = ${JSON.stringify(selector)};
181
+ const timeout = ${timeout};
182
+ const startTime = Date.now();
183
+
184
+ while (Date.now() - startTime < timeout) {
185
+ const element = document.querySelector(selector);
186
+ if (element) {
187
+ return { success: true, message: 'Element found', selector };
188
+ }
189
+ await new Promise(resolve => setTimeout(resolve, 100));
190
+ }
191
+
192
+ throw new Error('Timeout waiting for element: ' + selector);
193
+ })()
194
+ `);
195
+
196
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
197
+ } catch (error) {
198
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
199
+ }
200
+ },
201
+ { tag: "Automation" }
202
+ );
203
+
204
+ // 执行JavaScript并返回结果
205
+ registerTool(
206
+ "electron_evaluate",
207
+ "在页面中执行JavaScript代码并返回结果",
208
+ z.object({
209
+ win_id: z.number().optional().default(1).describe("窗口ID"),
210
+ code: z.string().describe("要执行的JavaScript代码"),
211
+ }),
212
+ async ({ win_id, code }) => {
213
+ try {
214
+ const win = BrowserWindow.fromId(win_id);
215
+ if (!win) throw new Error(`Window ${win_id} not found`);
216
+
217
+ const result = await win.webContents.executeJavaScript(code);
218
+
219
+ return {
220
+ content: [
221
+ {
222
+ type: "text",
223
+ text: typeof result === "string" ? result : JSON.stringify(result, null, 2),
224
+ },
225
+ ],
226
+ };
227
+ } catch (error) {
228
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
229
+ }
230
+ },
231
+ { tag: "Automation" }
232
+ );
233
+
234
+ // 获取元素属性
235
+ registerTool(
236
+ "electron_get_attribute",
237
+ "获取页面元素的属性值",
238
+ z.object({
239
+ win_id: z.number().optional().default(1).describe("窗口ID"),
240
+ selector: z.string().describe("CSS选择器"),
241
+ attribute: z.string().describe("属性名,例如:href, src, value, class"),
242
+ }),
243
+ async ({ win_id, selector, attribute }) => {
244
+ try {
245
+ const win = BrowserWindow.fromId(win_id);
246
+ if (!win) throw new Error(`Window ${win_id} not found`);
247
+
248
+ const result = await win.webContents.executeJavaScript(`
249
+ (() => {
250
+ const element = document.querySelector(${JSON.stringify(selector)});
251
+ if (!element) throw new Error('Element not found: ' + ${JSON.stringify(selector)});
252
+ return element.getAttribute(${JSON.stringify(attribute)});
253
+ })()
254
+ `);
255
+
256
+ return { content: [{ type: "text", text: result || "" }] };
257
+ } catch (error) {
258
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
259
+ }
260
+ },
261
+ { tag: "Automation" }
262
+ );
263
+
264
+ // 选择下拉框选项
265
+ registerTool(
266
+ "electron_select",
267
+ "选择下拉框(select)的选项",
268
+ z.object({
269
+ win_id: z.number().optional().default(1).describe("窗口ID"),
270
+ selector: z.string().describe("select元素的CSS选择器"),
271
+ value: z.string().describe("要选择的option的value值"),
272
+ }),
273
+ async ({ win_id, selector, value }) => {
274
+ try {
275
+ const win = BrowserWindow.fromId(win_id);
276
+ if (!win) throw new Error(`Window ${win_id} not found`);
277
+
278
+ const result = await win.webContents.executeJavaScript(`
279
+ (() => {
280
+ const element = document.querySelector(${JSON.stringify(selector)});
281
+ if (!element) throw new Error('Element not found: ' + ${JSON.stringify(selector)});
282
+ element.value = ${JSON.stringify(value)};
283
+ element.dispatchEvent(new Event('change', { bubbles: true }));
284
+ return { success: true, message: 'Option selected' };
285
+ })()
286
+ `);
287
+
288
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
289
+ } catch (error) {
290
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
291
+ }
292
+ },
293
+ { tag: "Automation" }
294
+ );
295
+ }
296
+
297
+ module.exports = registerTools;