cloudflare-mcp-smart-proxy 1.2.0 → 1.3.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.
- package/README.md +74 -142
- package/connector-cli.js +144 -0
- package/index.js +42 -6
- package/package.json +18 -4
- package/src/cloud-client.js +137 -0
- package/src/connector-bridge.js +284 -0
- package/src/device-identity.js +88 -0
- package/src/ide-configurator.js +316 -0
- package/src/local-tools.js +84 -2
- package/src/project-probe-discovery.js +137 -0
- package/src/reference-connectors.js +315 -0
- package/src/router.js +78 -32
- package/package-personal.json +0 -28
- package/publish-now.sh +0 -230
- package/publish-with-2fa.sh +0 -134
- package/publish.sh +0 -90
- package/version-bump.sh +0 -128
package/src/router.js
CHANGED
|
@@ -2,12 +2,48 @@
|
|
|
2
2
|
* Smart Router - 智能路由工具请求到云端或本地
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
function collectArgumentStrings(value, output = new Set(), seen = new WeakSet()) {
|
|
6
|
+
if (typeof value === 'string') {
|
|
7
|
+
const normalized = value.trim();
|
|
8
|
+
if (normalized.length >= 2) output.add(normalized);
|
|
9
|
+
return output;
|
|
10
|
+
}
|
|
11
|
+
if (value == null || typeof value !== 'object' || seen.has(value)) return output;
|
|
12
|
+
seen.add(value);
|
|
13
|
+
for (const item of Array.isArray(value) ? value : Object.values(value)) {
|
|
14
|
+
collectArgumentStrings(item, output, seen);
|
|
15
|
+
}
|
|
16
|
+
return output;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function sanitizeProxyError(error, params = {}) {
|
|
20
|
+
let message = typeof error === 'string'
|
|
21
|
+
? error
|
|
22
|
+
: (error?.message || JSON.stringify(error || 'Unknown error'));
|
|
23
|
+
const values = Array.from(collectArgumentStrings(params))
|
|
24
|
+
.sort((left, right) => right.length - left.length);
|
|
25
|
+
for (const value of values) {
|
|
26
|
+
const variants = new Set([value]);
|
|
27
|
+
try {
|
|
28
|
+
variants.add(encodeURIComponent(value));
|
|
29
|
+
} catch {}
|
|
30
|
+
for (const variant of variants) {
|
|
31
|
+
message = message.split(variant).join('[REDACTED_PARAM]');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return String(message)
|
|
35
|
+
.replace(/Bearer\s+[A-Za-z0-9._~+\/-]+=*/gi, 'Bearer [REDACTED]')
|
|
36
|
+
.replace(/mcp_[A-Za-z0-9]{16,}/g, '[REDACTED]')
|
|
37
|
+
.slice(0, 512);
|
|
38
|
+
}
|
|
39
|
+
|
|
5
40
|
export class SmartRouter {
|
|
6
|
-
constructor(cloudUrl, cloudApiKey, localTools, workspaceRoot = null) {
|
|
41
|
+
constructor(cloudUrl, cloudApiKey, localTools, workspaceRoot = null, deviceIdentity = null) {
|
|
7
42
|
this.cloudUrl = cloudUrl.replace(/\/$/, ''); // 移除尾部斜杠
|
|
8
43
|
this.cloudApiKey = cloudApiKey;
|
|
9
44
|
this.localTools = localTools;
|
|
10
45
|
this.workspaceRoot = workspaceRoot || process.cwd();
|
|
46
|
+
this.deviceIdentity = deviceIdentity;
|
|
11
47
|
|
|
12
48
|
// 工具路由规则
|
|
13
49
|
this.routingRules = {
|
|
@@ -27,7 +63,12 @@ export class SmartRouter {
|
|
|
27
63
|
'get_document_symbols',
|
|
28
64
|
'replace_lines',
|
|
29
65
|
'execute_command',
|
|
30
|
-
'execute_shell_command'
|
|
66
|
+
'execute_shell_command',
|
|
67
|
+
'connector_bridge_status',
|
|
68
|
+
'connector_sync_profile',
|
|
69
|
+
'connector_report_status',
|
|
70
|
+
'connector_discover_project_probe',
|
|
71
|
+
'connector_report_project_probe'
|
|
31
72
|
],
|
|
32
73
|
|
|
33
74
|
// 云端工具(需要网络或云端资源)
|
|
@@ -151,21 +192,26 @@ export class SmartRouter {
|
|
|
151
192
|
}
|
|
152
193
|
|
|
153
194
|
try {
|
|
195
|
+
const body = JSON.stringify({
|
|
196
|
+
jsonrpc: '2.0',
|
|
197
|
+
id: Date.now(),
|
|
198
|
+
method: 'tools/call',
|
|
199
|
+
params: {
|
|
200
|
+
name: toolName,
|
|
201
|
+
arguments: params
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
const signedHeaders = this.deviceIdentity
|
|
205
|
+
? await this.deviceIdentity.buildSignedHeaders({ method: 'POST', pathname: '/mcp', body })
|
|
206
|
+
: {};
|
|
154
207
|
const response = await fetch(`${this.cloudUrl}/mcp`, {
|
|
155
208
|
method: 'POST',
|
|
156
209
|
headers: {
|
|
157
210
|
'Authorization': `Bearer ${this.cloudApiKey}`,
|
|
158
|
-
'Content-Type': 'application/json'
|
|
211
|
+
'Content-Type': 'application/json',
|
|
212
|
+
...signedHeaders
|
|
159
213
|
},
|
|
160
|
-
body
|
|
161
|
-
jsonrpc: '2.0',
|
|
162
|
-
id: Date.now(),
|
|
163
|
-
method: 'tools/call',
|
|
164
|
-
params: {
|
|
165
|
-
name: toolName,
|
|
166
|
-
arguments: params
|
|
167
|
-
}
|
|
168
|
-
})
|
|
214
|
+
body
|
|
169
215
|
});
|
|
170
216
|
|
|
171
217
|
if (!response.ok) {
|
|
@@ -184,15 +230,13 @@ export class SmartRouter {
|
|
|
184
230
|
errorMessage = errorMessage.message || JSON.stringify(errorMessage, null, 2);
|
|
185
231
|
}
|
|
186
232
|
|
|
187
|
-
|
|
233
|
+
const safeErrorMessage = sanitizeProxyError(errorMessage, params);
|
|
188
234
|
console.error(`[SmartRouter] Cloud tool error for ${toolName}:`, {
|
|
189
235
|
code: result.error.code,
|
|
190
|
-
message:
|
|
191
|
-
data: result.error.data,
|
|
192
|
-
fullError: result.error
|
|
236
|
+
message: safeErrorMessage
|
|
193
237
|
});
|
|
194
238
|
|
|
195
|
-
throw new Error(
|
|
239
|
+
throw new Error(safeErrorMessage);
|
|
196
240
|
}
|
|
197
241
|
|
|
198
242
|
// 提取结果内容
|
|
@@ -218,19 +262,17 @@ export class SmartRouter {
|
|
|
218
262
|
return result;
|
|
219
263
|
}
|
|
220
264
|
} catch (error) {
|
|
221
|
-
|
|
265
|
+
const safeErrorMessage = sanitizeProxyError(error, params);
|
|
222
266
|
console.error(`[SmartRouter] Error calling cloud tool ${toolName}:`, {
|
|
223
|
-
error:
|
|
224
|
-
stack: error.stack,
|
|
225
|
-
params: params
|
|
267
|
+
error: safeErrorMessage
|
|
226
268
|
});
|
|
227
269
|
|
|
228
270
|
// 如果错误信息已经包含 "Cloud tool call failed",直接抛出
|
|
229
271
|
// 否则添加前缀
|
|
230
|
-
if (
|
|
231
|
-
throw
|
|
272
|
+
if (safeErrorMessage.includes('Cloud tool call failed')) {
|
|
273
|
+
throw new Error(safeErrorMessage);
|
|
232
274
|
}
|
|
233
|
-
throw new Error(`Cloud tool call failed: ${
|
|
275
|
+
throw new Error(`Cloud tool call failed: ${safeErrorMessage}`);
|
|
234
276
|
}
|
|
235
277
|
}
|
|
236
278
|
|
|
@@ -263,18 +305,23 @@ export class SmartRouter {
|
|
|
263
305
|
*/
|
|
264
306
|
async getCloudTools() {
|
|
265
307
|
try {
|
|
308
|
+
const body = JSON.stringify({
|
|
309
|
+
jsonrpc: '2.0',
|
|
310
|
+
id: Date.now(),
|
|
311
|
+
method: 'tools/list',
|
|
312
|
+
params: {}
|
|
313
|
+
});
|
|
314
|
+
const signedHeaders = this.deviceIdentity
|
|
315
|
+
? await this.deviceIdentity.buildSignedHeaders({ method: 'POST', pathname: '/mcp', body })
|
|
316
|
+
: {};
|
|
266
317
|
const response = await fetch(`${this.cloudUrl}/mcp`, {
|
|
267
318
|
method: 'POST',
|
|
268
319
|
headers: {
|
|
269
320
|
'Authorization': `Bearer ${this.cloudApiKey}`,
|
|
270
|
-
'Content-Type': 'application/json'
|
|
321
|
+
'Content-Type': 'application/json',
|
|
322
|
+
...signedHeaders
|
|
271
323
|
},
|
|
272
|
-
body
|
|
273
|
-
jsonrpc: '2.0',
|
|
274
|
-
id: Date.now(),
|
|
275
|
-
method: 'tools/list',
|
|
276
|
-
params: {}
|
|
277
|
-
})
|
|
324
|
+
body
|
|
278
325
|
});
|
|
279
326
|
|
|
280
327
|
if (!response.ok) {
|
|
@@ -294,4 +341,3 @@ export class SmartRouter {
|
|
|
294
341
|
}
|
|
295
342
|
}
|
|
296
343
|
}
|
|
297
|
-
|
package/package-personal.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cloudflare-mcp-smart-proxy",
|
|
3
|
-
"version": "1.1.1",
|
|
4
|
-
"description": "Smart proxy for Cloudflare MCP - routes tools to cloud or local execution",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"cloudflare-mcp-proxy": "./index.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"start": "node index.js"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"mcp",
|
|
15
|
-
"cloudflare",
|
|
16
|
-
"proxy",
|
|
17
|
-
"local",
|
|
18
|
-
"filesystem"
|
|
19
|
-
],
|
|
20
|
-
"author": "",
|
|
21
|
-
"license": "MIT",
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
24
|
-
},
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=18.0.0"
|
|
27
|
-
}
|
|
28
|
-
}
|
package/publish-now.sh
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# 快速发布脚本 - 自动版本管理
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
cd "$(dirname "$0")"
|
|
8
|
-
|
|
9
|
-
echo "📦 发布 Cloudflare MCP Smart Proxy"
|
|
10
|
-
echo "=================================="
|
|
11
|
-
echo ""
|
|
12
|
-
|
|
13
|
-
# 读取当前版本
|
|
14
|
-
CURRENT_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "1.0.0")
|
|
15
|
-
echo "当前版本: $CURRENT_VERSION"
|
|
16
|
-
|
|
17
|
-
# 检查 npm 上已发布的版本
|
|
18
|
-
PUBLISHED_VERSION=$(npm view cloudflare-mcp-smart-proxy version 2>/dev/null || echo "0.0.0")
|
|
19
|
-
echo "npm 上最新版本: $PUBLISHED_VERSION"
|
|
20
|
-
|
|
21
|
-
# 如果当前版本已发布,自动递增
|
|
22
|
-
if [ "$CURRENT_VERSION" == "$PUBLISHED_VERSION" ]; then
|
|
23
|
-
echo ""
|
|
24
|
-
echo "⚠️ 当前版本 $CURRENT_VERSION 已发布,需要升级版本"
|
|
25
|
-
echo ""
|
|
26
|
-
echo "选择版本升级类型:"
|
|
27
|
-
echo "1. patch (1.0.0 -> 1.0.1) - 修复 bug"
|
|
28
|
-
echo "2. minor (1.0.0 -> 1.1.0) - 新功能"
|
|
29
|
-
echo "3. major (1.0.0 -> 2.0.0) - 重大变更"
|
|
30
|
-
echo "4. 手动指定版本号"
|
|
31
|
-
echo ""
|
|
32
|
-
read -p "请选择 (1/2/3/4) [默认: 1]: " version_choice
|
|
33
|
-
version_choice=${version_choice:-1}
|
|
34
|
-
|
|
35
|
-
case $version_choice in
|
|
36
|
-
1)
|
|
37
|
-
NEW_VERSION=$(node -e "
|
|
38
|
-
const v = '$CURRENT_VERSION'.split('.');
|
|
39
|
-
v[2] = parseInt(v[2] || 0) + 1;
|
|
40
|
-
console.log(v.join('.'));
|
|
41
|
-
")
|
|
42
|
-
;;
|
|
43
|
-
2)
|
|
44
|
-
NEW_VERSION=$(node -e "
|
|
45
|
-
const v = '$CURRENT_VERSION'.split('.');
|
|
46
|
-
v[1] = parseInt(v[1] || 0) + 1;
|
|
47
|
-
v[2] = 0;
|
|
48
|
-
console.log(v.join('.'));
|
|
49
|
-
")
|
|
50
|
-
;;
|
|
51
|
-
3)
|
|
52
|
-
NEW_VERSION=$(node -e "
|
|
53
|
-
const v = '$CURRENT_VERSION'.split('.');
|
|
54
|
-
v[0] = parseInt(v[0] || 0) + 1;
|
|
55
|
-
v[1] = 0;
|
|
56
|
-
v[2] = 0;
|
|
57
|
-
console.log(v.join('.'));
|
|
58
|
-
")
|
|
59
|
-
;;
|
|
60
|
-
4)
|
|
61
|
-
read -p "请输入新版本号 (例如: 1.0.2): " NEW_VERSION
|
|
62
|
-
if [ -z "$NEW_VERSION" ]; then
|
|
63
|
-
echo "❌ 版本号不能为空"
|
|
64
|
-
exit 1
|
|
65
|
-
fi
|
|
66
|
-
;;
|
|
67
|
-
*)
|
|
68
|
-
echo "❌ 无效选择"
|
|
69
|
-
exit 1
|
|
70
|
-
;;
|
|
71
|
-
esac
|
|
72
|
-
|
|
73
|
-
echo ""
|
|
74
|
-
echo "将升级版本: $CURRENT_VERSION -> $NEW_VERSION"
|
|
75
|
-
read -p "确认升级?(y/n) " -n 1 -r
|
|
76
|
-
echo ""
|
|
77
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
78
|
-
echo "❌ 取消"
|
|
79
|
-
exit 1
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
# 更新所有 package 文件的版本号
|
|
83
|
-
echo "更新版本号..."
|
|
84
|
-
|
|
85
|
-
# 更新 package.json
|
|
86
|
-
node -e "
|
|
87
|
-
const fs = require('fs');
|
|
88
|
-
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
|
89
|
-
pkg.version = '$NEW_VERSION';
|
|
90
|
-
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
# 更新 package-personal.json
|
|
94
|
-
if [ -f "package-personal.json" ]; then
|
|
95
|
-
node -e "
|
|
96
|
-
const fs = require('fs');
|
|
97
|
-
const pkg = JSON.parse(fs.readFileSync('package-personal.json', 'utf-8'));
|
|
98
|
-
pkg.version = '$NEW_VERSION';
|
|
99
|
-
fs.writeFileSync('package-personal.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
100
|
-
"
|
|
101
|
-
fi
|
|
102
|
-
|
|
103
|
-
echo "✅ 版本号已更新为: $NEW_VERSION"
|
|
104
|
-
CURRENT_VERSION=$NEW_VERSION
|
|
105
|
-
echo ""
|
|
106
|
-
fi
|
|
107
|
-
|
|
108
|
-
# 检查登录
|
|
109
|
-
if ! npm whoami &> /dev/null; then
|
|
110
|
-
echo "⚠️ 需要先登录 npm"
|
|
111
|
-
echo ""
|
|
112
|
-
echo "运行: npm login"
|
|
113
|
-
echo ""
|
|
114
|
-
read -p "是否现在登录?(y/n) " -n 1 -r
|
|
115
|
-
echo ""
|
|
116
|
-
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
117
|
-
npm login
|
|
118
|
-
else
|
|
119
|
-
echo "❌ 取消"
|
|
120
|
-
exit 1
|
|
121
|
-
fi
|
|
122
|
-
fi
|
|
123
|
-
|
|
124
|
-
echo "✅ 已登录为: $(npm whoami)"
|
|
125
|
-
echo ""
|
|
126
|
-
|
|
127
|
-
# 选择发布方式
|
|
128
|
-
echo "选择发布方式:"
|
|
129
|
-
echo "1. 组织包 (@cloudflare-mcp/smart-proxy) - 需要组织权限"
|
|
130
|
-
echo "2. 个人包 (cloudflare-mcp-smart-proxy) - 无需组织权限"
|
|
131
|
-
echo ""
|
|
132
|
-
read -p "请选择 (1/2) [默认: 2]: " choice
|
|
133
|
-
choice=${choice:-2}
|
|
134
|
-
|
|
135
|
-
if [ "$choice" == "1" ]; then
|
|
136
|
-
PACKAGE_NAME="@cloudflare-mcp/smart-proxy"
|
|
137
|
-
echo "使用组织包名: $PACKAGE_NAME"
|
|
138
|
-
echo "⚠️ 需要 @cloudflare-mcp 组织权限"
|
|
139
|
-
else
|
|
140
|
-
PACKAGE_NAME="cloudflare-mcp-smart-proxy"
|
|
141
|
-
echo "使用个人包名: $PACKAGE_NAME"
|
|
142
|
-
|
|
143
|
-
# 备份原 package.json
|
|
144
|
-
if [ -f "package.json" ]; then
|
|
145
|
-
cp package.json package.json.backup
|
|
146
|
-
echo "✅ 已备份 package.json"
|
|
147
|
-
fi
|
|
148
|
-
|
|
149
|
-
# 使用个人包名,但保持当前版本号
|
|
150
|
-
node -e "
|
|
151
|
-
const fs = require('fs');
|
|
152
|
-
const currentPkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
|
153
|
-
const personalPkg = JSON.parse(fs.readFileSync('package-personal.json', 'utf-8'));
|
|
154
|
-
|
|
155
|
-
// 使用个人包名,但保持当前版本号
|
|
156
|
-
personalPkg.version = currentPkg.version;
|
|
157
|
-
fs.writeFileSync('package.json', JSON.stringify(personalPkg, null, 2) + '\n');
|
|
158
|
-
"
|
|
159
|
-
echo "✅ 已切换到个人包名(版本: $CURRENT_VERSION)"
|
|
160
|
-
fi
|
|
161
|
-
|
|
162
|
-
echo ""
|
|
163
|
-
read -p "确认发布?(y/n) " -n 1 -r
|
|
164
|
-
echo ""
|
|
165
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
166
|
-
echo "❌ 取消"
|
|
167
|
-
# 恢复原配置
|
|
168
|
-
if [ -f "package.json.backup" ]; then
|
|
169
|
-
mv package.json.backup package.json
|
|
170
|
-
fi
|
|
171
|
-
exit 1
|
|
172
|
-
fi
|
|
173
|
-
|
|
174
|
-
echo ""
|
|
175
|
-
echo "🚀 发布中..."
|
|
176
|
-
echo ""
|
|
177
|
-
echo "📱 如果启用 2FA,npm 会自动打开浏览器进行认证"
|
|
178
|
-
echo " 请按 ENTER 键打开浏览器(如果提示)"
|
|
179
|
-
echo ""
|
|
180
|
-
|
|
181
|
-
# 尝试发布,如果需要 2FA,npm 会自动打开浏览器
|
|
182
|
-
# macOS 保存的 2FA 会通过浏览器自动完成认证
|
|
183
|
-
npm publish --access public
|
|
184
|
-
|
|
185
|
-
if [ $? -eq 0 ]; then
|
|
186
|
-
echo ""
|
|
187
|
-
echo "=================================="
|
|
188
|
-
echo "✅ 发布成功!"
|
|
189
|
-
echo ""
|
|
190
|
-
echo "包地址: https://www.npmjs.com/package/$PACKAGE_NAME"
|
|
191
|
-
echo "版本: $CURRENT_VERSION"
|
|
192
|
-
echo ""
|
|
193
|
-
|
|
194
|
-
# 如果版本已更新,同步到 package-personal.json
|
|
195
|
-
if [ -f "package-personal.json" ] && [ "$choice" == "2" ]; then
|
|
196
|
-
node -e "
|
|
197
|
-
const fs = require('fs');
|
|
198
|
-
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
|
199
|
-
const personalPkg = JSON.parse(fs.readFileSync('package-personal.json', 'utf-8'));
|
|
200
|
-
personalPkg.version = pkg.version;
|
|
201
|
-
fs.writeFileSync('package-personal.json', JSON.stringify(personalPkg, null, 2) + '\n');
|
|
202
|
-
"
|
|
203
|
-
echo "✅ 已同步版本号到 package-personal.json"
|
|
204
|
-
fi
|
|
205
|
-
echo ""
|
|
206
|
-
echo "安装方式:"
|
|
207
|
-
if [ "$choice" == "1" ]; then
|
|
208
|
-
echo " npx -y @cloudflare-mcp/smart-proxy"
|
|
209
|
-
else
|
|
210
|
-
echo " npx -y cloudflare-mcp-smart-proxy"
|
|
211
|
-
echo ""
|
|
212
|
-
echo "⚠️ 注意: 如果使用个人包名,需要更新 CURSOR_配置示例.json 中的包名"
|
|
213
|
-
fi
|
|
214
|
-
echo ""
|
|
215
|
-
|
|
216
|
-
# 恢复原配置
|
|
217
|
-
if [ -f "package.json.backup" ]; then
|
|
218
|
-
mv package.json.backup package.json
|
|
219
|
-
echo "✅ 已恢复原 package.json"
|
|
220
|
-
fi
|
|
221
|
-
else
|
|
222
|
-
echo ""
|
|
223
|
-
echo "❌ 发布失败"
|
|
224
|
-
# 恢复原配置
|
|
225
|
-
if [ -f "package.json.backup" ]; then
|
|
226
|
-
mv package.json.backup package.json
|
|
227
|
-
fi
|
|
228
|
-
exit 1
|
|
229
|
-
fi
|
|
230
|
-
|
package/publish-with-2fa.sh
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# 发布脚本 - 带 2FA 检查
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
cd "$(dirname "$0")"
|
|
8
|
-
|
|
9
|
-
echo "📦 发布 Cloudflare MCP Smart Proxy"
|
|
10
|
-
echo "=================================="
|
|
11
|
-
echo ""
|
|
12
|
-
|
|
13
|
-
# 检查登录
|
|
14
|
-
if ! npm whoami &> /dev/null; then
|
|
15
|
-
echo "⚠️ 需要先登录 npm"
|
|
16
|
-
npm login
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
echo "✅ 已登录为: $(npm whoami)"
|
|
20
|
-
echo ""
|
|
21
|
-
|
|
22
|
-
# 检查 2FA 状态
|
|
23
|
-
echo "检查 2FA 状态..."
|
|
24
|
-
PROFILE=$(npm profile get 2>&1)
|
|
25
|
-
if echo "$PROFILE" | grep -q '"twoFactor":"auth-and-writes"'; then
|
|
26
|
-
echo "✅ 2FA 已启用(发布权限)"
|
|
27
|
-
elif echo "$PROFILE" | grep -q '"twoFactor":"auth-only"'; then
|
|
28
|
-
echo "⚠️ 2FA 已启用,但可能没有发布权限"
|
|
29
|
-
echo " 请访问: https://www.npmjs.com/settings/$(npm whoami)/two-factor"
|
|
30
|
-
echo " 确保选择了 'Authorization and Publishing'"
|
|
31
|
-
read -p "继续发布?(y/n) " -n 1 -r
|
|
32
|
-
echo ""
|
|
33
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
34
|
-
exit 1
|
|
35
|
-
fi
|
|
36
|
-
else
|
|
37
|
-
echo "❌ 2FA 未启用"
|
|
38
|
-
echo ""
|
|
39
|
-
echo "npm 现在要求启用 2FA 才能发布包。"
|
|
40
|
-
echo ""
|
|
41
|
-
echo "请执行以下步骤:"
|
|
42
|
-
echo "1. 访问: https://www.npmjs.com/settings/$(npm whoami)/two-factor"
|
|
43
|
-
echo "2. 启用 2FA,选择 'Authorization and Publishing'"
|
|
44
|
-
echo "3. 使用手机应用(如 Google Authenticator)扫描二维码"
|
|
45
|
-
echo "4. 完成后重新运行此脚本"
|
|
46
|
-
echo ""
|
|
47
|
-
read -p "是否已启用 2FA?(y/n) " -n 1 -r
|
|
48
|
-
echo ""
|
|
49
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
50
|
-
echo "请先启用 2FA,然后重新运行此脚本"
|
|
51
|
-
exit 1
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# 重新登录以启用 2FA
|
|
55
|
-
echo "重新登录以应用 2FA..."
|
|
56
|
-
npm logout
|
|
57
|
-
npm login
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
echo ""
|
|
61
|
-
|
|
62
|
-
# 选择发布方式
|
|
63
|
-
echo "选择发布方式:"
|
|
64
|
-
echo "1. 组织包 (@cloudflare-mcp/smart-proxy) - 需要组织权限"
|
|
65
|
-
echo "2. 个人包 (cloudflare-mcp-smart-proxy) - 无需组织权限"
|
|
66
|
-
echo ""
|
|
67
|
-
read -p "请选择 (1/2) [默认: 2]: " choice
|
|
68
|
-
choice=${choice:-2}
|
|
69
|
-
|
|
70
|
-
if [ "$choice" == "1" ]; then
|
|
71
|
-
PACKAGE_NAME="@cloudflare-mcp/smart-proxy"
|
|
72
|
-
echo "使用组织包名: $PACKAGE_NAME"
|
|
73
|
-
echo "⚠️ 需要 @cloudflare-mcp 组织权限"
|
|
74
|
-
else
|
|
75
|
-
PACKAGE_NAME="cloudflare-mcp-smart-proxy"
|
|
76
|
-
echo "使用个人包名: $PACKAGE_NAME"
|
|
77
|
-
|
|
78
|
-
# 备份原 package.json
|
|
79
|
-
if [ -f "package.json" ] && ! grep -q "cloudflare-mcp-smart-proxy" package.json; then
|
|
80
|
-
cp package.json package.json.backup
|
|
81
|
-
echo "✅ 已备份 package.json"
|
|
82
|
-
|
|
83
|
-
# 使用个人包名
|
|
84
|
-
cp package-personal.json package.json
|
|
85
|
-
echo "✅ 已切换到个人包名"
|
|
86
|
-
fi
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
echo ""
|
|
90
|
-
read -p "确认发布?(y/n) " -n 1 -r
|
|
91
|
-
echo ""
|
|
92
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
93
|
-
echo "❌ 取消"
|
|
94
|
-
# 恢复原配置
|
|
95
|
-
if [ -f "package.json.backup" ]; then
|
|
96
|
-
mv package.json.backup package.json
|
|
97
|
-
fi
|
|
98
|
-
exit 1
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
echo ""
|
|
102
|
-
echo "🚀 发布中..."
|
|
103
|
-
npm publish --access public
|
|
104
|
-
|
|
105
|
-
if [ $? -eq 0 ]; then
|
|
106
|
-
echo ""
|
|
107
|
-
echo "=================================="
|
|
108
|
-
echo "✅ 发布成功!"
|
|
109
|
-
echo ""
|
|
110
|
-
echo "包地址: https://www.npmjs.com/package/$PACKAGE_NAME"
|
|
111
|
-
echo ""
|
|
112
|
-
echo "安装方式:"
|
|
113
|
-
if [ "$choice" == "1" ]; then
|
|
114
|
-
echo " npx -y @cloudflare-mcp/smart-proxy"
|
|
115
|
-
else
|
|
116
|
-
echo " npx -y cloudflare-mcp-smart-proxy"
|
|
117
|
-
fi
|
|
118
|
-
echo ""
|
|
119
|
-
|
|
120
|
-
# 恢复原配置
|
|
121
|
-
if [ -f "package.json.backup" ]; then
|
|
122
|
-
mv package.json.backup package.json
|
|
123
|
-
echo "✅ 已恢复原 package.json"
|
|
124
|
-
fi
|
|
125
|
-
else
|
|
126
|
-
echo ""
|
|
127
|
-
echo "❌ 发布失败"
|
|
128
|
-
# 恢复原配置
|
|
129
|
-
if [ -f "package.json.backup" ]; then
|
|
130
|
-
mv package.json.backup package.json
|
|
131
|
-
fi
|
|
132
|
-
exit 1
|
|
133
|
-
fi
|
|
134
|
-
|
package/publish.sh
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# 发布脚本 - 发布 @cloudflare-mcp/smart-proxy 到 npm
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
echo "📦 准备发布 cloudflare-mcp-smart-proxy 到 npm"
|
|
8
|
-
echo "=============================================="
|
|
9
|
-
echo ""
|
|
10
|
-
|
|
11
|
-
# 检查是否在正确的目录
|
|
12
|
-
if [ ! -f "package.json" ]; then
|
|
13
|
-
echo "❌ 错误: 请在 local-proxy 目录中运行此脚本"
|
|
14
|
-
exit 1
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# 检查 npm 是否安装
|
|
18
|
-
if ! command -v npm &> /dev/null; then
|
|
19
|
-
echo "❌ 错误: 需要安装 npm"
|
|
20
|
-
exit 1
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
echo "✅ npm 版本: $(npm -v)"
|
|
24
|
-
echo ""
|
|
25
|
-
|
|
26
|
-
# 检查是否登录
|
|
27
|
-
echo "检查 npm 登录状态..."
|
|
28
|
-
if ! npm whoami &> /dev/null; then
|
|
29
|
-
echo "⚠️ 未登录 npm,请先登录:"
|
|
30
|
-
echo ""
|
|
31
|
-
echo "运行: npm login"
|
|
32
|
-
echo ""
|
|
33
|
-
read -p "是否现在登录?(y/n) " -n 1 -r
|
|
34
|
-
echo ""
|
|
35
|
-
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
36
|
-
npm login
|
|
37
|
-
else
|
|
38
|
-
echo "❌ 取消发布"
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
else
|
|
42
|
-
echo "✅ 已登录为: $(npm whoami)"
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
echo ""
|
|
46
|
-
|
|
47
|
-
# 检查包名
|
|
48
|
-
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
49
|
-
echo "包名: $PACKAGE_NAME"
|
|
50
|
-
|
|
51
|
-
# 检查版本
|
|
52
|
-
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
53
|
-
echo "当前版本: $CURRENT_VERSION"
|
|
54
|
-
echo ""
|
|
55
|
-
|
|
56
|
-
# 确认发布
|
|
57
|
-
read -p "确认发布到 npm?(y/n) " -n 1 -r
|
|
58
|
-
echo ""
|
|
59
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
60
|
-
echo "❌ 取消发布"
|
|
61
|
-
exit 1
|
|
62
|
-
fi
|
|
63
|
-
|
|
64
|
-
# 运行测试(如果有)
|
|
65
|
-
if [ -f "package.json" ] && grep -q '"test"' package.json; then
|
|
66
|
-
echo "运行测试..."
|
|
67
|
-
npm test || echo "⚠️ 测试失败,但继续发布..."
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
# 发布
|
|
71
|
-
echo ""
|
|
72
|
-
echo "🚀 发布中..."
|
|
73
|
-
npm publish --access public
|
|
74
|
-
|
|
75
|
-
if [ $? -eq 0 ]; then
|
|
76
|
-
echo ""
|
|
77
|
-
echo "=============================================="
|
|
78
|
-
echo "✅ 发布成功!"
|
|
79
|
-
echo ""
|
|
80
|
-
echo "包地址: https://www.npmjs.com/package/$PACKAGE_NAME"
|
|
81
|
-
echo ""
|
|
82
|
-
echo "安装方式:"
|
|
83
|
-
echo " npx -y $PACKAGE_NAME"
|
|
84
|
-
echo ""
|
|
85
|
-
else
|
|
86
|
-
echo ""
|
|
87
|
-
echo "❌ 发布失败"
|
|
88
|
-
exit 1
|
|
89
|
-
fi
|
|
90
|
-
|