@cloudbase/cloudbase-mcp 1.7.3 → 1.7.5
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/README.md +5 -5
- package/dist/cloudbase-manager.js +108 -70
- package/dist/interactive-server.js +107 -12
- package/dist/tools/env.js +2 -1
- package/dist/tools/interactive.js +10 -27
- package/dist/tools/setup.js +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
|
|
|
132
132
|
"mcpServers": {
|
|
133
133
|
"cloudbase-mcp": {
|
|
134
134
|
"command": "npx",
|
|
135
|
-
"args": ["@cloudbase/cloudbase-mcp@latest"]
|
|
135
|
+
"args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -162,7 +162,7 @@ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
|
|
|
162
162
|
"mcpServers": {
|
|
163
163
|
"cloudbase-mcp": {
|
|
164
164
|
"command": "npx",
|
|
165
|
-
"args": ["@cloudbase/cloudbase-mcp@latest"]
|
|
165
|
+
"args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -190,7 +190,7 @@ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
|
|
|
190
190
|
"mcpServers": {
|
|
191
191
|
"cloudbase-mcp": {
|
|
192
192
|
"command": "npx",
|
|
193
|
-
"args": ["@cloudbase/cloudbase-mcp@latest"]
|
|
193
|
+
"args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
}
|
|
@@ -284,7 +284,7 @@ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
|
|
|
284
284
|
"mcpServers": {
|
|
285
285
|
"cloudbase-mcp": {
|
|
286
286
|
"command": "npx",
|
|
287
|
-
"args": ["@cloudbase/cloudbase-mcp@latest"]
|
|
287
|
+
"args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
}
|
|
@@ -312,7 +312,7 @@ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
|
|
|
312
312
|
"mcpServers": {
|
|
313
313
|
"cloudbase-mcp": {
|
|
314
314
|
"command": "npx",
|
|
315
|
-
"args": ["@cloudbase/cloudbase-mcp@latest"]
|
|
315
|
+
"args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
}
|
|
@@ -1,84 +1,122 @@
|
|
|
1
1
|
import { getLoginState } from './auth.js';
|
|
2
|
-
import {
|
|
2
|
+
import { loadEnvIdFromUserConfig, saveEnvIdToUserConfig, autoSetupEnvironmentId } from './tools/interactive.js';
|
|
3
3
|
import CloudBase from "@cloudbase/manager-node";
|
|
4
4
|
import { debug, error } from './utils/logger.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
const ENV_ID_TIMEOUT = 30000; // 30 seconds
|
|
6
|
+
// 统一的环境ID管理类
|
|
7
|
+
class EnvironmentManager {
|
|
8
|
+
cachedEnvId = null;
|
|
9
|
+
envIdPromise = null;
|
|
10
|
+
// 重置缓存
|
|
11
|
+
reset() {
|
|
12
|
+
this.cachedEnvId = null;
|
|
13
|
+
this.envIdPromise = null;
|
|
14
|
+
delete process.env.CLOUDBASE_ENV_ID;
|
|
15
|
+
}
|
|
16
|
+
// 获取环境ID的核心逻辑
|
|
17
|
+
async getEnvId() {
|
|
18
|
+
// 1. 优先使用内存缓存
|
|
19
|
+
if (this.cachedEnvId) {
|
|
20
|
+
debug('使用内存缓存的环境ID:', this.cachedEnvId);
|
|
21
|
+
return this.cachedEnvId;
|
|
13
22
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (!userEnvId) {
|
|
22
|
-
throw new Error("CloudBase Environment ID not found after auto setup. Please set CLOUDBASE_ENV_ID or run setupEnvironmentId tool.");
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
const loginState = await getLoginState();
|
|
26
|
-
const { envId, secretId, secretKey, token } = loginState;
|
|
27
|
-
const manager = new CloudBase({
|
|
28
|
-
secretId,
|
|
29
|
-
secretKey,
|
|
30
|
-
envId: userEnvId,
|
|
31
|
-
token,
|
|
32
|
-
proxy: process.env.http_proxy
|
|
33
|
-
});
|
|
34
|
-
return manager;
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
error('Failed to initialize CloudBase Manager:', err);
|
|
38
|
-
throw err;
|
|
39
|
-
}
|
|
40
|
-
};
|
|
23
|
+
// 2. 如果正在获取中,等待结果
|
|
24
|
+
if (this.envIdPromise) {
|
|
25
|
+
return this.envIdPromise;
|
|
26
|
+
}
|
|
27
|
+
// 3. 开始获取环境ID
|
|
28
|
+
this.envIdPromise = this._fetchEnvId();
|
|
29
|
+
// 增加超时保护
|
|
41
30
|
const timeoutPromise = new Promise((_, reject) => {
|
|
42
31
|
const id = setTimeout(() => {
|
|
43
32
|
clearTimeout(id);
|
|
44
|
-
reject(new Error(`
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
initializationPromise = Promise.race([executor(), timeoutPromise]);
|
|
48
|
-
initializationPromise.catch(() => {
|
|
49
|
-
initializationPromise = null;
|
|
33
|
+
reject(new Error(`EnvId 获取超时(${ENV_ID_TIMEOUT / 1000}秒)`));
|
|
34
|
+
}, ENV_ID_TIMEOUT);
|
|
50
35
|
});
|
|
51
|
-
return initializationPromise;
|
|
52
|
-
}
|
|
53
|
-
if (noEnvIdInitializationPromise) {
|
|
54
|
-
return noEnvIdInitializationPromise;
|
|
55
|
-
}
|
|
56
|
-
const noEnvIdExecutor = async () => {
|
|
57
36
|
try {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const manager = new CloudBase({
|
|
61
|
-
secretId,
|
|
62
|
-
secretKey,
|
|
63
|
-
token,
|
|
64
|
-
proxy: process.env.http_proxy
|
|
65
|
-
});
|
|
66
|
-
return manager;
|
|
37
|
+
const result = await Promise.race([this.envIdPromise, timeoutPromise]);
|
|
38
|
+
return result;
|
|
67
39
|
}
|
|
68
40
|
catch (err) {
|
|
69
|
-
|
|
41
|
+
this.envIdPromise = null;
|
|
70
42
|
throw err;
|
|
71
43
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
44
|
+
}
|
|
45
|
+
async _fetchEnvId() {
|
|
46
|
+
try {
|
|
47
|
+
// 1. 检查进程环境变量
|
|
48
|
+
if (process.env.CLOUDBASE_ENV_ID) {
|
|
49
|
+
debug('使用进程环境变量的环境ID:', process.env.CLOUDBASE_ENV_ID);
|
|
50
|
+
this.cachedEnvId = process.env.CLOUDBASE_ENV_ID;
|
|
51
|
+
return this.cachedEnvId;
|
|
52
|
+
}
|
|
53
|
+
// 2. 从配置文件读取
|
|
54
|
+
const fileEnvId = await loadEnvIdFromUserConfig();
|
|
55
|
+
if (fileEnvId) {
|
|
56
|
+
debug('从配置文件读取到环境ID:', fileEnvId);
|
|
57
|
+
this._setCachedEnvId(fileEnvId);
|
|
58
|
+
return fileEnvId;
|
|
59
|
+
}
|
|
60
|
+
// 3. 自动设置环境ID
|
|
61
|
+
debug('未找到环境ID,尝试自动设置...');
|
|
62
|
+
const autoEnvId = await autoSetupEnvironmentId();
|
|
63
|
+
if (!autoEnvId) {
|
|
64
|
+
throw new Error("CloudBase Environment ID not found after auto setup. Please set CLOUDBASE_ENV_ID or run setupEnvironmentId tool.");
|
|
65
|
+
}
|
|
66
|
+
debug('自动设置环境ID成功:', autoEnvId);
|
|
67
|
+
this._setCachedEnvId(autoEnvId);
|
|
68
|
+
return autoEnvId;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
this.envIdPromise = null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// 统一设置缓存的方法
|
|
75
|
+
_setCachedEnvId(envId) {
|
|
76
|
+
this.cachedEnvId = envId;
|
|
77
|
+
process.env.CLOUDBASE_ENV_ID = envId;
|
|
78
|
+
debug('已更新环境ID缓存:', envId);
|
|
79
|
+
}
|
|
80
|
+
// 手动设置环境ID(用于外部调用)
|
|
81
|
+
async setEnvId(envId) {
|
|
82
|
+
this._setCachedEnvId(envId);
|
|
83
|
+
// 同步保存到配置文件
|
|
84
|
+
await saveEnvIdToUserConfig(envId);
|
|
85
|
+
debug('手动设置环境ID并保存到文件:', envId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// 全局实例
|
|
89
|
+
const envManager = new EnvironmentManager();
|
|
90
|
+
// 导出函数保持兼容性
|
|
91
|
+
export function resetCloudBaseManagerCache() {
|
|
92
|
+
envManager.reset();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 每次都实时获取最新的 token/secretId/secretKey
|
|
96
|
+
*/
|
|
97
|
+
export async function getCloudBaseManager(options = {}) {
|
|
98
|
+
const { requireEnvId = true } = options;
|
|
99
|
+
try {
|
|
100
|
+
const loginState = await getLoginState();
|
|
101
|
+
const { envId: loginEnvId, secretId, secretKey, token } = loginState;
|
|
102
|
+
let finalEnvId;
|
|
103
|
+
if (requireEnvId) {
|
|
104
|
+
finalEnvId = await envManager.getEnvId();
|
|
105
|
+
}
|
|
106
|
+
// envId 优先顺序:获取到的envId > loginState中的envId > undefined
|
|
107
|
+
const manager = new CloudBase({
|
|
108
|
+
secretId,
|
|
109
|
+
secretKey,
|
|
110
|
+
envId: finalEnvId || loginEnvId,
|
|
111
|
+
token,
|
|
112
|
+
proxy: process.env.http_proxy
|
|
113
|
+
});
|
|
114
|
+
return manager;
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
error('Failed to initialize CloudBase Manager:', err instanceof Error ? err.message : String(err));
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
84
120
|
}
|
|
121
|
+
// 导出环境管理器实例供其他地方使用
|
|
122
|
+
export { envManager };
|
|
@@ -17,13 +17,25 @@ export class InteractiveServer {
|
|
|
17
17
|
sessionData = new Map();
|
|
18
18
|
// 固定端口配置
|
|
19
19
|
DEFAULT_PORT = 3721;
|
|
20
|
-
FALLBACK_PORTS = [3722, 3723, 3724, 3725];
|
|
20
|
+
FALLBACK_PORTS = [3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735];
|
|
21
21
|
constructor() {
|
|
22
22
|
this.app = express();
|
|
23
23
|
this.server = http.createServer(this.app);
|
|
24
24
|
this.wss = new WebSocketServer({ server: this.server });
|
|
25
25
|
this.setupExpress();
|
|
26
26
|
this.setupWebSocket();
|
|
27
|
+
// 确保进程退出时清理资源
|
|
28
|
+
process.on('exit', () => this.cleanup());
|
|
29
|
+
process.on('SIGINT', () => this.cleanup());
|
|
30
|
+
process.on('SIGTERM', () => this.cleanup());
|
|
31
|
+
}
|
|
32
|
+
cleanup() {
|
|
33
|
+
if (this.isRunning) {
|
|
34
|
+
debug('Cleaning up interactive server resources...');
|
|
35
|
+
this.server.close();
|
|
36
|
+
this.wss.close();
|
|
37
|
+
this.isRunning = false;
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
setupExpress() {
|
|
29
41
|
this.app.use(express.json());
|
|
@@ -148,32 +160,41 @@ export class InteractiveServer {
|
|
|
148
160
|
let currentIndex = 0;
|
|
149
161
|
const tryNextPort = () => {
|
|
150
162
|
if (currentIndex >= tryPorts.length) {
|
|
151
|
-
const err = new Error(
|
|
163
|
+
const err = new Error(`All ${tryPorts.length} ports are in use (${tryPorts.join(', ')}), failed to start server`);
|
|
152
164
|
error('Server start failed', err);
|
|
153
165
|
reject(err);
|
|
154
166
|
return;
|
|
155
167
|
}
|
|
156
168
|
const portToTry = tryPorts[currentIndex];
|
|
157
169
|
currentIndex++;
|
|
158
|
-
debug(`Trying to start server on port ${portToTry}`);
|
|
159
|
-
//
|
|
170
|
+
debug(`Trying to start server on port ${portToTry} (attempt ${currentIndex}/${tryPorts.length})`);
|
|
171
|
+
// 清除之前的所有监听器
|
|
160
172
|
this.server.removeAllListeners('error');
|
|
161
|
-
this.server.
|
|
173
|
+
this.server.removeAllListeners('listening');
|
|
174
|
+
// 设置错误处理
|
|
175
|
+
const errorHandler = (err) => {
|
|
162
176
|
if (err.code === 'EADDRINUSE') {
|
|
163
177
|
warn(`Port ${portToTry} is in use, trying next port...`);
|
|
178
|
+
// 清理当前尝试
|
|
179
|
+
this.server.removeAllListeners('error');
|
|
180
|
+
this.server.removeAllListeners('listening');
|
|
164
181
|
tryNextPort();
|
|
165
182
|
}
|
|
166
183
|
else {
|
|
167
184
|
error('Server error', err);
|
|
168
185
|
reject(err);
|
|
169
186
|
}
|
|
170
|
-
}
|
|
171
|
-
|
|
187
|
+
};
|
|
188
|
+
// 设置成功监听处理
|
|
189
|
+
const listeningHandler = () => {
|
|
172
190
|
const address = this.server.address();
|
|
173
191
|
if (address && typeof address === 'object') {
|
|
174
192
|
this.port = address.port;
|
|
175
193
|
this.isRunning = true;
|
|
176
194
|
info(`Interactive server started successfully on http://localhost:${this.port}`);
|
|
195
|
+
// 移除临时监听器
|
|
196
|
+
this.server.removeListener('error', errorHandler);
|
|
197
|
+
this.server.removeListener('listening', listeningHandler);
|
|
177
198
|
resolve(this.port);
|
|
178
199
|
}
|
|
179
200
|
else {
|
|
@@ -181,19 +202,61 @@ export class InteractiveServer {
|
|
|
181
202
|
error('Server start error', err);
|
|
182
203
|
reject(err);
|
|
183
204
|
}
|
|
184
|
-
}
|
|
205
|
+
};
|
|
206
|
+
this.server.once('error', errorHandler);
|
|
207
|
+
this.server.once('listening', listeningHandler);
|
|
208
|
+
try {
|
|
209
|
+
this.server.listen(portToTry, '127.0.0.1');
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
error(`Failed to bind to port ${portToTry}:`, err);
|
|
213
|
+
tryNextPort();
|
|
214
|
+
}
|
|
185
215
|
};
|
|
186
216
|
tryNextPort();
|
|
187
217
|
});
|
|
188
218
|
}
|
|
189
219
|
async stop() {
|
|
190
|
-
if (!this.isRunning)
|
|
220
|
+
if (!this.isRunning) {
|
|
221
|
+
debug('Interactive server is not running, nothing to stop');
|
|
191
222
|
return;
|
|
192
|
-
|
|
193
|
-
|
|
223
|
+
}
|
|
224
|
+
info('Stopping interactive server...');
|
|
225
|
+
return new Promise((resolve, reject) => {
|
|
226
|
+
// 设置超时,防止无限等待
|
|
227
|
+
const timeout = setTimeout(() => {
|
|
228
|
+
warn('Server close timeout, forcing cleanup');
|
|
194
229
|
this.isRunning = false;
|
|
230
|
+
this.port = 0;
|
|
195
231
|
resolve();
|
|
196
|
-
});
|
|
232
|
+
}, 5000);
|
|
233
|
+
try {
|
|
234
|
+
// 首先关闭WebSocket服务器
|
|
235
|
+
this.wss.close(() => {
|
|
236
|
+
debug('WebSocket server closed');
|
|
237
|
+
});
|
|
238
|
+
// 然后关闭HTTP服务器
|
|
239
|
+
this.server.close((err) => {
|
|
240
|
+
clearTimeout(timeout);
|
|
241
|
+
if (err) {
|
|
242
|
+
error('Error closing server:', err);
|
|
243
|
+
reject(err);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
info('Interactive server stopped successfully');
|
|
247
|
+
this.isRunning = false;
|
|
248
|
+
this.port = 0;
|
|
249
|
+
resolve();
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
clearTimeout(timeout);
|
|
255
|
+
error('Error stopping server:', err);
|
|
256
|
+
this.isRunning = false;
|
|
257
|
+
this.port = 0;
|
|
258
|
+
reject(err);
|
|
259
|
+
}
|
|
197
260
|
});
|
|
198
261
|
}
|
|
199
262
|
async collectEnvId(availableEnvs) {
|
|
@@ -2438,6 +2501,14 @@ export class InteractiveServer {
|
|
|
2438
2501
|
</body>
|
|
2439
2502
|
</html>`;
|
|
2440
2503
|
}
|
|
2504
|
+
// 公共方法获取运行状态
|
|
2505
|
+
get running() {
|
|
2506
|
+
return this.isRunning;
|
|
2507
|
+
}
|
|
2508
|
+
// 公共方法获取端口
|
|
2509
|
+
get currentPort() {
|
|
2510
|
+
return this.port;
|
|
2511
|
+
}
|
|
2441
2512
|
}
|
|
2442
2513
|
// 单例实例
|
|
2443
2514
|
let interactiveServerInstance = null;
|
|
@@ -2447,3 +2518,27 @@ export function getInteractiveServer() {
|
|
|
2447
2518
|
}
|
|
2448
2519
|
return interactiveServerInstance;
|
|
2449
2520
|
}
|
|
2521
|
+
export async function resetInteractiveServer() {
|
|
2522
|
+
if (interactiveServerInstance) {
|
|
2523
|
+
try {
|
|
2524
|
+
await interactiveServerInstance.stop();
|
|
2525
|
+
}
|
|
2526
|
+
catch (err) {
|
|
2527
|
+
error('Error stopping existing server instance:', err);
|
|
2528
|
+
}
|
|
2529
|
+
interactiveServerInstance = null;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
export async function getInteractiveServerSafe() {
|
|
2533
|
+
// 如果当前实例存在但不在运行状态,先清理
|
|
2534
|
+
if (interactiveServerInstance && !interactiveServerInstance.running) {
|
|
2535
|
+
try {
|
|
2536
|
+
await interactiveServerInstance.stop();
|
|
2537
|
+
}
|
|
2538
|
+
catch (err) {
|
|
2539
|
+
debug('Error stopping non-running server:', err);
|
|
2540
|
+
}
|
|
2541
|
+
interactiveServerInstance = null;
|
|
2542
|
+
}
|
|
2543
|
+
return getInteractiveServer();
|
|
2544
|
+
}
|
package/dist/tools/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { getCloudBaseManager } from '../cloudbase-manager.js';
|
|
2
|
+
import { getCloudBaseManager, resetCloudBaseManagerCache } from '../cloudbase-manager.js';
|
|
3
3
|
import { logout } from '../auth.js';
|
|
4
4
|
import { clearUserEnvId, _promptAndSetEnvironmentId } from './interactive.js';
|
|
5
5
|
import { debug } from '../utils/logger.js';
|
|
@@ -48,6 +48,7 @@ export function registerEnvTools(server) {
|
|
|
48
48
|
await logout();
|
|
49
49
|
// 清理环境ID配置
|
|
50
50
|
await clearUserEnvId();
|
|
51
|
+
await resetCloudBaseManagerCache();
|
|
51
52
|
return {
|
|
52
53
|
content: [{
|
|
53
54
|
type: "text",
|
|
@@ -97,10 +97,10 @@ export async function _promptAndSetEnvironmentId(autoSelectSingle) {
|
|
|
97
97
|
}
|
|
98
98
|
selectedEnvId = result.data;
|
|
99
99
|
}
|
|
100
|
-
// 4.
|
|
100
|
+
// 4. 保存环境ID配置
|
|
101
101
|
if (selectedEnvId) {
|
|
102
102
|
await saveEnvIdToUserConfig(selectedEnvId);
|
|
103
|
-
|
|
103
|
+
debug('环境ID已保存到配置文件:', selectedEnvId);
|
|
104
104
|
}
|
|
105
105
|
return { selectedEnvId, cancelled: false };
|
|
106
106
|
}
|
|
@@ -109,7 +109,7 @@ function getUserConfigPath() {
|
|
|
109
109
|
return path.join(os.homedir(), '.cloudbase-env-id');
|
|
110
110
|
}
|
|
111
111
|
// 保存环境ID到用户配置文件
|
|
112
|
-
async function saveEnvIdToUserConfig(envId) {
|
|
112
|
+
export async function saveEnvIdToUserConfig(envId) {
|
|
113
113
|
const configPath = getUserConfigPath();
|
|
114
114
|
try {
|
|
115
115
|
const config = {
|
|
@@ -118,7 +118,7 @@ async function saveEnvIdToUserConfig(envId) {
|
|
|
118
118
|
version: '1.0'
|
|
119
119
|
};
|
|
120
120
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
121
|
-
|
|
121
|
+
debug('环境ID配置已保存到文件:', configPath);
|
|
122
122
|
}
|
|
123
123
|
catch (error) {
|
|
124
124
|
console.error('保存环境ID配置失败:', error);
|
|
@@ -126,7 +126,7 @@ async function saveEnvIdToUserConfig(envId) {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
// 从用户配置文件读取环境ID
|
|
129
|
-
async function loadEnvIdFromUserConfig() {
|
|
129
|
+
export async function loadEnvIdFromUserConfig() {
|
|
130
130
|
const configPath = getUserConfigPath();
|
|
131
131
|
try {
|
|
132
132
|
const configContent = await fs.readFile(configPath, 'utf8');
|
|
@@ -135,6 +135,9 @@ async function loadEnvIdFromUserConfig() {
|
|
|
135
135
|
if (!envId) {
|
|
136
136
|
warn(`Config file ${configPath} found, but 'envId' property is missing or empty.`);
|
|
137
137
|
}
|
|
138
|
+
else {
|
|
139
|
+
debug('从配置文件加载环境ID:', envId);
|
|
140
|
+
}
|
|
138
141
|
return envId;
|
|
139
142
|
}
|
|
140
143
|
catch (err) {
|
|
@@ -148,36 +151,16 @@ async function loadEnvIdFromUserConfig() {
|
|
|
148
151
|
return null;
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
// 检查并设置环境ID
|
|
152
|
-
export async function ensureEnvId() {
|
|
153
|
-
// 优先使用进程环境变量
|
|
154
|
-
if (process.env.CLOUDBASE_ENV_ID) {
|
|
155
|
-
return process.env.CLOUDBASE_ENV_ID;
|
|
156
|
-
}
|
|
157
|
-
// 从用户配置文件读取
|
|
158
|
-
const envId = await loadEnvIdFromUserConfig();
|
|
159
|
-
if (envId) {
|
|
160
|
-
// 设置到进程环境变量中
|
|
161
|
-
process.env.CLOUDBASE_ENV_ID = envId;
|
|
162
|
-
return envId;
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
154
|
// 清理用户环境ID配置
|
|
167
155
|
export async function clearUserEnvId() {
|
|
168
156
|
const configPath = getUserConfigPath();
|
|
169
157
|
try {
|
|
170
158
|
await fs.unlink(configPath);
|
|
171
|
-
|
|
172
|
-
delete process.env.CLOUDBASE_ENV_ID;
|
|
173
|
-
delete process.env.TENCENTCLOUD_SECRETID;
|
|
174
|
-
delete process.env.TENCENTCLOUD_SECRETKEY;
|
|
175
|
-
delete process.env.TENCENTCLOUD_SESSIONTOKEN;
|
|
176
|
-
// 环境ID配置已清理 - 静默操作
|
|
159
|
+
debug('环境ID配置文件已删除:', configPath);
|
|
177
160
|
}
|
|
178
161
|
catch (error) {
|
|
179
162
|
// 文件不存在或删除失败,忽略错误
|
|
180
|
-
|
|
163
|
+
debug('环境ID配置文件不存在或已清理:', configPath);
|
|
181
164
|
}
|
|
182
165
|
}
|
|
183
166
|
// 自动设置环境ID(无需MCP工具调用)
|
package/dist/tools/setup.js
CHANGED
|
@@ -12,6 +12,10 @@ const TEMPLATES = {
|
|
|
12
12
|
description: "React + CloudBase 全栈应用模板",
|
|
13
13
|
url: "https://static.cloudbase.net/cloudbase-examples/web-cloudbase-react-template.zip"
|
|
14
14
|
},
|
|
15
|
+
"vue": {
|
|
16
|
+
description: "Vue + CloudBase 全栈应用模板",
|
|
17
|
+
url: "https://static.cloudbase.net/cloudbase-examples/web-cloudbase-vue-template.zip"
|
|
18
|
+
},
|
|
15
19
|
"miniprogram": {
|
|
16
20
|
description: "微信小程序 + 云开发模板",
|
|
17
21
|
url: "https://static.cloudbase.net/cloudbase-examples/miniprogram-cloudbase-miniprogram-template.zip"
|
|
@@ -123,11 +127,12 @@ export function registerSetupTools(server) {
|
|
|
123
127
|
|
|
124
128
|
支持的模板:
|
|
125
129
|
- react: React + CloudBase 全栈应用模板
|
|
130
|
+
- vue: Vue + CloudBase 全栈应用模板
|
|
126
131
|
- miniprogram: 微信小程序 + 云开发模板
|
|
127
132
|
- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置
|
|
128
133
|
|
|
129
134
|
工具会自动下载模板到临时目录,解压后如果检测到WORKSPACE_FOLDER_PATHS环境变量,则复制到项目目录。`, {
|
|
130
|
-
template: z.enum(["react", "miniprogram", "rules"]).describe("要下载的模板类型"),
|
|
135
|
+
template: z.enum(["react", "vue", "miniprogram", "rules"]).describe("要下载的模板类型"),
|
|
131
136
|
overwrite: z.boolean().optional().describe("是否覆盖已存在的文件,默认为false(不覆盖)")
|
|
132
137
|
}, async ({ template, overwrite = false }) => {
|
|
133
138
|
try {
|