@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.
@@ -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 skillDir = path.join(claudeSkillsDir, skillName);
142
+ const skills = deps.discoverSkills();
143
+ let allOk = true;
144
144
 
145
- try {
146
- deps.ensureDirectory(skillDir);
147
- const skillDest = path.join(skillDir, "SKILL.md");
148
- deps.copyFile(deps.SKILL_SOURCE, skillDest);
149
- console.log(`✓ Copied standard skill to Claude Code ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
150
- return true;
151
- } catch (error) {
152
- console.log(`⚠️ Failed to copy skill to Claude Code ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
153
- return false;
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 安装 ====================
@@ -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 SKILL_SOURCE = path.join(PACKAGE_ROOT, "standard-skill", "SKILL.md");
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";
@@ -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 skillDir = path.join(qoderSkillsDir, skillName);
182
+ const skills = deps.discoverSkills();
183
+ let allOk = true;
184
184
 
185
- try {
186
- deps.ensureDirectory(skillDir);
187
- const skillDest = path.join(skillDir, "SKILL.md");
188
- deps.copyFile(deps.SKILL_SOURCE, skillDest);
189
- console.log(`✓ Copied skill to Qoder ${isProjectLevel ? "project" : "user"} directory: ${skillDir}`);
190
- return true;
191
- } catch (error) {
192
- console.log(`⚠️ Failed to copy skill to Qoder ${isProjectLevel ? "project" : "user"} directory: ${error.message}`);
193
- return false;
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 安装 ====================
@@ -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 skillDir = path.join(traeCliSkillsDir, skillName);
180
+ const skills = deps.discoverSkills();
181
+ let allOk = true;
182
182
 
183
- try {
184
- deps.ensureDirectory(skillDir);
185
- const skillDest = path.join(skillDir, "SKILL.md");
186
- deps.copyFile(deps.SKILL_SOURCE, skillDest);
187
- console.log(`✓ Copied skill to Trae CLI ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
188
- return true;
189
- } catch (error) {
190
- console.log(`⚠️ Failed to copy skill to Trae CLI ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
191
- return false;
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) ====================
@@ -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 skillDir = path.join(traeSkillsDir, skillName);
157
+ const skills = deps.discoverSkills();
158
+ let allOk = true;
159
159
 
160
- try {
161
- deps.ensureDirectory(skillDir);
162
- const skillDest = path.join(skillDir, "SKILL.md");
163
- deps.copyFile(deps.SKILL_SOURCE, skillDest);
164
- console.log(`✓ Copied standard skill to Trae ${isProjectLevel ? 'project' : 'user'} directory: ${skillDir}`);
165
- return true;
166
- } catch (error) {
167
- console.log(`⚠️ Failed to copy skill to Trae ${isProjectLevel ? 'project' : 'user'} directory: ${error.message}`);
168
- return false;
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
+
@@ -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
 
@@ -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
- if (!fs.existsSync(common.SKILL_SOURCE)) {
164
- throw new Error(`Skill source file not found: ${common.SKILL_SOURCE}`);
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(`- Skill source: ${common.SKILL_SOURCE}`);
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();