myagent-ai 1.3.1 → 1.3.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.
- package/core/version.py +1 -1
- package/install/install.ps1 +1 -1
- package/install/install.sh +1 -1
- package/package.json +3 -2
- package/requirements.txt +19 -41
- package/setup.py +1 -1
- package/start.js +361 -0
package/core/version.py
CHANGED
package/install/install.ps1
CHANGED
package/install/install.sh
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myagent-ai",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
|
|
5
5
|
"main": "main.py",
|
|
6
6
|
"bin": {
|
|
7
|
-
"myagent-ai": "start.
|
|
7
|
+
"myagent-ai": "start.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "python main.py",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"config.py",
|
|
49
49
|
"setup.py",
|
|
50
50
|
"requirements.txt",
|
|
51
|
+
"start.js",
|
|
51
52
|
"start.sh",
|
|
52
53
|
"install/",
|
|
53
54
|
"docs/",
|
package/requirements.txt
CHANGED
|
@@ -4,76 +4,54 @@
|
|
|
4
4
|
# ============================================================
|
|
5
5
|
# 核心依赖 (必需)
|
|
6
6
|
# ============================================================
|
|
7
|
-
openai>=1.12.0
|
|
8
|
-
aiohttp>=3.9.0
|
|
9
|
-
requests>=2.31.0
|
|
10
|
-
|
|
11
|
-
# ============================================================
|
|
12
|
-
# Web 管理后台
|
|
13
|
-
# ============================================================
|
|
14
|
-
# Web 服务器使用 aiohttp,无额外依赖
|
|
15
|
-
# aiohttp 已在核心依赖中
|
|
16
|
-
|
|
17
|
-
# ============================================================
|
|
18
|
-
# 记忆系统
|
|
19
|
-
# ============================================================
|
|
20
|
-
# SQLite3 为 Python 内置模块,无需额外安装
|
|
21
|
-
|
|
22
|
-
# ============================================================
|
|
23
|
-
# 执行引擎
|
|
24
|
-
# ============================================================
|
|
25
|
-
# subprocess, tempfile 为 Python 内置模块
|
|
7
|
+
openai>=1.12.0
|
|
8
|
+
aiohttp>=3.9.0
|
|
9
|
+
requests>=2.31.0
|
|
26
10
|
|
|
27
11
|
# ============================================================
|
|
28
12
|
# 技能系统 - 搜索
|
|
29
13
|
# ============================================================
|
|
30
|
-
duckduckgo-search>=6.0.0
|
|
31
|
-
beautifulsoup4>=4.12.0
|
|
32
|
-
lxml>=5.0.0
|
|
33
|
-
psutil>=5.9.0
|
|
14
|
+
duckduckgo-search>=6.0.0
|
|
15
|
+
beautifulsoup4>=4.12.0
|
|
16
|
+
lxml>=5.0.0
|
|
17
|
+
psutil>=5.9.0
|
|
34
18
|
|
|
35
19
|
# ============================================================
|
|
36
20
|
# 技能系统 - 浏览器自动化 (Playwright)
|
|
37
21
|
# ============================================================
|
|
38
|
-
playwright>=1.41.0
|
|
22
|
+
playwright>=1.41.0
|
|
39
23
|
|
|
40
24
|
# ============================================================
|
|
41
25
|
# 技能系统 - 桌面 GUI 自动化
|
|
42
26
|
# ============================================================
|
|
43
|
-
pynput>=1.7.6
|
|
44
|
-
pygetwindow>=0.0.9
|
|
45
|
-
mss>=9.0.0
|
|
27
|
+
pynput>=1.7.6
|
|
28
|
+
pygetwindow>=0.0.9
|
|
29
|
+
mss>=9.0.0
|
|
46
30
|
|
|
47
31
|
# ============================================================
|
|
48
32
|
# 系统托盘 (默认启用)
|
|
49
33
|
# ============================================================
|
|
50
|
-
pystray>=0.19.5
|
|
51
|
-
Pillow>=10.0.0
|
|
34
|
+
pystray>=0.19.5
|
|
35
|
+
Pillow>=10.0.0
|
|
52
36
|
|
|
53
37
|
# ============================================================
|
|
54
38
|
# 聊天平台 (按需使用,默认安装)
|
|
55
39
|
# ============================================================
|
|
56
|
-
python-telegram-bot>=21.0
|
|
57
|
-
discord.py>=2.3.0
|
|
58
|
-
# 飞书/QQ/微信 通过 aiohttp 实现,无需额外安装
|
|
40
|
+
python-telegram-bot>=21.0
|
|
41
|
+
discord.py>=2.3.0
|
|
59
42
|
|
|
60
43
|
# ============================================================
|
|
61
44
|
# 语音合成 (默认启用)
|
|
62
45
|
# ============================================================
|
|
63
|
-
edge-tts>=6.1.0
|
|
46
|
+
edge-tts>=6.1.0
|
|
64
47
|
|
|
65
48
|
# ============================================================
|
|
66
49
|
# Anthropic Claude (可选)
|
|
67
50
|
# ============================================================
|
|
68
|
-
anthropic>=0.18.0
|
|
51
|
+
anthropic>=0.18.0
|
|
69
52
|
|
|
70
53
|
# ============================================================
|
|
71
54
|
# Agent 间通信 (可选)
|
|
72
55
|
# ============================================================
|
|
73
|
-
cryptography>=41.0.0
|
|
74
|
-
websockets>=12.0
|
|
75
|
-
|
|
76
|
-
# ============================================================
|
|
77
|
-
# 打包 (可选, 仅开发用)
|
|
78
|
-
# ============================================================
|
|
79
|
-
# pyinstaller>=6.0.0 # 打包为 exe/app (按需安装)
|
|
56
|
+
cryptography>=41.0.0
|
|
57
|
+
websockets>=12.0
|
package/setup.py
CHANGED
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
_version_path = Path(__file__).parent / "core" / "version.py"
|
|
10
10
|
_version_vars = {}
|
|
11
11
|
exec(_version_path.read_text(), _version_vars)
|
|
12
|
-
__version__ = _version_vars.get("BASE_VERSION", "1.3.
|
|
12
|
+
__version__ = _version_vars.get("BASE_VERSION", "1.3.3")
|
|
13
13
|
|
|
14
14
|
setup(
|
|
15
15
|
name="myagent",
|
package/start.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* start.js - 跨平台入口脚本 (Windows/macOS/Linux)
|
|
4
|
+
* ================================================
|
|
5
|
+
* npm bin 入口,自动检测平台:
|
|
6
|
+
* - Windows: 直接调用 python main.py [args](不依赖 bash)
|
|
7
|
+
* - macOS/Linux: 委托给 start.sh [args](保留完整的环境检测逻辑)
|
|
8
|
+
*
|
|
9
|
+
* 用法:
|
|
10
|
+
* myagent-ai # 交互式选择运行模式
|
|
11
|
+
* myagent-ai web # Web 管理后台
|
|
12
|
+
* myagent-ai cli # CLI 模式
|
|
13
|
+
* myagent-ai tray # 系统托盘模式
|
|
14
|
+
* myagent-ai server # API 服务模式
|
|
15
|
+
* myagent-ai setup # 配置向导
|
|
16
|
+
*/
|
|
17
|
+
"use strict";
|
|
18
|
+
|
|
19
|
+
const { spawn, execSync, execFileSync } = require("child_process");
|
|
20
|
+
const path = require("path");
|
|
21
|
+
const fs = require("fs");
|
|
22
|
+
|
|
23
|
+
// ── 常量 ──────────────────────────────────────────────────
|
|
24
|
+
const IS_WIN = process.platform === "win32";
|
|
25
|
+
|
|
26
|
+
// 解析包目录(兼容 symlink / npm link / 全局安装)
|
|
27
|
+
function resolvePackageDir() {
|
|
28
|
+
// 1. 当前文件所在目录
|
|
29
|
+
let dir = __dirname;
|
|
30
|
+
|
|
31
|
+
// 2. 如果 main.py 不在这里,尝试 npm global prefix
|
|
32
|
+
if (!fs.existsSync(path.join(dir, "main.py"))) {
|
|
33
|
+
try {
|
|
34
|
+
const npmRoot = execSync("npm root -g", {
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
37
|
+
}).trim();
|
|
38
|
+
const candidate = path.join(npmRoot, "myagent-ai");
|
|
39
|
+
if (fs.existsSync(path.join(candidate, "main.py"))) {
|
|
40
|
+
dir = candidate;
|
|
41
|
+
}
|
|
42
|
+
} catch (_) {
|
|
43
|
+
// ignore
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 3. 向上查找
|
|
48
|
+
if (!fs.existsSync(path.join(dir, "main.py"))) {
|
|
49
|
+
let up = dir;
|
|
50
|
+
for (let i = 0; i < 5; i++) {
|
|
51
|
+
up = path.dirname(up);
|
|
52
|
+
if (fs.existsSync(path.join(up, "main.py"))) {
|
|
53
|
+
dir = up;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return dir;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── 查找 Python ────────────────────────────────────────────
|
|
63
|
+
function findPython() {
|
|
64
|
+
const candidates = IS_WIN
|
|
65
|
+
? ["python", "python3", "python3.12", "python3.11", "python3.10"]
|
|
66
|
+
: ["python3", "python3.12", "python3.11", "python3.10", "python"];
|
|
67
|
+
|
|
68
|
+
for (const cmd of candidates) {
|
|
69
|
+
try {
|
|
70
|
+
const result = execFileSync(
|
|
71
|
+
IS_WIN ? `${cmd}.exe` : cmd,
|
|
72
|
+
["--version"],
|
|
73
|
+
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }
|
|
74
|
+
);
|
|
75
|
+
// 解析版本号
|
|
76
|
+
const match = result.match(/Python (\d+)\.(\d+)/);
|
|
77
|
+
if (match) {
|
|
78
|
+
const major = parseInt(match[1], 10);
|
|
79
|
+
const minor = parseInt(match[2], 10);
|
|
80
|
+
if (major >= 3 && minor >= 10) {
|
|
81
|
+
return cmd;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (_) {
|
|
85
|
+
// 继续尝试下一个
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Windows: 常见 Python 安装路径 ──────────────────────────
|
|
93
|
+
function findPythonOnWindows() {
|
|
94
|
+
const localAppData = process.env.LOCALAPPDATA || "";
|
|
95
|
+
const programFiles = process.env.ProgramFiles || "";
|
|
96
|
+
const programFilesX86 = process.env["ProgramFiles(x86)"] || "";
|
|
97
|
+
|
|
98
|
+
const searchPaths = [
|
|
99
|
+
path.join(localAppData, "Programs", "Python", "Python312", "python.exe"),
|
|
100
|
+
path.join(localAppData, "Programs", "Python", "Python311", "python.exe"),
|
|
101
|
+
path.join(localAppData, "Programs", "Python", "Python310", "python.exe"),
|
|
102
|
+
path.join(programFiles, "Python312", "python.exe"),
|
|
103
|
+
path.join(programFiles, "Python311", "python.exe"),
|
|
104
|
+
path.join(programFiles, "Python310", "python.exe"),
|
|
105
|
+
path.join(programFilesX86, "Python312", "python.exe"),
|
|
106
|
+
path.join(programFilesX86, "Python311", "python.exe"),
|
|
107
|
+
"C:\\Python312\\python.exe",
|
|
108
|
+
"C:\\Python311\\python.exe",
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (const pyPath of searchPaths) {
|
|
112
|
+
if (fs.existsSync(pyPath)) {
|
|
113
|
+
try {
|
|
114
|
+
const result = execFileSync(pyPath, ["--version"], {
|
|
115
|
+
encoding: "utf8",
|
|
116
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
117
|
+
timeout: 5000,
|
|
118
|
+
});
|
|
119
|
+
if (result.includes("Python")) {
|
|
120
|
+
return pyPath;
|
|
121
|
+
}
|
|
122
|
+
} catch (_) {
|
|
123
|
+
// continue
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── 构建 Python 参数 ───────────────────────────────────────
|
|
132
|
+
function buildArgs(userArgs) {
|
|
133
|
+
const mode = userArgs[0] || "";
|
|
134
|
+
switch (mode) {
|
|
135
|
+
case "cli":
|
|
136
|
+
return ["main.py"];
|
|
137
|
+
case "web":
|
|
138
|
+
return ["main.py", "--web"];
|
|
139
|
+
case "tray":
|
|
140
|
+
return ["main.py", "--tray"];
|
|
141
|
+
case "server":
|
|
142
|
+
return ["main.py", "--server"];
|
|
143
|
+
case "setup":
|
|
144
|
+
return ["main.py", "--setup"];
|
|
145
|
+
case "":
|
|
146
|
+
// 无参数:不传任何 flag,让 Python 程序进入交互式选择
|
|
147
|
+
return ["main.py"];
|
|
148
|
+
default:
|
|
149
|
+
// 透传未知参数
|
|
150
|
+
return ["main.py", ...userArgs];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Windows: pip 安装依赖(带升级和 fallback) ──────────────
|
|
155
|
+
// 核心依赖包名列表(直接安装,不依赖 requirements.txt 解析)
|
|
156
|
+
const CORE_PACKAGES = [
|
|
157
|
+
"openai>=1.12.0",
|
|
158
|
+
"aiohttp>=3.9.0",
|
|
159
|
+
"requests>=2.31.0",
|
|
160
|
+
"duckduckgo-search>=6.0.0",
|
|
161
|
+
"beautifulsoup4>=4.12.0",
|
|
162
|
+
"lxml>=5.0.0",
|
|
163
|
+
"psutil>=5.9.0",
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
function pipInstall(pythonCmd, packages, cwd) {
|
|
167
|
+
const args = ["-m", "pip", "install", "--quiet", "--disable-pip-version-check", ...packages];
|
|
168
|
+
return execFileSync(pythonCmd, args, {
|
|
169
|
+
encoding: "utf8",
|
|
170
|
+
stdio: "inherit",
|
|
171
|
+
timeout: 180000,
|
|
172
|
+
cwd,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function pipInstallReqFile(pythonCmd, reqFile, cwd) {
|
|
177
|
+
return execFileSync(pythonCmd, ["-m", "pip", "install", "-r", reqFile, "--disable-pip-version-check"], {
|
|
178
|
+
encoding: "utf8",
|
|
179
|
+
stdio: "inherit",
|
|
180
|
+
timeout: 300000,
|
|
181
|
+
cwd,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function upgradePip(pythonCmd) {
|
|
186
|
+
try {
|
|
187
|
+
console.log(" \x1b[90m[i]\x1b[0m 升级 pip...");
|
|
188
|
+
execFileSync(pythonCmd, ["-m", "pip", "install", "--upgrade", "pip", "--quiet"], {
|
|
189
|
+
encoding: "utf8",
|
|
190
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
191
|
+
timeout: 120000,
|
|
192
|
+
});
|
|
193
|
+
} catch (_) {
|
|
194
|
+
// 升级失败不阻断,继续尝试安装
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ── Windows 快速依赖检查 ───────────────────────────────────
|
|
199
|
+
function checkDepsWin(pkgDir) {
|
|
200
|
+
const required = ["openai", "aiohttp", "requests"];
|
|
201
|
+
let pythonCmd = findPython() || findPythonOnWindows();
|
|
202
|
+
|
|
203
|
+
if (!pythonCmd) {
|
|
204
|
+
console.error("\x1b[31m[✗]\x1b[0m 未找到 Python 3.10+");
|
|
205
|
+
console.error(" 请先安装 Python: https://www.python.org/downloads/");
|
|
206
|
+
console.error(" 安装时请勾选 'Add Python to PATH'");
|
|
207
|
+
console.error("");
|
|
208
|
+
console.error(" 或一键安装: powershell -c \"irm https://raw.githubusercontent.com/ctz168/myagent/main/install/install.ps1 | iex\"");
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 检查核心依赖
|
|
213
|
+
let missing = [];
|
|
214
|
+
for (const mod of required) {
|
|
215
|
+
try {
|
|
216
|
+
execFileSync(
|
|
217
|
+
pythonCmd,
|
|
218
|
+
["-c", `import ${mod}`],
|
|
219
|
+
{ encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000, cwd: pkgDir }
|
|
220
|
+
);
|
|
221
|
+
console.log(` \x1b[32m[✓]\x1b[0m ${mod}`);
|
|
222
|
+
} catch (_) {
|
|
223
|
+
console.log(` \x1b[33m[!]\x1b[0m ${mod}`);
|
|
224
|
+
missing.push(mod);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (missing.length > 0) {
|
|
229
|
+
console.log(`\x1b[33m[!]\x1b[0m 正在安装 ${missing.length} 个缺失依赖...`);
|
|
230
|
+
const reqFile = path.join(pkgDir, "requirements.txt");
|
|
231
|
+
|
|
232
|
+
// 策略1: 先升级 pip(旧版 pip 无法解析 requirements.txt)
|
|
233
|
+
upgradePip(pythonCmd);
|
|
234
|
+
|
|
235
|
+
// 策略2: 尝试 pip install -r requirements.txt
|
|
236
|
+
let installed = false;
|
|
237
|
+
if (fs.existsSync(reqFile)) {
|
|
238
|
+
try {
|
|
239
|
+
pipInstallReqFile(pythonCmd, reqFile, pkgDir);
|
|
240
|
+
console.log(` \x1b[32m[✓]\x1b[0m 依赖安装完成`);
|
|
241
|
+
installed = true;
|
|
242
|
+
} catch (_) {
|
|
243
|
+
// requirements.txt 安装失败,进入 fallback
|
|
244
|
+
console.log(` \x1b[33m[!]\x1b[0m requirements.txt 安装失败,尝试直接安装核心依赖...`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 策略3: 直接按包名安装核心依赖(不依赖 requirements.txt 解析)
|
|
249
|
+
if (!installed) {
|
|
250
|
+
try {
|
|
251
|
+
pipInstall(pythonCmd, CORE_PACKAGES, pkgDir);
|
|
252
|
+
console.log(` \x1b[32m[✓]\x1b[0m 核心依赖安装完成`);
|
|
253
|
+
console.log(` \x1b[90m[i]\x1b[0m 其他依赖将在 MyAgent 启动时自动安装`);
|
|
254
|
+
} catch (_) {
|
|
255
|
+
console.error(` \x1b[31m[✗]\x1b[0m 依赖安装失败,请手动运行:`);
|
|
256
|
+
console.error(` ${pythonCmd} -m pip install -r "${reqFile}"`);
|
|
257
|
+
console.error(` 或逐个安装:`);
|
|
258
|
+
for (const pkg of CORE_PACKAGES) {
|
|
259
|
+
console.error(` ${pythonCmd} -m pip install ${pkg}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return pythonCmd;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── 主入口 ─────────────────────────────────────────────────
|
|
269
|
+
function main() {
|
|
270
|
+
const userArgs = process.argv.slice(2);
|
|
271
|
+
const pkgDir = resolvePackageDir();
|
|
272
|
+
|
|
273
|
+
if (!fs.existsSync(path.join(pkgDir, "main.py"))) {
|
|
274
|
+
console.error("\x1b[31m[✗]\x1b[0m 错误: 找不到 main.py");
|
|
275
|
+
console.error(` 搜索路径: ${pkgDir}`);
|
|
276
|
+
console.error(' 请重新安装: npm install -g myagent-ai');
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// 打印 Banner
|
|
281
|
+
console.log("");
|
|
282
|
+
console.log(" \x1b[1m\x1b[36mMyAgent\x1b[0m - 本地桌面端执行型 AI 助手");
|
|
283
|
+
console.log("");
|
|
284
|
+
|
|
285
|
+
if (IS_WIN) {
|
|
286
|
+
// ── Windows 路径 ──
|
|
287
|
+
const pythonCmd = checkDepsWin(pkgDir);
|
|
288
|
+
|
|
289
|
+
// 首次运行检测
|
|
290
|
+
const homeDir = process.env.USERPROFILE || process.env.HOME || "";
|
|
291
|
+
const configFile = path.join(homeDir, ".myagent", "config.json");
|
|
292
|
+
if (!fs.existsSync(configFile)) {
|
|
293
|
+
console.log("");
|
|
294
|
+
console.log(" \x1b[90m[i]\x1b[0m 检测到首次运行,MyAgent 将在启动后引导你完成配置。");
|
|
295
|
+
console.log(" 1. 配置 LLM API Key(支持 OpenAI/Anthropic/ModelScope 等)");
|
|
296
|
+
console.log(" 2. 选择默认运行模式");
|
|
297
|
+
console.log("");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// 构建 Python 参数
|
|
301
|
+
const mode = userArgs[0] || "";
|
|
302
|
+
const pyArgs = buildArgs(userArgs);
|
|
303
|
+
|
|
304
|
+
if (mode) {
|
|
305
|
+
const modeNames = {
|
|
306
|
+
web: "Web 管理后台 (http://localhost:8767)",
|
|
307
|
+
cli: "CLI 交互模式",
|
|
308
|
+
tray: "系统托盘模式",
|
|
309
|
+
server: "API 服务模式",
|
|
310
|
+
setup: "配置向导",
|
|
311
|
+
};
|
|
312
|
+
console.log(`\x1b[36m启动 ${modeNames[mode] || mode}...\x1b[0m`);
|
|
313
|
+
} else {
|
|
314
|
+
console.log(`\x1b[36m启动...\x1b[0m`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// 使用 spawn 以交互模式运行 Python
|
|
318
|
+
const child = spawn(pythonCmd, pyArgs, {
|
|
319
|
+
cwd: pkgDir,
|
|
320
|
+
stdio: "inherit",
|
|
321
|
+
env: { ...process.env },
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
child.on("error", (err) => {
|
|
325
|
+
console.error(`\x1b[31m[✗]\x1b[0m 启动失败: ${err.message}`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
child.on("exit", (code) => {
|
|
330
|
+
process.exit(code || 0);
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
// ── macOS / Linux 路径:委托给 start.sh ──
|
|
334
|
+
const bashPath = process.env.SHELL || "/bin/bash";
|
|
335
|
+
const shell = path.basename(bashPath);
|
|
336
|
+
const shellArgs = shell === "bash" ? [] : ["-l"]; // zsh 需要 -l 加载 profile
|
|
337
|
+
|
|
338
|
+
const startSh = path.join(pkgDir, "start.sh");
|
|
339
|
+
if (!fs.existsSync(startSh)) {
|
|
340
|
+
console.error("\x1b[31m[✗]\x1b[0m 找不到 start.sh");
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const child = spawn(bashPath, [...shellArgs, startSh, ...userArgs], {
|
|
345
|
+
cwd: pkgDir,
|
|
346
|
+
stdio: "inherit",
|
|
347
|
+
env: { ...process.env },
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
child.on("error", (err) => {
|
|
351
|
+
console.error(`\x1b[31m[✗]\x1b[0m 启动失败: ${err.message}`);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
child.on("exit", (code) => {
|
|
356
|
+
process.exit(code || 0);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
main();
|