@szc-ft/mcp-szcd-client 0.13.1 → 0.14.0
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/commands/szcd-mcp-api-config.md +48 -0
- package/package.json +4 -2
- package/qwen-extension/commands/szcd-mcp-api-config.md +48 -0
- package/qwen-extension/qwen-extension.json +1 -1
- package/qwen-extension/skills/szcd-component-helper/SKILL.md +231 -563
- package/scripts/lib/claude-code.js +15 -11
- package/scripts/lib/common.js +29 -5
- package/scripts/lib/qoder.js +15 -11
- package/scripts/lib/trae-cli.js +15 -11
- package/scripts/lib/trae-ide.js +59 -11
- package/scripts/lib/trae.js +3 -1
- package/scripts/postinstall.js +6 -4
- package/scripts/update-api-config.js +272 -0
- package/standard-skill/szcd-component-helper/SKILL.md +439 -0
- package/skill/SKILL.md +0 -827
- package/standard-skill/SKILL.md +0 -1509
|
@@ -131,7 +131,6 @@ function createClaudeCodeProjectConfig(deps) {
|
|
|
131
131
|
// ==================== Skill 复制 ====================
|
|
132
132
|
|
|
133
133
|
function copySkillToClaudeCode(deps, isProjectLevel = false) {
|
|
134
|
-
const skillName = deps.getMcpServerName();
|
|
135
134
|
let claudeSkillsDir;
|
|
136
135
|
|
|
137
136
|
if (isProjectLevel) {
|
|
@@ -140,18 +139,23 @@ function copySkillToClaudeCode(deps, isProjectLevel = false) {
|
|
|
140
139
|
claudeSkillsDir = getClaudeCodeSkillsDirectory();
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
const
|
|
142
|
+
const skills = deps.discoverSkills();
|
|
143
|
+
let allOk = true;
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
for (const skill of skills) {
|
|
146
|
+
const skillDir = path.join(claudeSkillsDir, skill.name);
|
|
147
|
+
try {
|
|
148
|
+
deps.ensureDirectory(skillDir);
|
|
149
|
+
const skillDest = path.join(skillDir, "SKILL.md");
|
|
150
|
+
deps.copyFile(skill.sourcePath, skillDest);
|
|
151
|
+
console.log(`✓ Copied skill "${skill.name}" to Claude Code ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.log(`⚠️ Failed to copy skill "${skill.name}" to Claude Code ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
|
|
154
|
+
allOk = false;
|
|
155
|
+
}
|
|
154
156
|
}
|
|
157
|
+
|
|
158
|
+
return allOk;
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
// ==================== Agent 安装 ====================
|
package/scripts/lib/common.js
CHANGED
|
@@ -14,8 +14,36 @@ import { execSync } from "node:child_process";
|
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname = path.dirname(__filename);
|
|
16
16
|
|
|
17
|
+
// 默认值(需在 SKILL_SOURCE 之前定义)
|
|
18
|
+
export const DEFAULT_MCP_SERVER_URL = "http://localhost:3456";
|
|
19
|
+
export const DEFAULT_MCP_SERVER_NAME = "szcd-component-helper";
|
|
20
|
+
|
|
17
21
|
export const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
|
|
18
|
-
export const
|
|
22
|
+
export const SKILLS_DIR = path.join(PACKAGE_ROOT, "standard-skill");
|
|
23
|
+
|
|
24
|
+
// 向后兼容:保留 SKILL_SOURCE 指向主技能包
|
|
25
|
+
export const SKILL_SOURCE = path.join(SKILLS_DIR, DEFAULT_MCP_SERVER_NAME, "SKILL.md");
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 扫描 standard-skill/ 目录下所有子目录,发现可安装的技能包。
|
|
29
|
+
* 目录结构约定:standard-skill/<skill-name>/SKILL.md
|
|
30
|
+
* 返回 [{ name, sourcePath }] 数组
|
|
31
|
+
*/
|
|
32
|
+
export function discoverSkills() {
|
|
33
|
+
const skills = [];
|
|
34
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
35
|
+
console.warn(`⚠️ Skills directory not found: ${SKILLS_DIR}`);
|
|
36
|
+
return skills;
|
|
37
|
+
}
|
|
38
|
+
for (const entry of fs.readdirSync(SKILLS_DIR, { withFileTypes: true })) {
|
|
39
|
+
if (!entry.isDirectory()) continue;
|
|
40
|
+
const skillFile = path.join(SKILLS_DIR, entry.name, "SKILL.md");
|
|
41
|
+
if (fs.existsSync(skillFile)) {
|
|
42
|
+
skills.push({ name: entry.name, sourcePath: skillFile });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return skills;
|
|
46
|
+
}
|
|
19
47
|
|
|
20
48
|
// 项目根目录:从 PACKAGE_ROOT 向上推导
|
|
21
49
|
export function findProjectRoot() {
|
|
@@ -32,10 +60,6 @@ export function findProjectRoot() {
|
|
|
32
60
|
}
|
|
33
61
|
export const PROJECT_ROOT = findProjectRoot();
|
|
34
62
|
|
|
35
|
-
// 默认值
|
|
36
|
-
export const DEFAULT_MCP_SERVER_URL = "http://localhost:3456";
|
|
37
|
-
export const DEFAULT_MCP_SERVER_NAME = "szcd-component-helper";
|
|
38
|
-
|
|
39
63
|
// ==================== 安全保护 ====================
|
|
40
64
|
|
|
41
65
|
export const RECURSION_GUARD_ENV = "SZCD_POSTINSTALL_RUNNING";
|
package/scripts/lib/qoder.js
CHANGED
|
@@ -171,7 +171,6 @@ function syncQoderSettings(deps) {
|
|
|
171
171
|
// ==================== Skill 复制 ====================
|
|
172
172
|
|
|
173
173
|
function copySkillToQoder(deps, isProjectLevel = false) {
|
|
174
|
-
const skillName = deps.getMcpServerName();
|
|
175
174
|
let qoderSkillsDir;
|
|
176
175
|
|
|
177
176
|
if (isProjectLevel) {
|
|
@@ -180,18 +179,23 @@ function copySkillToQoder(deps, isProjectLevel = false) {
|
|
|
180
179
|
qoderSkillsDir = getQoderSkillsDirectory();
|
|
181
180
|
}
|
|
182
181
|
|
|
183
|
-
const
|
|
182
|
+
const skills = deps.discoverSkills();
|
|
183
|
+
let allOk = true;
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
185
|
+
for (const skill of skills) {
|
|
186
|
+
const skillDir = path.join(qoderSkillsDir, skill.name);
|
|
187
|
+
try {
|
|
188
|
+
deps.ensureDirectory(skillDir);
|
|
189
|
+
const skillDest = path.join(skillDir, "SKILL.md");
|
|
190
|
+
deps.copyFile(skill.sourcePath, skillDest);
|
|
191
|
+
console.log(`✓ Copied skill "${skill.name}" to Qoder ${isProjectLevel ? "project" : "user"} directory: ${skillDir}`);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.log(`⚠️ Failed to copy skill "${skill.name}" to Qoder ${isProjectLevel ? "project" : "user"} directory: ${error.message}`);
|
|
194
|
+
allOk = false;
|
|
195
|
+
}
|
|
194
196
|
}
|
|
197
|
+
|
|
198
|
+
return allOk;
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
// ==================== Agent 安装 ====================
|
package/scripts/lib/trae-cli.js
CHANGED
|
@@ -169,7 +169,6 @@ export function getTraeCliSkillsDirectory() {
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
export function copySkillToTraeCli(deps, isProjectLevel = false) {
|
|
172
|
-
const skillName = deps.getMcpServerName();
|
|
173
172
|
let traeCliSkillsDir;
|
|
174
173
|
|
|
175
174
|
if (isProjectLevel) {
|
|
@@ -178,18 +177,23 @@ export function copySkillToTraeCli(deps, isProjectLevel = false) {
|
|
|
178
177
|
traeCliSkillsDir = getTraeCliSkillsDirectory();
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
const
|
|
180
|
+
const skills = deps.discoverSkills();
|
|
181
|
+
let allOk = true;
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
183
|
+
for (const skill of skills) {
|
|
184
|
+
const skillDir = path.join(traeCliSkillsDir, skill.name);
|
|
185
|
+
try {
|
|
186
|
+
deps.ensureDirectory(skillDir);
|
|
187
|
+
const skillDest = path.join(skillDir, "SKILL.md");
|
|
188
|
+
deps.copyFile(skill.sourcePath, skillDest);
|
|
189
|
+
console.log(`✓ Copied skill "${skill.name}" to Trae CLI ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.log(`⚠️ Failed to copy skill "${skill.name}" to Trae CLI ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
|
|
192
|
+
allOk = false;
|
|
193
|
+
}
|
|
192
194
|
}
|
|
195
|
+
|
|
196
|
+
return allOk;
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
// ==================== Slash Command 安装(Trae CLI) ====================
|
package/scripts/lib/trae-ide.js
CHANGED
|
@@ -146,7 +146,6 @@ export function syncMcpUrl(targetUrl, serverName) {
|
|
|
146
146
|
// ==================== Skill 复制 ====================
|
|
147
147
|
|
|
148
148
|
export function copySkillToTrae(deps, isProjectLevel = false) {
|
|
149
|
-
const skillName = deps.getMcpServerName();
|
|
150
149
|
let traeSkillsDir;
|
|
151
150
|
|
|
152
151
|
if (isProjectLevel) {
|
|
@@ -155,18 +154,23 @@ export function copySkillToTrae(deps, isProjectLevel = false) {
|
|
|
155
154
|
traeSkillsDir = getTraeSkillsDirectory();
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
const
|
|
157
|
+
const skills = deps.discoverSkills();
|
|
158
|
+
let allOk = true;
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
160
|
+
for (const skill of skills) {
|
|
161
|
+
const skillDir = path.join(traeSkillsDir, skill.name);
|
|
162
|
+
try {
|
|
163
|
+
deps.ensureDirectory(skillDir);
|
|
164
|
+
const skillDest = path.join(skillDir, "SKILL.md");
|
|
165
|
+
deps.copyFile(skill.sourcePath, skillDest);
|
|
166
|
+
console.log(`✓ Copied skill "${skill.name}" to Trae ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.log(`⚠️ Failed to copy skill "${skill.name}" to Trae ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
|
|
169
|
+
allOk = false;
|
|
170
|
+
}
|
|
169
171
|
}
|
|
172
|
+
|
|
173
|
+
return allOk;
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
// ==================== Agent 复制(Trae IDE) ====================
|
|
@@ -209,3 +213,47 @@ export function copyTraeIdeAgent(deps, isProjectLevel = false) {
|
|
|
209
213
|
return copied > 0;
|
|
210
214
|
}
|
|
211
215
|
|
|
216
|
+
// ==================== Slash Command 安装(Trae IDE) ====================
|
|
217
|
+
|
|
218
|
+
export function getTraeIdeCommandsDirectory() {
|
|
219
|
+
return path.join(getTraeUserDirectory(), "commands");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function installTraeIdeSlashCommand(deps) {
|
|
223
|
+
const commandsSourceDir = path.join(deps.PACKAGE_ROOT, "commands");
|
|
224
|
+
if (!fs.existsSync(commandsSourceDir)) {
|
|
225
|
+
console.log("⚠️ Commands source directory not found, skipping Trae IDE");
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const commandFiles = fs.readdirSync(commandsSourceDir).filter(f => f.endsWith(".md"));
|
|
230
|
+
if (commandFiles.length === 0) {
|
|
231
|
+
console.log("⚠️ No command files found, skipping Trae IDE");
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const traeIdeCommandsDir = getTraeIdeCommandsDirectory();
|
|
236
|
+
try {
|
|
237
|
+
deps.ensureDirectory(traeIdeCommandsDir);
|
|
238
|
+
for (const file of commandFiles) {
|
|
239
|
+
const commandSource = path.join(commandsSourceDir, file);
|
|
240
|
+
const commandDest = path.join(traeIdeCommandsDir, file);
|
|
241
|
+
|
|
242
|
+
// 如果目标已存在且内容不同,跳过(用户可能已修改)
|
|
243
|
+
if (fs.existsSync(commandDest)) {
|
|
244
|
+
const existingContent = fs.readFileSync(commandDest, "utf8").trim();
|
|
245
|
+
const sourceContent = fs.readFileSync(commandSource, "utf8").trim();
|
|
246
|
+
if (existingContent !== sourceContent) {
|
|
247
|
+
console.log(`⏭️ Skipping Trae IDE command ${file}: already exists (user modified)`);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
deps.copyFile(commandSource, commandDest);
|
|
253
|
+
console.log(`✓ Installed Trae IDE slash command: /${file.replace(".md", "")}`);
|
|
254
|
+
}
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.log(`⚠️ Failed to install Trae IDE slash commands: ${error.message}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
package/scripts/lib/trae.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 负责编排 Trae CLI 与 Trae IDE 的初始化流程。
|
|
5
5
|
* 具体逻辑已按方向拆离到:
|
|
6
6
|
* - trae-cli.js Trae CLI 专属逻辑(YAML、trae-cli 命令、.traecli/skills/agents/commands)
|
|
7
|
-
* - trae-ide.js Trae IDE 专属逻辑(mcp.json、.trae-cn/skills、.trae-cn/agents)
|
|
7
|
+
* - trae-ide.js Trae IDE 专属逻辑(mcp.json、.trae-cn/skills、.trae-cn/agents、.trae-cn/commands)
|
|
8
8
|
*
|
|
9
9
|
* 导出 setupTrae(deps) 供 postinstall.js 调用。
|
|
10
10
|
* deps 需包含: { getMcpServerUrl, getMcpServerName, safeExecSync, isCommandAvailable, ensureDirectory, copyFile, writeFile, SKILL_SOURCE, PROJECT_ROOT, PACKAGE_ROOT }
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
copySkillToTrae,
|
|
24
24
|
copyTraeIdeAgent,
|
|
25
25
|
getTraeAgentsDirectory,
|
|
26
|
+
installTraeIdeSlashCommand,
|
|
26
27
|
} from "./trae-ide.js";
|
|
27
28
|
|
|
28
29
|
// ==================== 导出 ====================
|
|
@@ -31,6 +32,7 @@ export function setupTrae(deps) {
|
|
|
31
32
|
// ---- Trae IDE ----
|
|
32
33
|
createTraeIdeConfig(deps);
|
|
33
34
|
copySkillToTrae(deps, false);
|
|
35
|
+
installTraeIdeSlashCommand(deps);
|
|
34
36
|
// IDE 暂不支持 agent,跳过
|
|
35
37
|
// copyTraeIdeAgent(deps, false);
|
|
36
38
|
|
package/scripts/postinstall.js
CHANGED
|
@@ -39,6 +39,7 @@ const deps = {
|
|
|
39
39
|
ensureDirectory: common.ensureDirectory,
|
|
40
40
|
copyFile: common.copyFile,
|
|
41
41
|
writeFile: common.writeFile,
|
|
42
|
+
discoverSkills: common.discoverSkills,
|
|
42
43
|
SKILL_SOURCE: common.SKILL_SOURCE,
|
|
43
44
|
PROJECT_ROOT: common.PROJECT_ROOT,
|
|
44
45
|
PACKAGE_ROOT: common.PACKAGE_ROOT,
|
|
@@ -158,11 +159,12 @@ function main() {
|
|
|
158
159
|
console.log("\n🔧 Setting up szcd-component-helper client...\n");
|
|
159
160
|
|
|
160
161
|
console.log(`📁 Package root: ${common.PACKAGE_ROOT}`);
|
|
161
|
-
console.log(`📄 Skill source: ${common.SKILL_SOURCE}`);
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
const discoveredSkills = common.discoverSkills();
|
|
164
|
+
if (discoveredSkills.length === 0) {
|
|
165
|
+
throw new Error(`No skills found in ${common.SKILLS_DIR}. Expected subdirectories with SKILL.md files.`);
|
|
165
166
|
}
|
|
167
|
+
console.log(`📄 Found ${discoveredSkills.length} skill(s): ${discoveredSkills.map(s => s.name).join(", ")}`);
|
|
166
168
|
|
|
167
169
|
// ---- 配置文件 ----
|
|
168
170
|
createConfigTemplate();
|
|
@@ -196,7 +198,7 @@ function main() {
|
|
|
196
198
|
console.error(`- Node version: ${process.version}`);
|
|
197
199
|
console.error(`- Platform: ${process.platform}`);
|
|
198
200
|
console.error(`- Package root: ${common.PACKAGE_ROOT}`);
|
|
199
|
-
console.error(`-
|
|
201
|
+
console.error(`- Skills directory: ${common.SKILLS_DIR}`);
|
|
200
202
|
process.exit(1);
|
|
201
203
|
}
|
|
202
204
|
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* szcd-mcp-api-config - 管理 API 工具(YApi + Swagger)的默认配置
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* npx szcd-mcp-api-config get 查看当前 API 配置
|
|
8
|
+
* npx szcd-mcp-api-config set --baseUrl=xxx 设置 YApi 基础地址
|
|
9
|
+
* npx szcd-mcp-api-config set --account=xxx 设置 YApi 登录账号
|
|
10
|
+
* npx szcd-mcp-api-config set --password=xxx 设置 YApi 密码
|
|
11
|
+
* npx szcd-mcp-api-config set --cookies=xxx 设置 YApi Cookie
|
|
12
|
+
* npx szcd-mcp-api-config set --swgUser=xxx 设置 Swagger 默认用户名
|
|
13
|
+
* npx szcd-mcp-api-config set --swgPass=xxx 设置 Swagger 默认密码
|
|
14
|
+
* npx szcd-mcp-api-config set --baseUrl=xxx --account=yyy --password=zzz 批量设置
|
|
15
|
+
* npx szcd-mcp-api-config clear 清除所有 API 配置
|
|
16
|
+
*
|
|
17
|
+
* 配置保存在 ~/.szcd-mcp-config.json 中,字段名:
|
|
18
|
+
* YAPI_BASE_URL — YApi 基础地址(如 http://yapi.smartcitysz.work)
|
|
19
|
+
* YAPI_ACCOUNT — YApi 登录账号/邮箱
|
|
20
|
+
* YAPI_PASSWORD — YApi 密码(敏感)
|
|
21
|
+
* YAPI_COOKIES — YApi Cookie 字符串(敏感,优先使用)
|
|
22
|
+
* SWAGGER_DEFAULT_USERNAME — Swagger 默认鉴权用户名
|
|
23
|
+
* SWAGGER_DEFAULT_PASSWORD — Swagger 默认鉴权密码(敏感,留空则跳过鉴权)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import fs from "node:fs";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import os from "node:os";
|
|
29
|
+
|
|
30
|
+
// ==================== 工具函数 ====================
|
|
31
|
+
|
|
32
|
+
function getHomeDir() {
|
|
33
|
+
if (os.platform() === "win32") {
|
|
34
|
+
return process.env.USERPROFILE || process.env.HOME || os.homedir();
|
|
35
|
+
}
|
|
36
|
+
return process.env.HOME || os.homedir();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getConfigFilePath() {
|
|
40
|
+
return path.join(getHomeDir(), ".szcd-mcp-config.json");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function loadConfig() {
|
|
44
|
+
const configPath = getConfigFilePath();
|
|
45
|
+
try {
|
|
46
|
+
if (fs.existsSync(configPath)) {
|
|
47
|
+
return JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(`Failed to read config: ${error.message}`);
|
|
51
|
+
}
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function saveConfig(config) {
|
|
56
|
+
const configPath = getConfigFilePath();
|
|
57
|
+
try {
|
|
58
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
59
|
+
return true;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error(`Failed to write config: ${error.message}`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function maskValue(value) {
|
|
67
|
+
if (!value) return "(未设置)";
|
|
68
|
+
if (value.length <= 6) return "***";
|
|
69
|
+
return value.substring(0, 4) + "***";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseArgs(argv) {
|
|
73
|
+
const args = {
|
|
74
|
+
action: null,
|
|
75
|
+
baseUrl: null,
|
|
76
|
+
account: null,
|
|
77
|
+
password: null,
|
|
78
|
+
cookies: null,
|
|
79
|
+
swgUser: null,
|
|
80
|
+
swgPass: null,
|
|
81
|
+
};
|
|
82
|
+
const positional = [];
|
|
83
|
+
|
|
84
|
+
for (let i = 2; i < argv.length; i++) {
|
|
85
|
+
const arg = argv[i];
|
|
86
|
+
if (arg.startsWith("--")) {
|
|
87
|
+
const eqIdx = arg.indexOf("=");
|
|
88
|
+
if (eqIdx !== -1) {
|
|
89
|
+
const key = arg.slice(2, eqIdx);
|
|
90
|
+
const value = arg.slice(eqIdx + 1);
|
|
91
|
+
if (key === "baseUrl" || key === "base-url") args.baseUrl = value;
|
|
92
|
+
if (key === "account") args.account = value;
|
|
93
|
+
if (key === "password") args.password = value;
|
|
94
|
+
if (key === "cookies") args.cookies = value;
|
|
95
|
+
if (key === "swgUser" || key === "swg-user") args.swgUser = value;
|
|
96
|
+
if (key === "swgPass" || key === "swg-pass") args.swgPass = value;
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
positional.push(arg);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
args.action = positional[0] || "get";
|
|
104
|
+
return args;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ==================== 命令实现 ====================
|
|
108
|
+
|
|
109
|
+
function cmdGet() {
|
|
110
|
+
const config = loadConfig();
|
|
111
|
+
|
|
112
|
+
console.log(`\nAPI 工具配置 (${getConfigFilePath()})\n`);
|
|
113
|
+
console.log(` [YApi]`);
|
|
114
|
+
console.log(` YAPI_BASE_URL : ${config.YAPI_BASE_URL || "(未设置)"}`);
|
|
115
|
+
console.log(` YAPI_ACCOUNT : ${config.YAPI_ACCOUNT || "(未设置)"}`);
|
|
116
|
+
console.log(` YAPI_PASSWORD : ${maskValue(config.YAPI_PASSWORD)}`);
|
|
117
|
+
console.log(` YAPI_COOKIES : ${maskValue(config.YAPI_COOKIES)}`);
|
|
118
|
+
console.log(`\n [Swagger]`);
|
|
119
|
+
console.log(` SWAGGER_DEFAULT_USERNAME : ${config.SWAGGER_DEFAULT_USERNAME || "(未设置)"}`);
|
|
120
|
+
console.log(` SWAGGER_DEFAULT_PASSWORD : ${maskValue(config.SWAGGER_DEFAULT_PASSWORD)}`);
|
|
121
|
+
console.log(`\n配置后,api_tool fetch 操作可自动读取认证信息。`);
|
|
122
|
+
console.log(` 用法: npx szcd-mcp-api-config set --baseUrl=xxx --account=yyy --cookies=zzz --swgUser=admin --swgPass=xxx\n`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function cmdSet(baseUrl, account, password, cookies, swgUser, swgPass) {
|
|
126
|
+
const config = loadConfig();
|
|
127
|
+
let changed = false;
|
|
128
|
+
|
|
129
|
+
if (baseUrl) {
|
|
130
|
+
const old = config.YAPI_BASE_URL || "(未设置)";
|
|
131
|
+
config.YAPI_BASE_URL = baseUrl;
|
|
132
|
+
console.log(` YAPI_BASE_URL : ${old} -> ${baseUrl}`);
|
|
133
|
+
changed = true;
|
|
134
|
+
}
|
|
135
|
+
if (account) {
|
|
136
|
+
const old = config.YAPI_ACCOUNT || "(未设置)";
|
|
137
|
+
config.YAPI_ACCOUNT = account;
|
|
138
|
+
console.log(` YAPI_ACCOUNT : ${old} -> ${account}`);
|
|
139
|
+
changed = true;
|
|
140
|
+
}
|
|
141
|
+
if (password) {
|
|
142
|
+
const old = maskValue(config.YAPI_PASSWORD);
|
|
143
|
+
config.YAPI_PASSWORD = password;
|
|
144
|
+
console.log(` YAPI_PASSWORD : ${old} -> ${maskValue(password)}`);
|
|
145
|
+
changed = true;
|
|
146
|
+
}
|
|
147
|
+
if (cookies) {
|
|
148
|
+
const old = maskValue(config.YAPI_COOKIES);
|
|
149
|
+
config.YAPI_COOKIES = cookies;
|
|
150
|
+
console.log(` YAPI_COOKIES : ${old} -> ${maskValue(cookies)}`);
|
|
151
|
+
changed = true;
|
|
152
|
+
}
|
|
153
|
+
if (swgUser) {
|
|
154
|
+
const old = config.SWAGGER_DEFAULT_USERNAME || "(未设置)";
|
|
155
|
+
config.SWAGGER_DEFAULT_USERNAME = swgUser;
|
|
156
|
+
console.log(` SWAGGER_DEFAULT_USERNAME : ${old} -> ${swgUser}`);
|
|
157
|
+
changed = true;
|
|
158
|
+
}
|
|
159
|
+
if (swgPass) {
|
|
160
|
+
const old = maskValue(config.SWAGGER_DEFAULT_PASSWORD);
|
|
161
|
+
config.SWAGGER_DEFAULT_PASSWORD = swgPass;
|
|
162
|
+
console.log(` SWAGGER_DEFAULT_PASSWORD : ${old} -> ${maskValue(swgPass)}`);
|
|
163
|
+
changed = true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!changed) {
|
|
167
|
+
console.log("\n未提供任何要设置的参数。用法:");
|
|
168
|
+
console.log(" npx szcd-mcp-api-config set --baseUrl=xxx --account=yyy --password=zzz --cookies=ccc --swgUser=admin --swgPass=xxx\n");
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (saveConfig(config)) {
|
|
173
|
+
console.log(`\n配置已保存。`);
|
|
174
|
+
console.log(` YAPI_BASE_URL : ${config.YAPI_BASE_URL || "(未设置)"}`);
|
|
175
|
+
console.log(` YAPI_ACCOUNT : ${config.YAPI_ACCOUNT || "(未设置)"}`);
|
|
176
|
+
console.log(` YAPI_PASSWORD : ${maskValue(config.YAPI_PASSWORD)}`);
|
|
177
|
+
console.log(` YAPI_COOKIES : ${maskValue(config.YAPI_COOKIES)}`);
|
|
178
|
+
console.log(` SWAGGER_DEFAULT_USERNAME : ${config.SWAGGER_DEFAULT_USERNAME || "(未设置)"}`);
|
|
179
|
+
console.log(` SWAGGER_DEFAULT_PASSWORD : ${maskValue(config.SWAGGER_DEFAULT_PASSWORD)}\n`);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
console.log("\n保存配置失败。\n");
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function cmdClear() {
|
|
187
|
+
const config = loadConfig();
|
|
188
|
+
const hadBaseUrl = !!config.YAPI_BASE_URL;
|
|
189
|
+
const hadAccount = !!config.YAPI_ACCOUNT;
|
|
190
|
+
const hadPassword = !!config.YAPI_PASSWORD;
|
|
191
|
+
const hadCookies = !!config.YAPI_COOKIES;
|
|
192
|
+
const hadSwgUser = !!config.SWAGGER_DEFAULT_USERNAME;
|
|
193
|
+
const hadSwgPass = !!config.SWAGGER_DEFAULT_PASSWORD;
|
|
194
|
+
|
|
195
|
+
if (!hadBaseUrl && !hadAccount && !hadPassword && !hadCookies && !hadSwgUser && !hadSwgPass) {
|
|
196
|
+
console.log("\n没有 API 配置需要清除。\n");
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
delete config.YAPI_BASE_URL;
|
|
201
|
+
delete config.YAPI_ACCOUNT;
|
|
202
|
+
delete config.YAPI_PASSWORD;
|
|
203
|
+
delete config.YAPI_COOKIES;
|
|
204
|
+
delete config.SWAGGER_DEFAULT_USERNAME;
|
|
205
|
+
delete config.SWAGGER_DEFAULT_PASSWORD;
|
|
206
|
+
|
|
207
|
+
if (saveConfig(config)) {
|
|
208
|
+
console.log("\n已清除 API 配置。\n");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
console.log("\n清除配置失败。\n");
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ==================== 帮助信息 ====================
|
|
216
|
+
|
|
217
|
+
function printHelp() {
|
|
218
|
+
console.log(`
|
|
219
|
+
Usage: npx szcd-mcp-api-config <command> [options]
|
|
220
|
+
|
|
221
|
+
Commands:
|
|
222
|
+
get 查看当前 API 工具配置
|
|
223
|
+
set [options] 设置 YApi / Swagger 配置项
|
|
224
|
+
clear 清除所有 API 配置
|
|
225
|
+
|
|
226
|
+
Options for 'set':
|
|
227
|
+
--baseUrl=<url> YApi 基础地址,如 http://yapi.smartcitysz.work
|
|
228
|
+
--account=<email> YApi 登录账号/邮箱
|
|
229
|
+
--password=<string> YApi 密码(敏感)
|
|
230
|
+
--cookies=<string> YApi Cookie 字符串(敏感,优先使用)
|
|
231
|
+
--swgUser=<string> Swagger 默认鉴权用户名
|
|
232
|
+
--swgPass=<string> Swagger 默认鉴权密码(敏感,留空则跳过鉴权)
|
|
233
|
+
|
|
234
|
+
Examples:
|
|
235
|
+
npx szcd-mcp-api-config get
|
|
236
|
+
npx szcd-mcp-api-config set --baseUrl=http://yapi.smartcitysz.work
|
|
237
|
+
npx szcd-mcp-api-config set --account=xxx@smartcitysz.work --password=xxx
|
|
238
|
+
npx szcd-mcp-api-config set --cookies="_yapi_token=xxx; _yapi_uid=xxx"
|
|
239
|
+
npx szcd-mcp-api-config set --swgUser=admin --swgPass=xxx
|
|
240
|
+
npx szcd-mcp-api-config set --baseUrl=xxx --account=yyy --swgUser=admin --swgPass=zzz
|
|
241
|
+
npx szcd-mcp-api-config clear
|
|
242
|
+
|
|
243
|
+
Config file: ~/.szcd-mcp-config.json
|
|
244
|
+
`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ==================== 主函数 ====================
|
|
248
|
+
|
|
249
|
+
function main() {
|
|
250
|
+
const args = parseArgs(process.argv);
|
|
251
|
+
|
|
252
|
+
if (args.action === "help" || args.action === "-h" || args.action === "--help") {
|
|
253
|
+
printHelp();
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (args.action === "get") {
|
|
258
|
+
cmdGet();
|
|
259
|
+
} else if (args.action === "set") {
|
|
260
|
+
const ok = cmdSet(args.baseUrl, args.account, args.password, args.cookies, args.swgUser, args.swgPass);
|
|
261
|
+
process.exit(ok ? 0 : 1);
|
|
262
|
+
} else if (args.action === "clear") {
|
|
263
|
+
const ok = cmdClear();
|
|
264
|
+
process.exit(ok ? 0 : 1);
|
|
265
|
+
} else {
|
|
266
|
+
console.error(`Unknown command: ${args.action}`);
|
|
267
|
+
printHelp();
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
main();
|