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.
- package/.github/workflows/build.yml +85 -0
- package/.kiro/steering/dev-workflow.md +166 -0
- package/AGENTS.md +247 -0
- package/CLAUDE.md +162 -0
- package/DOCKER.md +85 -0
- package/Dockerfile +46 -0
- package/README.md +720 -0
- package/TODO-anti-detection.md +326 -0
- package/bin/cicy +176 -0
- package/bin/preinstall.sh +32 -0
- package/copy-to-desktop.sh +26 -0
- package/docs/AUTOMATION-API.md +342 -0
- package/docs/REQUEST_MONITORING.md +435 -0
- package/docs/REST-API-FEATURE.md +155 -0
- package/docs/REST-API.md +319 -0
- package/docs/feature-distributed-multi-agent.md +555 -0
- package/docs/yaml.md +255 -0
- package/electron-mcp-fixed.command +134 -0
- package/electron-mcp-simple.command +135 -0
- package/electron-mcp.command +92 -0
- package/generate-openapi.js +158 -0
- package/jest.config.js +10 -0
- package/jest.setup.global.js +13 -0
- package/jest.teardown.global.js +7 -0
- package/package.json +75 -0
- package/service.sh +164 -0
- package/src/config.js +8 -0
- package/src/extension/inject.js +135 -0
- package/src/main-old.js +837 -0
- package/src/main.js +403 -0
- package/src/preload-rpc.js +4 -0
- package/src/server/args-parser.js +37 -0
- package/src/server/electron-setup.js +33 -0
- package/src/server/express-app.js +166 -0
- package/src/server/logging.js +58 -0
- package/src/server/mcp-server.js +53 -0
- package/src/server/tool-registry.js +77 -0
- package/src/server/ui-routes.js +81 -0
- package/src/swagger-ui.html +41 -0
- package/src/tools/account-tools.js +194 -0
- package/src/tools/automation-tools.js +297 -0
- package/src/tools/cdp-tools.js +444 -0
- package/src/tools/clipboard-tools.js +180 -0
- package/src/tools/download-tools.js +57 -0
- package/src/tools/exec-js.js +297 -0
- package/src/tools/exec-tools.js +139 -0
- package/src/tools/file-tools.js +212 -0
- package/src/tools/hook-chatgpt.js +489 -0
- package/src/tools/hook-gemini.js +454 -0
- package/src/tools/index.js +19 -0
- package/src/tools/ipc-bridge.js +31 -0
- package/src/tools/ping.js +60 -0
- package/src/tools/r-reset.js +28 -0
- package/src/tools/screenshot-tools.js +28 -0
- package/src/tools/system-tools.js +531 -0
- package/src/tools/window-tools.js +882 -0
- package/src/ui.html +914 -0
- package/src/utils/auth.js +81 -0
- package/src/utils/cdp-utils.js +8 -0
- package/src/utils/download-manager.js +41 -0
- package/src/utils/process-utils.js +185 -0
- package/src/utils/snapshot-utils.js +56 -0
- package/src/utils/window-monitor.js +605 -0
- package/src/utils/window-state.js +137 -0
- package/src/utils/window-utils.js +336 -0
- package/update-desktop.sh +33 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# TODO: Anti-Detection & Reliability Enhancement
|
|
2
|
+
|
|
3
|
+
## 🎯 目标
|
|
4
|
+
增强 CDP 和模拟控制的可靠性,降低被检测风险,提高自动化成功率。
|
|
5
|
+
|
|
6
|
+
## 📋 任务清单
|
|
7
|
+
|
|
8
|
+
### Phase 1: 反检测基础 (1-2 天)
|
|
9
|
+
|
|
10
|
+
- [ ] **WebDriver 隐藏**
|
|
11
|
+
- [ ] 修改 `navigator.webdriver` 为 undefined
|
|
12
|
+
- [ ] 隐藏 `window.chrome.runtime`
|
|
13
|
+
- [ ] 修改 `navigator.plugins` 和 `navigator.languages`
|
|
14
|
+
- [ ] 测试工具:https://bot.sannysoft.com/
|
|
15
|
+
|
|
16
|
+
- [ ] **Canvas 指纹伪装**
|
|
17
|
+
- [ ] 随机化 Canvas 渲染结果
|
|
18
|
+
- [ ] 随机化 WebGL 指纹
|
|
19
|
+
- [ ] 随机化 AudioContext 指纹
|
|
20
|
+
- [ ] 测试工具:https://browserleaks.com/canvas
|
|
21
|
+
|
|
22
|
+
- [ ] **User-Agent 管理**
|
|
23
|
+
- [ ] 内置常见 UA 列表(Chrome/Firefox/Safari)
|
|
24
|
+
- [ ] 支持自定义 UA
|
|
25
|
+
- [ ] UA 与其他特征一致性检查
|
|
26
|
+
- [ ] 工具:`set_user_agent`
|
|
27
|
+
|
|
28
|
+
### Phase 2: 行为模拟 (2-3 天)
|
|
29
|
+
|
|
30
|
+
- [ ] **鼠标轨迹模拟**
|
|
31
|
+
- [ ] 贝塞尔曲线鼠标移动
|
|
32
|
+
- [ ] 随机速度和加速度
|
|
33
|
+
- [ ] 偶尔的抖动和停顿
|
|
34
|
+
- [ ] 工具:`cdp_move_mouse_human`
|
|
35
|
+
|
|
36
|
+
- [ ] **随机延迟**
|
|
37
|
+
- [ ] 操作间随机延迟(100-500ms)
|
|
38
|
+
- [ ] 页面加载等待(随机 1-3 秒)
|
|
39
|
+
- [ ] 输入速度随机化(50-150ms/字符)
|
|
40
|
+
- [ ] 工具:`cdp_type_text_human`
|
|
41
|
+
|
|
42
|
+
- [ ] **真人行为模拟**
|
|
43
|
+
- [ ] 随机滚动页面
|
|
44
|
+
- [ ] 偶尔移动鼠标到无关元素
|
|
45
|
+
- [ ] 随机点击空白区域
|
|
46
|
+
- [ ] 工具:`simulate_human_behavior`
|
|
47
|
+
|
|
48
|
+
### Phase 3: 混合控制模式 (2-3 天)
|
|
49
|
+
|
|
50
|
+
- [ ] **智能控制器**
|
|
51
|
+
- [ ] 自动选择 CDP 或系统级控制
|
|
52
|
+
- [ ] 根据检测风险动态切换
|
|
53
|
+
- [ ] 失败自动重试(切换方法)
|
|
54
|
+
- [ ] 工具:`hybrid_click`, `hybrid_type`
|
|
55
|
+
|
|
56
|
+
- [ ] **元素定位增强**
|
|
57
|
+
- [ ] CDP 选择器定位(优先)
|
|
58
|
+
- [ ] 图像识别定位(备用)
|
|
59
|
+
- [ ] OCR 文字定位(备用)
|
|
60
|
+
- [ ] 工具:`find_element_smart`
|
|
61
|
+
|
|
62
|
+
- [ ] **操作验证**
|
|
63
|
+
- [ ] 点击后验证元素状态
|
|
64
|
+
- [ ] 输入后验证文本内容
|
|
65
|
+
- [ ] 截图对比验证
|
|
66
|
+
- [ ] 工具:`verify_action`
|
|
67
|
+
|
|
68
|
+
### Phase 4: 图像识别集成 (3-4 天)
|
|
69
|
+
|
|
70
|
+
- [ ] **OCR 文字识别**
|
|
71
|
+
- [ ] 安装 Tesseract
|
|
72
|
+
- [ ] 封装 OCR 工具
|
|
73
|
+
- [ ] 支持中英文识别
|
|
74
|
+
- [ ] 工具:`ocr_find_text`, `ocr_read_screen`
|
|
75
|
+
|
|
76
|
+
- [ ] **模板匹配**
|
|
77
|
+
- [ ] 安装 OpenCV (opencv4nodejs)
|
|
78
|
+
- [ ] 模板图片管理
|
|
79
|
+
- [ ] 相似度阈值配置
|
|
80
|
+
- [ ] 工具:`find_image`, `wait_for_image`
|
|
81
|
+
|
|
82
|
+
- [ ] **颜色检测**
|
|
83
|
+
- [ ] 按颜色查找元素
|
|
84
|
+
- [ ] 颜色变化监控
|
|
85
|
+
- [ ] 工具:`find_by_color`
|
|
86
|
+
|
|
87
|
+
- [ ] **UI 元素识别**
|
|
88
|
+
- [ ] 按钮识别(形状+文字)
|
|
89
|
+
- [ ] 输入框识别
|
|
90
|
+
- [ ] 图标识别
|
|
91
|
+
- [ ] 工具:`detect_ui_elements`
|
|
92
|
+
|
|
93
|
+
### Phase 5: 可靠性测试 (2-3 天)
|
|
94
|
+
|
|
95
|
+
- [ ] **反爬虫测试**
|
|
96
|
+
- [ ] 测试常见反爬虫网站
|
|
97
|
+
- [ ] Cloudflare Challenge
|
|
98
|
+
- [ ] reCAPTCHA 检测
|
|
99
|
+
- [ ] 记录检测率
|
|
100
|
+
|
|
101
|
+
- [ ] **成功率统计**
|
|
102
|
+
- [ ] 操作成功率监控
|
|
103
|
+
- [ ] 失败原因分析
|
|
104
|
+
- [ ] 性能指标收集
|
|
105
|
+
- [ ] Dashboard 展示
|
|
106
|
+
|
|
107
|
+
- [ ] **压力测试**
|
|
108
|
+
- [ ] 并发 10+ Agent 测试
|
|
109
|
+
- [ ] 长时间运行稳定性
|
|
110
|
+
- [ ] 内存泄漏检测
|
|
111
|
+
- [ ] 资源使用监控
|
|
112
|
+
|
|
113
|
+
### Phase 6: 文档和示例 (1-2 天)
|
|
114
|
+
|
|
115
|
+
- [ ] **使用文档**
|
|
116
|
+
- [ ] 反检测最佳实践
|
|
117
|
+
- [ ] 混合控制模式说明
|
|
118
|
+
- [ ] 图像识别使用指南
|
|
119
|
+
- [ ] 常见问题解答
|
|
120
|
+
|
|
121
|
+
- [ ] **示例代码**
|
|
122
|
+
- [ ] 反检测配置示例
|
|
123
|
+
- [ ] 复杂场景自动化示例
|
|
124
|
+
- [ ] 图像识别示例
|
|
125
|
+
- [ ] 错误处理示例
|
|
126
|
+
|
|
127
|
+
- [ ] **测试用例**
|
|
128
|
+
- [ ] 单元测试
|
|
129
|
+
- [ ] 集成测试
|
|
130
|
+
- [ ] E2E 测试
|
|
131
|
+
|
|
132
|
+
## 🛠️ 新增工具列表
|
|
133
|
+
|
|
134
|
+
### 反检测工具
|
|
135
|
+
```javascript
|
|
136
|
+
// 配置反检测
|
|
137
|
+
set_anti_detect({
|
|
138
|
+
hideWebdriver: true,
|
|
139
|
+
randomCanvas: true,
|
|
140
|
+
randomUA: true
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// 设置 User-Agent
|
|
144
|
+
set_user_agent({
|
|
145
|
+
win_id: 1,
|
|
146
|
+
userAgent: "Mozilla/5.0 ..."
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// 注入反检测脚本
|
|
150
|
+
inject_stealth_scripts({ win_id: 1 })
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 行为模拟工具
|
|
154
|
+
```javascript
|
|
155
|
+
// 人类化鼠标移动
|
|
156
|
+
cdp_move_mouse_human({
|
|
157
|
+
win_id: 1,
|
|
158
|
+
x: 500,
|
|
159
|
+
y: 300,
|
|
160
|
+
duration: 1000 // 移动时间
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// 人类化输入
|
|
164
|
+
cdp_type_text_human({
|
|
165
|
+
win_id: 1,
|
|
166
|
+
text: "Hello",
|
|
167
|
+
minDelay: 50,
|
|
168
|
+
maxDelay: 150
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// 模拟真人行为
|
|
172
|
+
simulate_human_behavior({
|
|
173
|
+
win_id: 1,
|
|
174
|
+
duration: 5000, // 持续 5 秒
|
|
175
|
+
actions: ["scroll", "move", "pause"]
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 混合控制工具
|
|
180
|
+
```javascript
|
|
181
|
+
// 智能点击(自动选择方法)
|
|
182
|
+
hybrid_click({
|
|
183
|
+
win_id: 1,
|
|
184
|
+
selector: "button.submit", // 优先 CDP
|
|
185
|
+
fallback: "image", // 失败时用图像
|
|
186
|
+
antiDetect: true
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// 智能输入
|
|
190
|
+
hybrid_type({
|
|
191
|
+
win_id: 1,
|
|
192
|
+
selector: "input#username",
|
|
193
|
+
text: "user123",
|
|
194
|
+
method: "auto" // auto/cdp/system
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// 智能元素查找
|
|
198
|
+
find_element_smart({
|
|
199
|
+
win_id: 1,
|
|
200
|
+
selector: "button", // CSS 选择器
|
|
201
|
+
text: "登录", // OCR 文字
|
|
202
|
+
image: "login_button.png", // 模板图片
|
|
203
|
+
color: "#FF0000" // 颜色
|
|
204
|
+
})
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 图像识别工具
|
|
208
|
+
```javascript
|
|
209
|
+
// OCR 文字识别
|
|
210
|
+
ocr_find_text({
|
|
211
|
+
win_id: 1,
|
|
212
|
+
text: "登录",
|
|
213
|
+
lang: "chi_sim+eng"
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
// 读取屏幕文字
|
|
217
|
+
ocr_read_screen({
|
|
218
|
+
win_id: 1,
|
|
219
|
+
region: { x: 0, y: 0, width: 800, height: 600 }
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// 图像模板匹配
|
|
223
|
+
find_image({
|
|
224
|
+
win_id: 1,
|
|
225
|
+
template: "button.png",
|
|
226
|
+
threshold: 0.8
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
// 等待图像出现
|
|
230
|
+
wait_for_image({
|
|
231
|
+
win_id: 1,
|
|
232
|
+
template: "success.png",
|
|
233
|
+
timeout: 10000
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// 按颜色查找
|
|
237
|
+
find_by_color({
|
|
238
|
+
win_id: 1,
|
|
239
|
+
color: "#FF0000",
|
|
240
|
+
tolerance: 10
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
// UI 元素检测
|
|
244
|
+
detect_ui_elements({
|
|
245
|
+
win_id: 1,
|
|
246
|
+
types: ["button", "input", "icon"]
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 验证工具
|
|
251
|
+
```javascript
|
|
252
|
+
// 验证操作结果
|
|
253
|
+
verify_action({
|
|
254
|
+
win_id: 1,
|
|
255
|
+
action: "click",
|
|
256
|
+
selector: "button",
|
|
257
|
+
expect: {
|
|
258
|
+
urlChange: true,
|
|
259
|
+
elementVisible: ".success"
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// 截图对比
|
|
264
|
+
compare_screenshots({
|
|
265
|
+
win_id: 1,
|
|
266
|
+
before: "before.png",
|
|
267
|
+
after: "after.png",
|
|
268
|
+
threshold: 0.95
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## 📊 验收标准
|
|
273
|
+
|
|
274
|
+
### 反检测效果
|
|
275
|
+
- [ ] bot.sannysoft.com 检测通过率 > 90%
|
|
276
|
+
- [ ] browserleaks.com 指纹随机化成功
|
|
277
|
+
- [ ] Cloudflare Challenge 通过率 > 80%
|
|
278
|
+
|
|
279
|
+
### 可靠性指标
|
|
280
|
+
- [ ] 操作成功率 > 95%
|
|
281
|
+
- [ ] 图像识别准确率 > 90%
|
|
282
|
+
- [ ] OCR 识别准确率 > 85%
|
|
283
|
+
|
|
284
|
+
### 性能指标
|
|
285
|
+
- [ ] 人类化操作延迟 < 2 秒
|
|
286
|
+
- [ ] 图像识别响应 < 1 秒
|
|
287
|
+
- [ ] OCR 识别响应 < 500ms
|
|
288
|
+
|
|
289
|
+
## 🔗 参考资料
|
|
290
|
+
|
|
291
|
+
### 反检测
|
|
292
|
+
- [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth)
|
|
293
|
+
- [undetected-chromedriver](https://github.com/ultrafunkamsterdam/undetected-chromedriver)
|
|
294
|
+
- [Bot Detection Tests](https://bot.sannysoft.com/)
|
|
295
|
+
|
|
296
|
+
### 图像识别
|
|
297
|
+
- [Tesseract.js](https://github.com/naptha/tesseract.js)
|
|
298
|
+
- [opencv4nodejs](https://github.com/justadudewhohacks/opencv4nodejs)
|
|
299
|
+
- [node-tesseract-ocr](https://github.com/zapolnoch/node-tesseract-ocr)
|
|
300
|
+
|
|
301
|
+
### 行为模拟
|
|
302
|
+
- [ghost-cursor](https://github.com/Xetera/ghost-cursor)
|
|
303
|
+
- [humanize](https://github.com/HubSpot/humanize)
|
|
304
|
+
|
|
305
|
+
## 📝 实施优先级
|
|
306
|
+
|
|
307
|
+
### P0 (必须完成)
|
|
308
|
+
1. WebDriver 隐藏
|
|
309
|
+
2. 基础行为随机化
|
|
310
|
+
3. 混合控制模式
|
|
311
|
+
|
|
312
|
+
### P1 (重要)
|
|
313
|
+
4. Canvas 指纹伪装
|
|
314
|
+
5. OCR 文字识别
|
|
315
|
+
6. 反爬虫测试
|
|
316
|
+
|
|
317
|
+
### P2 (可选)
|
|
318
|
+
7. 模板匹配
|
|
319
|
+
8. UI 元素识别
|
|
320
|
+
9. 完整文档
|
|
321
|
+
|
|
322
|
+
## 🚀 开始时间
|
|
323
|
+
待确认
|
|
324
|
+
|
|
325
|
+
## ✅ 完成时间
|
|
326
|
+
预计 2-3 周
|
package/bin/cicy
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawn, execSync } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const HOME = os.homedir();
|
|
8
|
+
const PID_FILE = path.join(HOME, '.cicy.pid');
|
|
9
|
+
const LOG_FILE = path.join(HOME, 'logs', 'cicy.log');
|
|
10
|
+
const PACKAGE_ROOT = path.join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
let command = 'start';
|
|
15
|
+
let useCNMirror = false;
|
|
16
|
+
let runUpdate = false;
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < args.length; i++) {
|
|
19
|
+
const arg = args[i];
|
|
20
|
+
if (arg === '-h' || arg === '--help') {
|
|
21
|
+
showHelp();
|
|
22
|
+
process.exit(0);
|
|
23
|
+
} else if (arg === '-cn' || arg === '--cn') {
|
|
24
|
+
useCNMirror = true;
|
|
25
|
+
} else if (arg === '-u' || arg === '--update') {
|
|
26
|
+
runUpdate = true;
|
|
27
|
+
} else if (!arg.startsWith('-')) {
|
|
28
|
+
command = arg;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (useCNMirror) {
|
|
33
|
+
try {
|
|
34
|
+
execSync('npm config set registry https://registry.npmmirror.com', { stdio: 'inherit' });
|
|
35
|
+
console.log('📦 Using CN npm mirror: https://registry.npmmirror.com');
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error('❌ Failed to set npm mirror:', err.message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (runUpdate) {
|
|
42
|
+
update();
|
|
43
|
+
} else {
|
|
44
|
+
executeCommand(command);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function showHelp() {
|
|
48
|
+
console.log(`cicy - Electron MCP Controller
|
|
49
|
+
|
|
50
|
+
Usage: cicy [command] [options]
|
|
51
|
+
|
|
52
|
+
Commands:
|
|
53
|
+
start Start cicy (default)
|
|
54
|
+
stop Stop cicy
|
|
55
|
+
status Check cicy status
|
|
56
|
+
restart Restart cicy
|
|
57
|
+
logs View logs (tail -f)
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
-h, --help Show this help message
|
|
61
|
+
-cn Use CN npm mirror
|
|
62
|
+
-u, --update Update cicy to latest version
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
cicy start
|
|
66
|
+
cicy -cn start
|
|
67
|
+
cicy -u
|
|
68
|
+
cicy -cn -u`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function update() {
|
|
72
|
+
console.log('🔄 Updating cicy...');
|
|
73
|
+
try {
|
|
74
|
+
execSync('git pull', { cwd: PACKAGE_ROOT, stdio: 'inherit' });
|
|
75
|
+
execSync('npm install', { cwd: PACKAGE_ROOT, stdio: 'inherit' });
|
|
76
|
+
console.log('✅ cicy updated successfully');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error('❌ Update failed:', err.message);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function executeCommand(cmd) {
|
|
84
|
+
switch (cmd) {
|
|
85
|
+
case 'start': start(); break;
|
|
86
|
+
case 'stop': stop(); break;
|
|
87
|
+
case 'status': status(); break;
|
|
88
|
+
case 'restart': restart(); break;
|
|
89
|
+
case 'logs': logs(); break;
|
|
90
|
+
default:
|
|
91
|
+
console.log(`Unknown command: ${cmd}`);
|
|
92
|
+
console.log('Usage: cicy <start|stop|status|restart|logs>');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getPid() {
|
|
98
|
+
try {
|
|
99
|
+
return fs.readFileSync(PID_FILE, 'utf8').trim();
|
|
100
|
+
} catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isRunning(pid) {
|
|
106
|
+
if (!pid) return false;
|
|
107
|
+
try {
|
|
108
|
+
process.kill(pid, 0);
|
|
109
|
+
return true;
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function start() {
|
|
116
|
+
const pid = getPid();
|
|
117
|
+
if (pid && isRunning(pid)) {
|
|
118
|
+
console.log(`✅ cicy is already running (PID: ${pid})`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fs.mkdirSync(path.dirname(LOG_FILE), { recursive: true });
|
|
123
|
+
|
|
124
|
+
const child = spawn('electron', [PACKAGE_ROOT], {
|
|
125
|
+
detached: true,
|
|
126
|
+
stdio: ['ignore', fs.openSync(LOG_FILE, 'a'), fs.openSync(LOG_FILE, 'a')],
|
|
127
|
+
env: { ...process.env, PORT: process.env.PORT || '8101' }
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
child.unref();
|
|
131
|
+
fs.writeFileSync(PID_FILE, child.pid.toString());
|
|
132
|
+
|
|
133
|
+
console.log(`✅ cicy started (PID: ${child.pid})`);
|
|
134
|
+
console.log(`📝 Logs: ${LOG_FILE}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function stop() {
|
|
138
|
+
const pid = getPid();
|
|
139
|
+
if (!pid || !isRunning(pid)) {
|
|
140
|
+
console.log('❌ cicy is not running');
|
|
141
|
+
fs.existsSync(PID_FILE) && fs.unlinkSync(PID_FILE);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
process.kill(pid, 'SIGTERM');
|
|
147
|
+
fs.unlinkSync(PID_FILE);
|
|
148
|
+
console.log(`✅ cicy stopped (PID: ${pid})`);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.error(`❌ Failed to stop: ${err.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function status() {
|
|
155
|
+
const pid = getPid();
|
|
156
|
+
if (pid && isRunning(pid)) {
|
|
157
|
+
console.log(`✅ cicy is running (PID: ${pid})`);
|
|
158
|
+
console.log(`📝 Logs: ${LOG_FILE}`);
|
|
159
|
+
} else {
|
|
160
|
+
console.log('❌ cicy is not running');
|
|
161
|
+
fs.existsSync(PID_FILE) && fs.unlinkSync(PID_FILE);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function restart() {
|
|
166
|
+
stop();
|
|
167
|
+
setTimeout(start, 1000);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function logs() {
|
|
171
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
172
|
+
console.log('❌ No logs found');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
execSync(`tail -f ${LOG_FILE}`, { stdio: 'inherit' });
|
|
176
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
echo "Installing electron globally..."
|
|
6
|
+
|
|
7
|
+
if [ "$(uname)" = "Linux" ]; then
|
|
8
|
+
sudo npm install -g electron
|
|
9
|
+
else
|
|
10
|
+
npm install -g electron
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [ "$(uname)" = "Linux" ]; then
|
|
14
|
+
echo "Fixing chrome-sandbox permissions on Linux..."
|
|
15
|
+
ELECTRON_PATH=$(which electron)
|
|
16
|
+
ELECTRON_DIR=$(dirname "$ELECTRON_PATH")
|
|
17
|
+
SANDBOX_PATH="$ELECTRON_DIR/../lib/node_modules/electron/dist/chrome-sandbox"
|
|
18
|
+
|
|
19
|
+
if [ -f "$SANDBOX_PATH" ]; then
|
|
20
|
+
if command -v sudo &> /dev/null; then
|
|
21
|
+
sudo chown root:root "$SANDBOX_PATH"
|
|
22
|
+
sudo chmod 4755 "$SANDBOX_PATH"
|
|
23
|
+
echo "chrome-sandbox permissions fixed"
|
|
24
|
+
else
|
|
25
|
+
echo "Warning: sudo not available, skipping chrome-sandbox permissions"
|
|
26
|
+
fi
|
|
27
|
+
else
|
|
28
|
+
echo "Warning: chrome-sandbox not found at $SANDBOX_PATH"
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
echo "Electron setup complete"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 复制修复后的启动脚本到桌面
|
|
4
|
+
|
|
5
|
+
DESKTOP_PATH="$HOME/Desktop"
|
|
6
|
+
SOURCE_FILE="./electron-mcp-fixed.command"
|
|
7
|
+
TARGET_FILE="$DESKTOP_PATH/electron-mcp.command"
|
|
8
|
+
|
|
9
|
+
echo "正在复制修复后的启动脚本到桌面..."
|
|
10
|
+
|
|
11
|
+
# 备份原文件(如果存在)
|
|
12
|
+
if [ -f "$TARGET_FILE" ]; then
|
|
13
|
+
echo "备份原文件为 electron-mcp.command.backup"
|
|
14
|
+
cp "$TARGET_FILE" "$TARGET_FILE.backup"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# 复制新文件
|
|
18
|
+
cp "$SOURCE_FILE" "$TARGET_FILE"
|
|
19
|
+
|
|
20
|
+
# 设置执行权限
|
|
21
|
+
chmod +x "$TARGET_FILE"
|
|
22
|
+
|
|
23
|
+
echo "✅ 复制完成!"
|
|
24
|
+
echo "📁 文件位置: $TARGET_FILE"
|
|
25
|
+
echo ""
|
|
26
|
+
echo "现在你可以双击桌面上的 electron-mcp.command 文件来启动服务了!"
|