jvibe 1.1.8 → 1.1.10

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.
@@ -5,49 +5,435 @@
5
5
  "id": "serena",
6
6
  "name": "Serena",
7
7
  "category": "memory",
8
+ "description": "符号分析 + 项目记忆",
8
9
  "integration": { "type": "mcp" },
9
- "default_tier": "core"
10
- },
11
- {
12
- "id": "brave-search",
13
- "name": "Brave Search",
14
- "category": "search",
15
- "integration": { "type": "mcp" },
10
+ "claude": {
11
+ "mcpServerName": "serena",
12
+ "mcpAliases": ["serena"],
13
+ "mcpServer": {
14
+ "command": "npx",
15
+ "args": ["-y", "serena-slim"]
16
+ }
17
+ },
16
18
  "default_tier": "core"
17
19
  },
18
20
  {
19
21
  "id": "filesystem-mcp",
20
22
  "name": "Filesystem MCP",
21
23
  "category": "filesystem",
24
+ "description": "基础文件操作",
22
25
  "integration": { "type": "mcp" },
26
+ "claude": {
27
+ "mcpServerName": "filesystem",
28
+ "mcpAliases": ["filesystem", "filesystem-mcp"],
29
+ "mcpServer": {
30
+ "command": "npx",
31
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "{{project_root}}"]
32
+ }
33
+ },
23
34
  "default_tier": "core"
24
35
  },
25
36
  {
26
37
  "id": "github-mcp",
27
38
  "name": "GitHub MCP",
28
39
  "category": "git",
40
+ "description": "Git/代码托管",
29
41
  "integration": { "type": "mcp" },
30
- "default_tier": "core"
42
+ "claude": {
43
+ "mcpServerName": "github",
44
+ "mcpAliases": ["github", "github-mcp"],
45
+ "mcpServer": {
46
+ "command": "npx",
47
+ "args": ["-y", "@modelcontextprotocol/server-github"],
48
+ "env": {
49
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "{{GITHUB_PERSONAL_ACCESS_TOKEN}}"
50
+ }
51
+ }
52
+ },
53
+ "requires": { "env": ["GITHUB_PERSONAL_ACCESS_TOKEN"] },
54
+ "default_tier": "project"
31
55
  },
32
56
  {
33
57
  "id": "context7",
34
58
  "name": "Context7",
35
59
  "category": "docs",
60
+ "description": "查询库/框架文档",
36
61
  "integration": { "type": "mcp" },
62
+ "claude": {
63
+ "mcpServerName": "context7",
64
+ "mcpAliases": ["context7", "context7-mcp"],
65
+ "mcpServer": {
66
+ "command": "npx",
67
+ "args": ["-y", "@upstash/context7-mcp"]
68
+ }
69
+ },
37
70
  "default_tier": "core"
38
71
  },
39
72
  {
40
73
  "id": "agent-browser",
41
74
  "name": "Agent Browser",
42
75
  "category": "browser",
43
- "integration": { "type": "daemon+skill" },
76
+ "description": "浏览器自动化(Skill 形态)",
77
+ "integration": { "type": "skill" },
78
+ "claude": {
79
+ "skillName": "agent-browser",
80
+ "skillSource": "https://raw.githubusercontent.com/vercel-labs/agent-browser/v0.6.0/skills/agent-browser/SKILL.md",
81
+ "skillDir": ".claude/skills/agent-browser",
82
+ "globalInstall": "npm install -g agent-browser && agent-browser install",
83
+ "allowedTools": ["Bash(agent-browser:*)"]
84
+ },
44
85
  "default_tier": "core"
45
86
  },
87
+
88
+ {
89
+ "id": "postgres-mcp",
90
+ "name": "PostgreSQL",
91
+ "category": "database",
92
+ "description": "PostgreSQL 数据库操作",
93
+ "integration": { "type": "mcp" },
94
+ "claude": {
95
+ "mcpServerName": "postgres",
96
+ "mcpAliases": ["postgres", "postgresql"],
97
+ "mcpServer": {
98
+ "command": "npx",
99
+ "args": ["-y", "@modelcontextprotocol/server-postgres"],
100
+ "env": {
101
+ "POSTGRES_CONNECTION_STRING": "{{POSTGRES_CONNECTION_STRING}}"
102
+ }
103
+ }
104
+ },
105
+ "requires": { "env": ["POSTGRES_CONNECTION_STRING"] },
106
+ "default_tier": "project"
107
+ },
108
+ {
109
+ "id": "mysql-mcp",
110
+ "name": "MySQL",
111
+ "category": "database",
112
+ "description": "MySQL 数据库操作",
113
+ "integration": { "type": "mcp" },
114
+ "claude": {
115
+ "mcpServerName": "mysql",
116
+ "mcpAliases": ["mysql"],
117
+ "mcpServer": {
118
+ "command": "npx",
119
+ "args": ["-y", "mysql-mcp"],
120
+ "env": {
121
+ "MYSQL_HOST": "{{MYSQL_HOST}}",
122
+ "MYSQL_PORT": "{{MYSQL_PORT}}",
123
+ "MYSQL_USER": "{{MYSQL_USER}}",
124
+ "MYSQL_PASSWORD": "{{MYSQL_PASSWORD}}",
125
+ "MYSQL_DATABASE": "{{MYSQL_DATABASE}}"
126
+ }
127
+ }
128
+ },
129
+ "requires": { "env": ["MYSQL_HOST", "MYSQL_USER", "MYSQL_PASSWORD", "MYSQL_DATABASE"] },
130
+ "default_tier": "project"
131
+ },
132
+ {
133
+ "id": "mongodb-mcp",
134
+ "name": "MongoDB",
135
+ "category": "database",
136
+ "description": "MongoDB 数据库操作",
137
+ "integration": { "type": "mcp" },
138
+ "claude": {
139
+ "mcpServerName": "mongodb",
140
+ "mcpAliases": ["mongodb", "mongo"],
141
+ "mcpServer": {
142
+ "command": "npx",
143
+ "args": ["-y", "mcp-mongo-server"],
144
+ "env": {
145
+ "MONGODB_URI": "{{MONGODB_URI}}"
146
+ }
147
+ }
148
+ },
149
+ "requires": { "env": ["MONGODB_URI"] },
150
+ "default_tier": "project"
151
+ },
152
+ {
153
+ "id": "supabase-mcp",
154
+ "name": "Supabase",
155
+ "category": "database",
156
+ "description": "Supabase 数据库 + Auth + Storage",
157
+ "integration": { "type": "mcp" },
158
+ "claude": {
159
+ "mcpServerName": "supabase",
160
+ "mcpAliases": ["supabase"],
161
+ "mcpServer": {
162
+ "command": "npx",
163
+ "args": ["-y", "@supabase/mcp-server-supabase", "--access-token", "{{SUPABASE_ACCESS_TOKEN}}"]
164
+ }
165
+ },
166
+ "requires": { "env": ["SUPABASE_ACCESS_TOKEN"] },
167
+ "default_tier": "project"
168
+ },
169
+ {
170
+ "id": "redis-mcp",
171
+ "name": "Redis",
172
+ "category": "database",
173
+ "description": "Redis 缓存操作",
174
+ "integration": { "type": "mcp" },
175
+ "claude": {
176
+ "mcpServerName": "redis",
177
+ "mcpAliases": ["redis"],
178
+ "mcpServer": {
179
+ "command": "npx",
180
+ "args": ["-y", "@modelcontextprotocol/server-redis"],
181
+ "env": {
182
+ "REDIS_URL": "{{REDIS_URL}}"
183
+ }
184
+ }
185
+ },
186
+ "requires": { "env": ["REDIS_URL"] },
187
+ "default_tier": "project"
188
+ },
189
+
190
+ {
191
+ "id": "docker-mcp",
192
+ "name": "Docker",
193
+ "category": "container",
194
+ "description": "Docker 容器管理",
195
+ "integration": { "type": "mcp" },
196
+ "claude": {
197
+ "mcpServerName": "docker",
198
+ "mcpAliases": ["docker"],
199
+ "mcpServer": {
200
+ "command": "npx",
201
+ "args": ["-y", "mcp-server-docker"]
202
+ }
203
+ },
204
+ "default_tier": "project"
205
+ },
206
+ {
207
+ "id": "kubernetes-mcp",
208
+ "name": "Kubernetes",
209
+ "category": "container",
210
+ "description": "Kubernetes 集群管理",
211
+ "integration": { "type": "mcp" },
212
+ "claude": {
213
+ "mcpServerName": "kubernetes",
214
+ "mcpAliases": ["kubernetes", "k8s"],
215
+ "mcpServer": {
216
+ "command": "npx",
217
+ "args": ["-y", "mcp-server-kubernetes"]
218
+ }
219
+ },
220
+ "default_tier": "project"
221
+ },
222
+
223
+ {
224
+ "id": "aws-mcp",
225
+ "name": "AWS",
226
+ "category": "cloud",
227
+ "description": "AWS 云服务管理",
228
+ "integration": { "type": "mcp" },
229
+ "claude": {
230
+ "mcpServerName": "aws",
231
+ "mcpAliases": ["aws"],
232
+ "mcpServer": {
233
+ "command": "npx",
234
+ "args": ["-y", "mcp-server-aws"],
235
+ "env": {
236
+ "AWS_ACCESS_KEY_ID": "{{AWS_ACCESS_KEY_ID}}",
237
+ "AWS_SECRET_ACCESS_KEY": "{{AWS_SECRET_ACCESS_KEY}}",
238
+ "AWS_REGION": "{{AWS_REGION}}"
239
+ }
240
+ }
241
+ },
242
+ "requires": { "env": ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"] },
243
+ "default_tier": "project"
244
+ },
245
+ {
246
+ "id": "gcp-mcp",
247
+ "name": "Google Cloud",
248
+ "category": "cloud",
249
+ "description": "GCP 云服务管理",
250
+ "integration": { "type": "mcp" },
251
+ "claude": {
252
+ "mcpServerName": "gcp",
253
+ "mcpAliases": ["gcp", "google-cloud"],
254
+ "mcpServer": {
255
+ "command": "npx",
256
+ "args": ["-y", "gcp-mcp"],
257
+ "env": {
258
+ "GOOGLE_APPLICATION_CREDENTIALS": "{{GOOGLE_APPLICATION_CREDENTIALS}}"
259
+ }
260
+ }
261
+ },
262
+ "requires": { "env": ["GOOGLE_APPLICATION_CREDENTIALS"] },
263
+ "default_tier": "project"
264
+ },
265
+ {
266
+ "id": "azure-mcp",
267
+ "name": "Azure",
268
+ "category": "cloud",
269
+ "description": "Azure 云服务管理",
270
+ "integration": { "type": "mcp" },
271
+ "claude": {
272
+ "mcpServerName": "azure",
273
+ "mcpAliases": ["azure"],
274
+ "mcpServer": {
275
+ "command": "npx",
276
+ "args": ["-y", "mcp-server-azure"],
277
+ "env": {
278
+ "AZURE_SUBSCRIPTION_ID": "{{AZURE_SUBSCRIPTION_ID}}",
279
+ "AZURE_CLIENT_ID": "{{AZURE_CLIENT_ID}}",
280
+ "AZURE_CLIENT_SECRET": "{{AZURE_CLIENT_SECRET}}",
281
+ "AZURE_TENANT_ID": "{{AZURE_TENANT_ID}}"
282
+ }
283
+ }
284
+ },
285
+ "requires": { "env": ["AZURE_SUBSCRIPTION_ID", "AZURE_CLIENT_ID", "AZURE_CLIENT_SECRET", "AZURE_TENANT_ID"] },
286
+ "default_tier": "project"
287
+ },
288
+
46
289
  {
47
290
  "id": "playwright-mcp",
48
- "name": "Playwright MCP",
49
- "category": "browser",
291
+ "name": "Playwright",
292
+ "category": "testing",
293
+ "description": "浏览器自动化测试",
294
+ "integration": { "type": "mcp" },
295
+ "claude": {
296
+ "mcpServerName": "playwright",
297
+ "mcpAliases": ["playwright"],
298
+ "mcpServer": {
299
+ "command": "npx",
300
+ "args": ["-y", "@playwright/mcp"]
301
+ }
302
+ },
303
+ "default_tier": "project"
304
+ },
305
+ {
306
+ "id": "puppeteer-mcp",
307
+ "name": "Puppeteer",
308
+ "category": "testing",
309
+ "description": "Chrome 无头浏览器测试",
310
+ "integration": { "type": "mcp" },
311
+ "claude": {
312
+ "mcpServerName": "puppeteer",
313
+ "mcpAliases": ["puppeteer"],
314
+ "mcpServer": {
315
+ "command": "npx",
316
+ "args": ["-y", "@hisma/server-puppeteer"]
317
+ }
318
+ },
319
+ "default_tier": "project"
320
+ },
321
+
322
+ {
323
+ "id": "chrome-devtools-mcp",
324
+ "name": "Chrome DevTools",
325
+ "category": "frontend",
326
+ "description": "Chrome 开发者工具调试",
327
+ "integration": { "type": "mcp" },
328
+ "claude": {
329
+ "mcpServerName": "chrome-devtools",
330
+ "mcpAliases": ["chrome-devtools", "devtools"],
331
+ "mcpServer": {
332
+ "command": "npx",
333
+ "args": ["-y", "chrome-devtools-mcp"]
334
+ }
335
+ },
336
+ "default_tier": "project"
337
+ },
338
+
339
+ {
340
+ "id": "figma-mcp",
341
+ "name": "Figma",
342
+ "category": "design",
343
+ "description": "Figma 设计文件操作",
344
+ "integration": { "type": "mcp" },
345
+ "claude": {
346
+ "mcpServerName": "figma",
347
+ "mcpAliases": ["figma"],
348
+ "mcpServer": {
349
+ "command": "npx",
350
+ "args": ["-y", "mcp-figma"]
351
+ }
352
+ },
353
+ "default_tier": "project"
354
+ },
355
+
356
+ {
357
+ "id": "slack-mcp",
358
+ "name": "Slack",
359
+ "category": "communication",
360
+ "description": "Slack 消息与频道管理",
361
+ "integration": { "type": "mcp" },
362
+ "claude": {
363
+ "mcpServerName": "slack",
364
+ "mcpAliases": ["slack"],
365
+ "mcpServer": {
366
+ "command": "npx",
367
+ "args": ["-y", "slack-mcp-server"],
368
+ "env": {
369
+ "SLACK_MCP_XOXB_TOKEN": "{{SLACK_MCP_XOXB_TOKEN}}"
370
+ }
371
+ }
372
+ },
373
+ "requires": { "env": ["SLACK_MCP_XOXB_TOKEN"] },
374
+ "default_tier": "project"
375
+ },
376
+ {
377
+ "id": "discord-mcp",
378
+ "name": "Discord",
379
+ "category": "communication",
380
+ "description": "Discord 消息与服务器管理",
381
+ "integration": { "type": "mcp" },
382
+ "claude": {
383
+ "mcpServerName": "discord",
384
+ "mcpAliases": ["discord"],
385
+ "mcpServer": {
386
+ "command": "npx",
387
+ "args": ["-y", "mcp-server-discord"],
388
+ "env": {
389
+ "DISCORD_BOT_TOKEN": "{{DISCORD_BOT_TOKEN}}"
390
+ }
391
+ }
392
+ },
393
+ "requires": { "env": ["DISCORD_BOT_TOKEN"] },
394
+ "default_tier": "project"
395
+ },
396
+
397
+ {
398
+ "id": "notion-mcp",
399
+ "name": "Notion",
400
+ "category": "docs",
401
+ "description": "Notion 页面与数据库操作",
402
+ "integration": { "type": "mcp" },
403
+ "claude": {
404
+ "mcpServerName": "notion",
405
+ "mcpAliases": ["notion"],
406
+ "mcpServer": {
407
+ "command": "npx",
408
+ "args": ["-y", "@notionhq/notion-mcp-server"],
409
+ "env": {
410
+ "NOTION_TOKEN": "{{NOTION_TOKEN}}"
411
+ }
412
+ }
413
+ },
414
+ "requires": { "env": ["NOTION_TOKEN"] },
415
+ "default_tier": "project"
416
+ },
417
+ {
418
+ "id": "confluence-mcp",
419
+ "name": "Confluence",
420
+ "category": "docs",
421
+ "description": "Confluence 文档协作",
50
422
  "integration": { "type": "mcp" },
423
+ "claude": {
424
+ "mcpServerName": "confluence",
425
+ "mcpAliases": ["confluence"],
426
+ "mcpServer": {
427
+ "command": "npx",
428
+ "args": ["-y", "@answerai/confluence-mcp"],
429
+ "env": {
430
+ "CONFLUENCE_BASE_URL": "{{CONFLUENCE_BASE_URL}}",
431
+ "CONFLUENCE_USER_EMAIL": "{{CONFLUENCE_USER_EMAIL}}",
432
+ "CONFLUENCE_API_TOKEN": "{{CONFLUENCE_API_TOKEN}}"
433
+ }
434
+ }
435
+ },
436
+ "requires": { "env": ["CONFLUENCE_BASE_URL", "CONFLUENCE_USER_EMAIL", "CONFLUENCE_API_TOKEN"] },
51
437
  "default_tier": "project"
52
438
  }
53
439
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvibe",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "description": "\u6587\u6863\u9a71\u52a8\u7684 AI \u8f85\u52a9\u5f00\u53d1\u7cfb\u7edf - Doc-driven AI-assisted development system for Claude Code and OpenCode",
5
5
  "main": "bin/jvibe.js",
6
6
  "bin": {
package/scripts/init.js CHANGED
@@ -6,6 +6,10 @@
6
6
  const fs = require('fs-extra');
7
7
  const path = require('path');
8
8
  const chalk = require('chalk');
9
+ const {
10
+ loadPluginRegistry,
11
+ configureClaudeCoreTools
12
+ } = require('../lib/plugins/core-tools');
9
13
 
10
14
  const TEMPLATE_DIR = path.join(__dirname, '../template');
11
15
 
@@ -30,6 +34,8 @@ async function init(options = {}) {
30
34
  console.log(chalk.blue('\n🚀 正在初始化 JVibe...\n'));
31
35
 
32
36
  try {
37
+ const pluginRegistry = await loadPluginRegistry();
38
+
33
39
  // 1. 检查是否已存在 JVibe 配置
34
40
  const claudeDir = path.join(cwd, '.claude');
35
41
  const opencodeDir = path.join(cwd, '.opencode');
@@ -143,6 +149,37 @@ async function init(options = {}) {
143
149
  await fs.writeJson(opencodeMetaPath, opencodeMeta, { spaces: 2 });
144
150
  }
145
151
 
152
+ // 6.5 配置 Core Tools(MCP Servers + Skills,仅写入缺失项)
153
+ const coreToolsResult = await configureClaudeCoreTools(cwd, pluginRegistry);
154
+ if (coreToolsResult && coreToolsResult.error) {
155
+ console.log(chalk.yellow(`⚠️ Core Tools 自动配置已跳过:${coreToolsResult.error}`));
156
+ } else if (coreToolsResult) {
157
+ const mcpAdded = typeof coreToolsResult.mcpAdded === 'number'
158
+ ? coreToolsResult.mcpAdded
159
+ : coreToolsResult.added - (coreToolsResult.skillsAdded ? coreToolsResult.skillsAdded.length : 0);
160
+ if (mcpAdded > 0) {
161
+ console.log(chalk.gray(` 已写入 MCP Server 配置: ${mcpAdded} 项 (.claude/settings.local.json)`));
162
+ }
163
+ if (Array.isArray(coreToolsResult.skillsAdded) && coreToolsResult.skillsAdded.length > 0) {
164
+ console.log(chalk.gray(` 已安装 Skill: ${coreToolsResult.skillsAdded.length} 项`));
165
+ }
166
+ if (Array.isArray(coreToolsResult.skillsNeedingCli) && coreToolsResult.skillsNeedingCli.length > 0) {
167
+ coreToolsResult.skillsNeedingCli.forEach(({ pluginId, globalInstall }) => {
168
+ if (!pluginId || !globalInstall) return;
169
+ console.log(chalk.yellow(`⚠️ ${pluginId} 需要全局安装 CLI: ${globalInstall}`));
170
+ });
171
+ }
172
+ }
173
+ if (coreToolsResult && Array.isArray(coreToolsResult.missingTemplates) && coreToolsResult.missingTemplates.length > 0) {
174
+ console.log(chalk.yellow(`⚠️ 以下 Core Tools 未提供自动配置模板,请手动配置: ${coreToolsResult.missingTemplates.join(', ')}`));
175
+ }
176
+ if (coreToolsResult && Array.isArray(coreToolsResult.missingEnv) && coreToolsResult.missingEnv.length > 0) {
177
+ coreToolsResult.missingEnv.forEach(({ pluginId, keys }) => {
178
+ if (!pluginId || !Array.isArray(keys) || keys.length === 0) return;
179
+ console.log(chalk.yellow(`⚠️ ${pluginId} 可能缺少环境变量: ${keys.join(', ')}`));
180
+ });
181
+ }
182
+
146
183
  // 7. 输出成功信息
147
184
  console.log(chalk.green('\n✅ JVibe 初始化完成!\n'));
148
185
 
@@ -0,0 +1,159 @@
1
+ /**
2
+ * JVibe Plugins Script
3
+ * 配置/检查插件(先从 Core Tools 开始)
4
+ */
5
+
6
+ const fs = require('fs-extra');
7
+ const path = require('path');
8
+ const chalk = require('chalk');
9
+ const { spawn } = require('child_process');
10
+ const readline = require('readline');
11
+ const {
12
+ loadPluginRegistry,
13
+ configureClaudeCoreTools
14
+ } = require('../lib/plugins/core-tools');
15
+
16
+ function askQuestion(question) {
17
+ // 非交互环境(CI / stdin 重定向 / 管道)下,避免 readline 卡住。
18
+ // 默认选择 "n"(跳过安装),以免误触发全局安装。
19
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
20
+ return Promise.resolve('n');
21
+ }
22
+
23
+ const rl = readline.createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout
26
+ });
27
+ return new Promise(resolve => {
28
+ let resolved = false;
29
+ const finish = (answer) => {
30
+ if (resolved) return;
31
+ resolved = true;
32
+ try { rl.close(); } catch {}
33
+ resolve((answer || '').trim().toLowerCase());
34
+ };
35
+
36
+ rl.on('close', () => finish('n'));
37
+ rl.on('SIGINT', () => finish('n'));
38
+
39
+ try {
40
+ rl.question(question, finish);
41
+ } catch {
42
+ finish('n');
43
+ }
44
+ });
45
+ }
46
+
47
+ async function installSkillCli(globalInstall) {
48
+ return new Promise((resolve) => {
49
+ console.log(chalk.gray(` 正在安装: ${globalInstall}`));
50
+
51
+ // 解析命令
52
+ const parts = globalInstall.split('&&').map(s => s.trim());
53
+
54
+ const runCommand = (cmd, callback) => {
55
+ const [command, ...args] = cmd.split(/\s+/);
56
+ const child = spawn(command, args, {
57
+ stdio: 'inherit',
58
+ shell: true
59
+ });
60
+ child.on('close', code => callback(code === 0));
61
+ child.on('error', () => callback(false));
62
+ };
63
+
64
+ const runSequentially = (commands, index = 0) => {
65
+ if (index >= commands.length) {
66
+ resolve(true);
67
+ return;
68
+ }
69
+ runCommand(commands[index], success => {
70
+ if (!success) {
71
+ resolve(false);
72
+ return;
73
+ }
74
+ runSequentially(commands, index + 1);
75
+ });
76
+ };
77
+
78
+ runSequentially(parts);
79
+ });
80
+ }
81
+
82
+ async function configureCore() {
83
+ const cwd = process.cwd();
84
+
85
+ const registry = await loadPluginRegistry();
86
+ const claudeDir = path.join(cwd, '.claude');
87
+
88
+ if (!await fs.pathExists(claudeDir)) {
89
+ console.log(chalk.yellow('⚠️ 未检测到 .claude/,已跳过 Core Tools 配置'));
90
+ return;
91
+ }
92
+
93
+ const result = await configureClaudeCoreTools(cwd, registry);
94
+ if (result && result.error) {
95
+ console.log(chalk.yellow(`⚠️ Core Tools 自动配置已跳过:${result.error}`));
96
+ return;
97
+ }
98
+
99
+ // MCP Server 配置结果
100
+ const mcpAdded = typeof result.mcpAdded === 'number'
101
+ ? result.mcpAdded
102
+ : result.added - (result.skillsAdded ? result.skillsAdded.length : 0);
103
+ if (mcpAdded > 0) {
104
+ console.log(chalk.green(`✅ 已写入 MCP Server 配置: ${mcpAdded} 项 (.claude/settings.local.json)`));
105
+ }
106
+
107
+ // Skill 配置结果
108
+ if (result && Array.isArray(result.skillsAdded) && result.skillsAdded.length > 0) {
109
+ console.log(chalk.green(`✅ 已安装 Skill: ${result.skillsAdded.length} 项`));
110
+
111
+ for (const { pluginId, skillDir } of result.skillsAdded) {
112
+ console.log(chalk.gray(` - ${pluginId} → ${skillDir}`));
113
+ }
114
+ }
115
+
116
+ // Skill CLI 安装提示(即使 Skill 已存在也提示)
117
+ if (result && Array.isArray(result.skillsNeedingCli) && result.skillsNeedingCli.length > 0) {
118
+ for (const { pluginId, cliCommand, globalInstall } of result.skillsNeedingCli) {
119
+ if (!globalInstall) continue;
120
+ const label = cliCommand ? `${pluginId} (${cliCommand})` : pluginId;
121
+ const answer = await askQuestion(chalk.yellow(` ⚠️ ${label} 需要全局安装 CLI,是否现在安装?(Y/n) `));
122
+ if (answer === '' || answer === 'y' || answer === 'yes') {
123
+ const success = await installSkillCli(globalInstall);
124
+ if (success) {
125
+ console.log(chalk.green(` ✅ ${pluginId} CLI 安装成功`));
126
+ } else {
127
+ console.log(chalk.red(` ❌ ${pluginId} CLI 安装失败,请手动执行: ${globalInstall}`));
128
+ }
129
+ } else {
130
+ console.log(chalk.gray(` 跳过安装,稍后可手动执行: ${globalInstall}`));
131
+ }
132
+ }
133
+ }
134
+
135
+ if (
136
+ mcpAdded === 0 &&
137
+ (!result.skillsAdded || result.skillsAdded.length === 0) &&
138
+ (!result.skillsNeedingCli || result.skillsNeedingCli.length === 0)
139
+ ) {
140
+ console.log(chalk.green('✅ Core Tools 配置已存在,无需重复写入'));
141
+ }
142
+
143
+ if (result && Array.isArray(result.missingTemplates) && result.missingTemplates.length > 0) {
144
+ console.log(chalk.yellow(`⚠️ 以下 Core Tools 未提供自动配置模板,请手动配置: ${result.missingTemplates.join(', ')}`));
145
+ }
146
+
147
+ if (result && Array.isArray(result.missingEnv) && result.missingEnv.length > 0) {
148
+ console.log(chalk.yellow('⚠️ 以下 Core Tools 可能缺少环境变量,启动 MCP Server 时可能失败:'));
149
+ result.missingEnv.forEach(({ pluginId, keys }) => {
150
+ if (!pluginId || !Array.isArray(keys) || keys.length === 0) return;
151
+ console.log(chalk.yellow(` - ${pluginId}: ${keys.join(', ')}`));
152
+ });
153
+ console.log(chalk.gray(' 提示:在当前 shell 中 export 对应变量后重试'));
154
+ }
155
+ }
156
+
157
+ module.exports = {
158
+ configureCore
159
+ };