aicodeswitch 2.0.10 → 2.1.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.
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getToolsInstallationStatus = getToolsInstallationStatus;
16
+ exports.installTool = installTool;
17
+ const child_process_1 = require("child_process");
18
+ const os_1 = __importDefault(require("os"));
19
+ /**
20
+ * 检测工具是否已安装
21
+ */
22
+ function checkToolInstalled(toolName) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ console.log(`[ToolsService] 开始检测工具: ${toolName}`);
25
+ return new Promise((resolve) => {
26
+ var _a, _b;
27
+ const command = toolName === 'claude-code' ? 'claude' : 'codex';
28
+ console.log(`[ToolsService] 执行命令: ${command} --version`);
29
+ const child = (0, child_process_1.spawn)(command, ['--version'], {
30
+ shell: true,
31
+ stdio: ['ignore', 'pipe', 'pipe'],
32
+ });
33
+ let stdout = '';
34
+ let stderr = '';
35
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
36
+ stdout += data.toString();
37
+ console.log(`[ToolsService] ${toolName} stdout:`, data.toString());
38
+ });
39
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
40
+ stderr += data.toString();
41
+ console.log(`[ToolsService] ${toolName} stderr:`, data.toString());
42
+ });
43
+ child.on('close', (code) => {
44
+ console.log(`[ToolsService] ${toolName} 进程退出,退出码: ${code}`);
45
+ if (code === 0) {
46
+ // 尝试从输出中提取版本号
47
+ const versionMatch = stdout.match(/(\d+\.\d+\.\d+)/) || stderr.match(/(\d+\.\d+\.\d+)/);
48
+ resolve({
49
+ installed: true,
50
+ version: versionMatch ? versionMatch[1] : 'unknown',
51
+ });
52
+ }
53
+ else {
54
+ resolve({ installed: false });
55
+ }
56
+ });
57
+ child.on('error', (err) => {
58
+ console.log(`[ToolsService] ${toolName} 检测出错:`, err);
59
+ resolve({ installed: false });
60
+ });
61
+ // 10秒超时
62
+ setTimeout(() => {
63
+ console.log(`[ToolsService] ${toolName} 检测超时`);
64
+ child.kill();
65
+ resolve({ installed: false });
66
+ }, 10000);
67
+ });
68
+ });
69
+ }
70
+ /**
71
+ * 获取工具的安装命令
72
+ */
73
+ function getInstallCommand(toolName) {
74
+ const platform = os_1.default.platform();
75
+ const tool = toolName === 'claude-code' ? '@anthropic-ai/claude-code' : '@openai/codex';
76
+ if (platform === 'win32') {
77
+ return `npm install -g ${tool}`;
78
+ }
79
+ else {
80
+ // macOS 和 Linux 需要 sudo
81
+ return `sudo npm install -g ${tool}`;
82
+ }
83
+ }
84
+ /**
85
+ * 检测所有工具的安装状态
86
+ */
87
+ function getToolsInstallationStatus() {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const [claudeCodeStatus, codexStatus] = yield Promise.all([
90
+ checkToolInstalled('claude-code'),
91
+ checkToolInstalled('codex'),
92
+ ]);
93
+ return {
94
+ claudeCode: Object.assign(Object.assign({}, claudeCodeStatus), { installCommand: claudeCodeStatus.installed ? undefined : getInstallCommand('claude-code') }),
95
+ codex: Object.assign(Object.assign({}, codexStatus), { installCommand: codexStatus.installed ? undefined : getInstallCommand('codex') }),
96
+ };
97
+ });
98
+ }
99
+ /**
100
+ * 执行工具安装
101
+ */
102
+ function installTool(toolName, callbacks) {
103
+ var _a, _b;
104
+ const command = getInstallCommand(toolName);
105
+ const platform = os_1.default.platform();
106
+ console.log(`[ToolsService] ========== 开始安装 ${toolName} ==========`);
107
+ console.log(`[ToolsService] 操作系统: ${platform}`);
108
+ console.log(`[ToolsService] 安装命令: ${command}`);
109
+ // 立即发送启动消息,让前端快速进入 terminal 界面
110
+ callbacks.onData(`\n========== 开始安装 ${toolName} ==========\n`);
111
+ callbacks.onData(`操作系统: ${platform}\n`);
112
+ callbacks.onData(`执行命令: ${command}\n`);
113
+ callbacks.onData(`进程启动中...\n\n`);
114
+ // 在 macOS/Linux 上,需要使用 sudo 并且可能需要输入密码
115
+ // 在 Windows 上直接使用 cmd 执行 npm 命令
116
+ let child;
117
+ if (platform === 'win32') {
118
+ // Windows: 使用 cmd.exe 执行命令
119
+ console.log(`[ToolsService] Windows 环境,使用 cmd.exe`);
120
+ child = (0, child_process_1.spawn)('cmd.exe', ['/c', command], {
121
+ stdio: ['pipe', 'pipe', 'pipe'],
122
+ shell: false,
123
+ windowsHide: true, // 隐藏命令行窗口
124
+ });
125
+ }
126
+ else {
127
+ // Unix: 使用 sh 执行命令
128
+ console.log(`[ToolsService] Unix 环境,使用 sh`);
129
+ child = (0, child_process_1.spawn)('sh', ['-c', command], {
130
+ stdio: ['pipe', 'pipe', 'pipe'],
131
+ shell: false,
132
+ });
133
+ }
134
+ console.log(`[ToolsService] 子进程 PID: ${child.pid}`);
135
+ // 立即发送进程信息
136
+ callbacks.onData(`子进程已创建 (PID: ${child.pid})\n`);
137
+ callbacks.onData(`等待 npm 输出...\n\n`);
138
+ // 设置超时:30分钟后自动终止
139
+ const timeout = 30 * 60 * 1000;
140
+ const timeoutHandle = setTimeout(() => {
141
+ console.error(`[ToolsService] ${toolName} 安装超时 (${timeout}ms),终止进程`);
142
+ child.kill('SIGTERM');
143
+ callbacks.onError(`\n安装超时 (${timeout / 60000} 分钟),请检查网络连接或手动执行命令:\n${command}\n`);
144
+ }, timeout);
145
+ let hasReceivedData = false;
146
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
147
+ const output = data.toString();
148
+ if (!hasReceivedData) {
149
+ console.log(`[ToolsService] ${toolName} 首次收到 stdout 数据`);
150
+ hasReceivedData = true;
151
+ }
152
+ console.log(`[ToolsService] ${toolName} stdout:`, output.slice(0, 200)); // 只记录前200字符
153
+ callbacks.onData(output);
154
+ });
155
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
156
+ const output = data.toString();
157
+ if (!hasReceivedData) {
158
+ console.log(`[ToolsService] ${toolName} 首次收到 stderr 数据`);
159
+ hasReceivedData = true;
160
+ }
161
+ console.log(`[ToolsService] ${toolName} stderr:`, output.slice(0, 200)); // 只记录前200字符
162
+ callbacks.onError(output);
163
+ });
164
+ child.on('close', (code) => {
165
+ clearTimeout(timeoutHandle);
166
+ console.log(`[ToolsService] ${toolName} 安装进程关闭,退出码: ${code}`);
167
+ if (code === 0) {
168
+ callbacks.onData(`\n========== 安装完成 ==========\n`);
169
+ }
170
+ else if (code === null) {
171
+ callbacks.onError(`\n========== 安装被终止 ==========\n`);
172
+ }
173
+ else {
174
+ callbacks.onError(`\n========== 安装失败 (退出码: ${code}) ==========\n`);
175
+ }
176
+ callbacks.onClose(code);
177
+ });
178
+ child.on('error', (err) => {
179
+ clearTimeout(timeoutHandle);
180
+ console.error(`[ToolsService] ${toolName} 安装进程错误:`, err);
181
+ callbacks.onError(`启动安装进程失败: ${err.message}\n`);
182
+ callbacks.onError(`错误详情: ${err}\n`);
183
+ callbacks.onClose(null);
184
+ });
185
+ // 处理进程退出信号
186
+ child.on('exit', (_code, signal) => {
187
+ clearTimeout(timeoutHandle);
188
+ if (signal) {
189
+ console.log(`[ToolsService] ${toolName} 进程被信号终止: ${signal}`);
190
+ callbacks.onError(`\n安装进程被信号终止: ${signal}\n`);
191
+ }
192
+ });
193
+ // 如果10秒后还没有收到任何数据,发送提示
194
+ setTimeout(() => {
195
+ if (!hasReceivedData) {
196
+ console.log(`[ToolsService] ${toolName} 10秒内未收到输出,发送等待提示`);
197
+ callbacks.onData(`[提示] 正在连接 npm 服务器,这可能需要一些时间...\n`);
198
+ callbacks.onData(`[提示] 如果持续无响应,请检查网络连接或 npm 配置\n\n`);
199
+ }
200
+ }, 10000);
201
+ return child;
202
+ }