ai-engineering-init 1.6.0 → 1.8.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.
Files changed (187) hide show
  1. package/.claude/agents/code-reviewer.md +3 -130
  2. package/.claude/hooks/skill-forced-eval.js +46 -60
  3. package/.claude/hooks/stop.js +24 -1
  4. package/.claude/settings.json +10 -1
  5. package/.claude/skills/api-development/SKILL.md +179 -130
  6. package/.claude/skills/architecture-design/SKILL.md +102 -212
  7. package/.claude/skills/backend-annotations/SKILL.md +166 -220
  8. package/.claude/skills/bug-detective/SKILL.md +225 -186
  9. package/.claude/skills/code-patterns/SKILL.md +127 -244
  10. package/.claude/skills/codex-code-review/SKILL.md +327 -0
  11. package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
  12. package/.claude/skills/crud-development/SKILL.md +226 -307
  13. package/.claude/skills/data-permission/SKILL.md +131 -202
  14. package/.claude/skills/database-ops/SKILL.md +158 -355
  15. package/.claude/skills/error-handler/SKILL.md +224 -285
  16. package/.claude/skills/file-oss-management/SKILL.md +174 -169
  17. package/.claude/skills/git-workflow/SKILL.md +123 -341
  18. package/.claude/skills/json-serialization/SKILL.md +121 -137
  19. package/.claude/skills/leniu-report-customization/SKILL.md +82 -2
  20. package/.claude/skills/leniu-report-standard-customization/SKILL.md +65 -2
  21. package/.claude/skills/loki-log-query/SKILL.md +400 -0
  22. package/.claude/skills/mysql-debug/SKILL.md +58 -22
  23. package/.claude/skills/performance-doctor/SKILL.md +83 -89
  24. package/.claude/skills/redis-cache/SKILL.md +134 -185
  25. package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
  26. package/.claude/skills/security-guard/SKILL.md +168 -276
  27. package/.claude/skills/sms-mail/SKILL.md +266 -228
  28. package/.claude/skills/social-login/SKILL.md +257 -195
  29. package/.claude/skills/sync-back-merge/SKILL.md +66 -0
  30. package/.claude/skills/tenant-management/SKILL.md +172 -188
  31. package/.claude/skills/utils-toolkit/SKILL.md +214 -222
  32. package/.claude/skills/websocket-sse/SKILL.md +251 -172
  33. package/.claude/skills/workflow-engine/SKILL.md +178 -250
  34. package/.claude/skills/yunxiao-task-management/SKILL.md +489 -0
  35. package/.codex/skills/api-development/SKILL.md +179 -130
  36. package/.codex/skills/architecture-design/SKILL.md +102 -212
  37. package/.codex/skills/backend-annotations/SKILL.md +166 -220
  38. package/.codex/skills/bug-detective/SKILL.md +225 -186
  39. package/.codex/skills/code-patterns/SKILL.md +127 -244
  40. package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
  41. package/.codex/skills/crud-development/SKILL.md +226 -307
  42. package/.codex/skills/data-permission/SKILL.md +131 -202
  43. package/.codex/skills/database-ops/SKILL.md +158 -355
  44. package/.codex/skills/error-handler/SKILL.md +224 -285
  45. package/.codex/skills/file-oss-management/SKILL.md +174 -169
  46. package/.codex/skills/git-workflow/SKILL.md +123 -341
  47. package/.codex/skills/json-serialization/SKILL.md +121 -137
  48. package/.codex/skills/leniu-report-customization/SKILL.md +82 -2
  49. package/.codex/skills/leniu-report-standard-customization/SKILL.md +65 -2
  50. package/.codex/skills/loki-log-query/SKILL.md +400 -0
  51. package/.codex/skills/loki-log-query/environments.json +45 -0
  52. package/.codex/skills/mysql-debug/SKILL.md +58 -22
  53. package/.codex/skills/performance-doctor/SKILL.md +83 -89
  54. package/.codex/skills/redis-cache/SKILL.md +134 -185
  55. package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
  56. package/.codex/skills/security-guard/SKILL.md +168 -276
  57. package/.codex/skills/skill-creator/LICENSE.txt +202 -0
  58. package/.codex/skills/skill-creator/SKILL.md +479 -0
  59. package/.codex/skills/skill-creator/agents/analyzer.md +274 -0
  60. package/.codex/skills/skill-creator/agents/comparator.md +202 -0
  61. package/.codex/skills/skill-creator/agents/grader.md +223 -0
  62. package/.codex/skills/skill-creator/assets/eval_review.html +146 -0
  63. package/.codex/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  64. package/.codex/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  65. package/.codex/skills/skill-creator/references/schemas.md +430 -0
  66. package/.codex/skills/skill-creator/scripts/__init__.py +0 -0
  67. package/.codex/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  68. package/.codex/skills/skill-creator/scripts/generate_report.py +326 -0
  69. package/.codex/skills/skill-creator/scripts/improve_description.py +248 -0
  70. package/.codex/skills/skill-creator/scripts/package_skill.py +136 -0
  71. package/.codex/skills/skill-creator/scripts/quick_validate.py +103 -0
  72. package/.codex/skills/skill-creator/scripts/run_eval.py +310 -0
  73. package/.codex/skills/skill-creator/scripts/run_loop.py +332 -0
  74. package/.codex/skills/skill-creator/scripts/utils.py +47 -0
  75. package/.codex/skills/sms-mail/SKILL.md +266 -228
  76. package/.codex/skills/social-login/SKILL.md +257 -195
  77. package/.codex/skills/sync-back-merge/SKILL.md +66 -0
  78. package/.codex/skills/tenant-management/SKILL.md +172 -188
  79. package/.codex/skills/utils-toolkit/SKILL.md +214 -222
  80. package/.codex/skills/websocket-sse/SKILL.md +251 -172
  81. package/.codex/skills/workflow-engine/SKILL.md +178 -250
  82. package/.codex/skills/yunxiao-task-management/SKILL.md +489 -0
  83. package/.cursor/hooks/cursor-skill-eval.js +66 -6
  84. package/.cursor/hooks/stop.js +23 -1
  85. package/.cursor/skills/api-development/SKILL.md +179 -130
  86. package/.cursor/skills/architecture-design/SKILL.md +102 -212
  87. package/.cursor/skills/backend-annotations/SKILL.md +166 -220
  88. package/.cursor/skills/bug-detective/SKILL.md +225 -186
  89. package/.cursor/skills/code-patterns/SKILL.md +127 -244
  90. package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
  91. package/.cursor/skills/crud-development/SKILL.md +226 -307
  92. package/.cursor/skills/data-permission/SKILL.md +131 -202
  93. package/.cursor/skills/database-ops/SKILL.md +158 -355
  94. package/.cursor/skills/error-handler/SKILL.md +224 -285
  95. package/.cursor/skills/file-oss-management/SKILL.md +174 -169
  96. package/.cursor/skills/git-workflow/SKILL.md +123 -341
  97. package/.cursor/skills/json-serialization/SKILL.md +121 -137
  98. package/.cursor/skills/leniu-report-customization/SKILL.md +82 -2
  99. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +65 -2
  100. package/.cursor/skills/loki-log-query/SKILL.md +400 -0
  101. package/.cursor/skills/loki-log-query/environments.json +45 -0
  102. package/.cursor/skills/mysql-debug/SKILL.md +58 -22
  103. package/.cursor/skills/performance-doctor/SKILL.md +83 -89
  104. package/.cursor/skills/redis-cache/SKILL.md +134 -185
  105. package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
  106. package/.cursor/skills/security-guard/SKILL.md +168 -276
  107. package/.cursor/skills/skill-creator/LICENSE.txt +202 -0
  108. package/.cursor/skills/skill-creator/SKILL.md +479 -0
  109. package/.cursor/skills/skill-creator/agents/analyzer.md +274 -0
  110. package/.cursor/skills/skill-creator/agents/comparator.md +202 -0
  111. package/.cursor/skills/skill-creator/agents/grader.md +223 -0
  112. package/.cursor/skills/skill-creator/assets/eval_review.html +146 -0
  113. package/.cursor/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  114. package/.cursor/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  115. package/.cursor/skills/skill-creator/references/schemas.md +430 -0
  116. package/.cursor/skills/skill-creator/scripts/__init__.py +0 -0
  117. package/.cursor/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  118. package/.cursor/skills/skill-creator/scripts/generate_report.py +326 -0
  119. package/.cursor/skills/skill-creator/scripts/improve_description.py +248 -0
  120. package/.cursor/skills/skill-creator/scripts/package_skill.py +136 -0
  121. package/.cursor/skills/skill-creator/scripts/quick_validate.py +103 -0
  122. package/.cursor/skills/skill-creator/scripts/run_eval.py +310 -0
  123. package/.cursor/skills/skill-creator/scripts/run_loop.py +332 -0
  124. package/.cursor/skills/skill-creator/scripts/utils.py +47 -0
  125. package/.cursor/skills/sms-mail/SKILL.md +266 -228
  126. package/.cursor/skills/social-login/SKILL.md +257 -195
  127. package/.cursor/skills/sync-back-merge/SKILL.md +66 -0
  128. package/.cursor/skills/tenant-management/SKILL.md +172 -188
  129. package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
  130. package/.cursor/skills/websocket-sse/SKILL.md +251 -172
  131. package/.cursor/skills/workflow-engine/SKILL.md +178 -250
  132. package/.cursor/skills/yunxiao-task-management/SKILL.md +489 -0
  133. package/AGENTS.md +49 -540
  134. package/CLAUDE.md +73 -119
  135. package/README.md +37 -6
  136. package/bin/index.js +611 -25
  137. package/package.json +1 -1
  138. package/src/platform-map.json +4 -0
  139. package/src/skills/api-development/SKILL.md +179 -130
  140. package/src/skills/architecture-design/SKILL.md +102 -212
  141. package/src/skills/backend-annotations/SKILL.md +166 -220
  142. package/src/skills/bug-detective/SKILL.md +225 -186
  143. package/src/skills/code-patterns/SKILL.md +127 -244
  144. package/src/skills/codex-code-review/SKILL.md +261 -69
  145. package/src/skills/collaborating-with-codex/SKILL.md +96 -113
  146. package/src/skills/crud-development/SKILL.md +226 -307
  147. package/src/skills/data-permission/SKILL.md +131 -202
  148. package/src/skills/database-ops/SKILL.md +158 -355
  149. package/src/skills/error-handler/SKILL.md +224 -285
  150. package/src/skills/file-oss-management/SKILL.md +174 -169
  151. package/src/skills/git-workflow/SKILL.md +123 -341
  152. package/src/skills/json-serialization/SKILL.md +121 -137
  153. package/src/skills/leniu-report-customization/SKILL.md +82 -2
  154. package/src/skills/leniu-report-standard-customization/SKILL.md +65 -2
  155. package/src/skills/loki-log-query/SKILL.md +400 -0
  156. package/src/skills/loki-log-query/environments.json +45 -0
  157. package/src/skills/mysql-debug/SKILL.md +58 -22
  158. package/src/skills/performance-doctor/SKILL.md +83 -89
  159. package/src/skills/redis-cache/SKILL.md +134 -185
  160. package/src/skills/scheduled-jobs/SKILL.md +187 -224
  161. package/src/skills/security-guard/SKILL.md +168 -276
  162. package/src/skills/skill-creator/LICENSE.txt +202 -0
  163. package/src/skills/skill-creator/SKILL.md +479 -0
  164. package/src/skills/skill-creator/agents/analyzer.md +274 -0
  165. package/src/skills/skill-creator/agents/comparator.md +202 -0
  166. package/src/skills/skill-creator/agents/grader.md +223 -0
  167. package/src/skills/skill-creator/assets/eval_review.html +146 -0
  168. package/src/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  169. package/src/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  170. package/src/skills/skill-creator/references/schemas.md +430 -0
  171. package/src/skills/skill-creator/scripts/__init__.py +0 -0
  172. package/src/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  173. package/src/skills/skill-creator/scripts/generate_report.py +326 -0
  174. package/src/skills/skill-creator/scripts/improve_description.py +248 -0
  175. package/src/skills/skill-creator/scripts/package_skill.py +136 -0
  176. package/src/skills/skill-creator/scripts/quick_validate.py +103 -0
  177. package/src/skills/skill-creator/scripts/run_eval.py +310 -0
  178. package/src/skills/skill-creator/scripts/run_loop.py +332 -0
  179. package/src/skills/skill-creator/scripts/utils.py +47 -0
  180. package/src/skills/sms-mail/SKILL.md +266 -228
  181. package/src/skills/social-login/SKILL.md +257 -195
  182. package/src/skills/sync-back-merge/SKILL.md +66 -0
  183. package/src/skills/tenant-management/SKILL.md +172 -188
  184. package/src/skills/utils-toolkit/SKILL.md +214 -222
  185. package/src/skills/websocket-sse/SKILL.md +251 -172
  186. package/src/skills/workflow-engine/SKILL.md +178 -250
  187. package/src/skills/yunxiao-task-management/SKILL.md +489 -0
package/bin/index.js CHANGED
@@ -62,9 +62,18 @@ for (let i = 0; i < args.length; i++) {
62
62
  case 'global':
63
63
  command = 'global';
64
64
  break;
65
+ case 'init':
66
+ command = 'init';
67
+ break;
65
68
  case 'sync-back':
66
69
  command = 'sync-back';
67
70
  break;
71
+ case 'config':
72
+ command = 'config';
73
+ break;
74
+ case 'mcp':
75
+ command = 'mcp';
76
+ break;
68
77
  case '--tool': case '-t':
69
78
  if (i + 1 >= args.length || args[i + 1].startsWith('-')) {
70
79
  console.error(fmt('red', `错误:${arg} 需要一个值(claude | cursor | codex | all)`));
@@ -109,10 +118,13 @@ for (let i = 0; i < args.length; i++) {
109
118
  function printHelp() {
110
119
  console.log(`用法: ${fmt('bold', 'npx ai-engineering-init')} [命令] [选项]\n`);
111
120
  console.log('命令:');
112
- console.log(` ${fmt('bold', '(无)')} 交互式初始化(安装到当前项目目录)`);
121
+ console.log(` ${fmt('bold', 'init')} 交互式初始化(安装到当前项目目录)`);
113
122
  console.log(` ${fmt('bold', 'update')} 更新已安装的框架文件(跳过用户自定义文件)`);
114
123
  console.log(` ${fmt('bold', 'global')} 全局安装到 ~/.claude / ~/.cursor 等,对所有项目生效`);
115
- console.log(` ${fmt('bold', 'sync-back')} 对比本地技能修改,生成 diff 或提交 GitHub Issue\n`);
124
+ console.log(` ${fmt('bold', 'sync-back')} 对比本地技能修改,生成 diff 或提交 GitHub Issue`);
125
+ console.log(` ${fmt('bold', 'config')} 初始化数据库配置文件(.claude/mysql-config.json)`);
126
+ console.log(` ${fmt('bold', 'mcp')} MCP 服务器管理(安装/卸载/状态检查)\n`);
127
+ console.log(`无命令时显示交互式主菜单。\n`);
116
128
  console.log('选项:');
117
129
  console.log(' --tool, -t <工具> 指定工具: claude | cursor | codex | all');
118
130
  console.log(' --dir, -d <目录> 目标目录(默认:当前目录,仅 init/update 有效)');
@@ -513,16 +525,20 @@ function showDoneHint(toolKey) {
513
525
  console.log('');
514
526
  if (toolKey === 'claude' || toolKey === 'all') {
515
527
  console.log(fmt('cyan', 'Claude Code 使用:'));
516
- console.log(` 1. 按需修改 ${fmt('bold', 'CLAUDE.md')} 中的项目信息`);
528
+ console.log(` 1. ${fmt('bold', '必做')}:修改 ${fmt('bold', 'CLAUDE.md')} — 把 [你的xxx] 占位符替换为项目实际信息`);
517
529
  console.log(` 2. 在 Claude Code 中输入 ${fmt('bold', '/start')} 快速了解项目`);
518
530
  console.log(` 3. 输入 ${fmt('bold', '/dev')} 开始开发新功能`);
519
531
  console.log('');
532
+ console.log(fmt('yellow', ' 💡 CLAUDE.md 和 AGENTS.md 是示例模板,务必替换占位符后使用'));
533
+ console.log(fmt('yellow', ` 💡 运行 ${fmt('bold', hintCmd('mcp'))} 管理 MCP 服务器(云效、语雀等)`));
534
+ console.log('');
520
535
  }
521
536
  if (toolKey === 'cursor' || toolKey === 'all') {
522
537
  console.log(fmt('cyan', 'Cursor 使用:'));
523
538
  console.log(` 1. 在 Cursor Chat 中输入 ${fmt('bold', '/')} 查看所有可用 Skills`);
524
539
  console.log(` 2. 输入 ${fmt('bold', '@技能名')} 手动调用指定技能`);
525
540
  console.log(` 3. 在 Settings → MCP 中确认 MCP 服务器已连接`);
541
+ console.log(fmt('yellow', ` 💡 运行 ${fmt('bold', hintCmd('mcp'))} 管理 MCP 服务器(云效、语雀等)`));
526
542
  console.log('');
527
543
  }
528
544
  if (toolKey === 'codex' || toolKey === 'all') {
@@ -1103,39 +1119,536 @@ function runSyncBack(selectedTool, selectedSkill, doSubmit) {
1103
1119
  console.log('');
1104
1120
  }
1105
1121
 
1106
- // ── 主入口 ────────────────────────────────────────────────────────────────
1107
- if (command === 'update') {
1108
- runUpdate(tool);
1109
- } else if (command === 'global') {
1110
- runGlobal(tool);
1111
- } else if (command === 'sync-back') {
1112
- runSyncBack(tool, skillFilter, submitIssue);
1113
- } else if (tool) {
1114
- run(tool);
1115
- } else {
1116
- // TTY 环境(CI/管道)无法交互,强制要求显式指定 --tool
1122
+ // ── 数据库配置初始化 ──────────────────────────────────────────────────────
1123
+ function runConfig() {
1124
+ if (!process.stdin.isTTY) {
1125
+ console.error(fmt('red', '错误:config 命令需要交互式终端'));
1126
+ process.exit(1);
1127
+ }
1128
+
1129
+ const configPath = path.join(targetDir, '.claude', 'mysql-config.json');
1130
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1131
+
1132
+ const ask = (question) => new Promise((resolve) => {
1133
+ rl.question(question, (answer) => resolve(answer.trim()));
1134
+ });
1135
+
1136
+ const ENV_DEFAULTS = {
1137
+ local: { host: '127.0.0.1', user: 'root', desc: '本地开发环境' },
1138
+ dev: { host: '', user: '', desc: '开发测试环境' },
1139
+ test: { host: '', user: '', desc: '测试环境' },
1140
+ prod: { host: '', user: '', desc: '生产环境' },
1141
+ };
1142
+
1143
+ (async () => {
1144
+ try {
1145
+ // 1. 检测已有配置
1146
+ if (fs.existsSync(configPath)) {
1147
+ console.log(fmt('yellow', `⚠ 配置文件已存在:${configPath}`));
1148
+ const overwrite = await ask(fmt('bold', '是否重新配置?[y/N]: '));
1149
+ if (overwrite.toLowerCase() !== 'y') {
1150
+ console.log('已取消。');
1151
+ rl.close();
1152
+ return;
1153
+ }
1154
+ console.log('');
1155
+ }
1156
+
1157
+ // 2. 选择环境
1158
+ console.log(fmt('cyan', '请选择要配置的数据库环境(多选,用逗号分隔):'));
1159
+ console.log('');
1160
+ console.log(` ${fmt('bold', '1')}) local — 本地开发环境`);
1161
+ console.log(` ${fmt('bold', '2')}) dev — 开发测试环境`);
1162
+ console.log(` ${fmt('bold', '3')}) test — 测试环境`);
1163
+ console.log(` ${fmt('bold', '4')}) prod — 生产环境`);
1164
+ console.log('');
1165
+ const envAnswer = await ask(fmt('bold', '请输入选项(如 1,2 或 1-3): '));
1166
+
1167
+ // 解析选择
1168
+ const envNames = ['local', 'dev', 'test', 'prod'];
1169
+ const selected = new Set();
1170
+ for (const part of envAnswer.split(',')) {
1171
+ const trimmed = part.trim();
1172
+ const rangeMatch = trimmed.match(/^(\d)-(\d)$/);
1173
+ if (rangeMatch) {
1174
+ const start = parseInt(rangeMatch[1], 10);
1175
+ const end = parseInt(rangeMatch[2], 10);
1176
+ for (let n = start; n <= end; n++) {
1177
+ if (n >= 1 && n <= 4) selected.add(envNames[n - 1]);
1178
+ }
1179
+ } else {
1180
+ const n = parseInt(trimmed, 10);
1181
+ if (n >= 1 && n <= 4) selected.add(envNames[n - 1]);
1182
+ }
1183
+ }
1184
+
1185
+ const selectedEnvs = [...selected];
1186
+ if (selectedEnvs.length === 0) {
1187
+ console.error(fmt('red', '未选择任何环境,退出。'));
1188
+ rl.close();
1189
+ process.exit(1);
1190
+ }
1191
+
1192
+ console.log('');
1193
+ console.log(fmt('green', `已选择环境:${selectedEnvs.join(', ')}`));
1194
+ console.log('');
1195
+
1196
+ // 3. 收集每个环境的配置
1197
+ const environments = {};
1198
+ for (const env of selectedEnvs) {
1199
+ const defaults = ENV_DEFAULTS[env];
1200
+ console.log(fmt('cyan', `── ${env} 环境配置 ──`));
1201
+
1202
+ const host = await ask(` host [${defaults.host || '无默认'}]: `) || defaults.host;
1203
+ const port = await ask(' port [3306]: ') || '3306';
1204
+ const user = await ask(` user [${defaults.user || '无默认'}]: `) || defaults.user;
1205
+ const password = await ask(' password: ');
1206
+ const desc = await ask(` 描述 [${defaults.desc}]: `) || defaults.desc;
1207
+ console.log('');
1208
+
1209
+ if (!host) {
1210
+ console.error(fmt('red', `错误:${env} 环境的 host 不能为空`));
1211
+ rl.close();
1212
+ process.exit(1);
1213
+ }
1214
+ if (!user) {
1215
+ console.error(fmt('red', `错误:${env} 环境的 user 不能为空`));
1216
+ rl.close();
1217
+ process.exit(1);
1218
+ }
1219
+
1220
+ environments[env] = {
1221
+ host,
1222
+ port: parseInt(port, 10),
1223
+ user,
1224
+ password,
1225
+ description: desc,
1226
+ };
1227
+ }
1228
+
1229
+ // 4. 选择默认环境
1230
+ let defaultEnv = selectedEnvs[0];
1231
+ if (selectedEnvs.length > 1) {
1232
+ console.log(fmt('cyan', '请选择默认环境:'));
1233
+ selectedEnvs.forEach((env, i) => {
1234
+ console.log(` ${fmt('bold', String(i + 1))}) ${env}`);
1235
+ });
1236
+ const defaultAnswer = await ask(fmt('bold', `请输入选项 [1-${selectedEnvs.length}]: `));
1237
+ const idx = parseInt(defaultAnswer, 10) - 1;
1238
+ if (idx >= 0 && idx < selectedEnvs.length) {
1239
+ defaultEnv = selectedEnvs[idx];
1240
+ }
1241
+ console.log('');
1242
+ }
1243
+
1244
+ // 5. 写入配置文件
1245
+ const config = { defaultEnv, environments };
1246
+ const claudeDir = path.join(targetDir, '.claude');
1247
+ if (!fs.existsSync(claudeDir)) {
1248
+ fs.mkdirSync(claudeDir, { recursive: true });
1249
+ }
1250
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
1251
+ console.log(fmt('green', `✔ 配置已写入:${configPath}`));
1252
+
1253
+ // 6. 确保 .gitignore 包含该文件
1254
+ const gitignorePath = path.join(targetDir, '.gitignore');
1255
+ const ignoreEntry = '.claude/mysql-config.json';
1256
+ let needAppend = true;
1257
+ if (fs.existsSync(gitignorePath)) {
1258
+ const content = fs.readFileSync(gitignorePath, 'utf-8');
1259
+ if (content.split('\n').some(line => line.trim() === ignoreEntry)) {
1260
+ needAppend = false;
1261
+ }
1262
+ }
1263
+ if (needAppend) {
1264
+ const separator = fs.existsSync(gitignorePath) ? '\n' : '';
1265
+ fs.appendFileSync(gitignorePath, `${separator}${ignoreEntry}\n`, 'utf-8');
1266
+ console.log(fmt('green', `✔ 已添加 ${ignoreEntry} 到 .gitignore`));
1267
+ }
1268
+
1269
+ console.log('');
1270
+ console.log(fmt('green', '数据库配置初始化完成!'));
1271
+ console.log(`使用 ${fmt('bold', 'mysql-debug')} 技能时将自动读取此配置。`);
1272
+ } finally {
1273
+ rl.close();
1274
+ }
1275
+ })();
1276
+ }
1277
+
1278
+ // ── MCP 服务器管理 ──────────────────────────────────────────────────────────
1279
+
1280
+ const MCP_REGISTRY = [
1281
+ {
1282
+ name: 'sequential-thinking',
1283
+ package: '@modelcontextprotocol/server-sequential-thinking',
1284
+ description: '链式推理 — 深度分析、仔细思考、全面评估时使用',
1285
+ env: {},
1286
+ recommended: true,
1287
+ },
1288
+ {
1289
+ name: 'context7',
1290
+ package: '@upstash/context7-mcp',
1291
+ description: '官方文档查询 — 最佳实践、官方文档、标准写法时使用',
1292
+ env: {},
1293
+ recommended: true,
1294
+ },
1295
+ {
1296
+ name: 'github',
1297
+ package: '@modelcontextprotocol/server-github',
1298
+ description: 'GitHub 集成 — 查询 Issues、PR、仓库信息',
1299
+ env: { GITHUB_PERSONAL_ACCESS_TOKEN: '${GITHUB_TOKEN}' },
1300
+ recommended: true,
1301
+ },
1302
+ {
1303
+ name: 'filesystem',
1304
+ package: '@modelcontextprotocol/server-filesystem',
1305
+ description: '文件系统访问 — 读写项目外的文件',
1306
+ env: {},
1307
+ recommended: false,
1308
+ },
1309
+ {
1310
+ name: 'fetch',
1311
+ package: '@anthropic-ai/mcp-fetch',
1312
+ description: '网页抓取 — 获取网页内容',
1313
+ env: {},
1314
+ recommended: false,
1315
+ },
1316
+ {
1317
+ name: 'yunxiao',
1318
+ package: 'alibabacloud-devops-mcp-server',
1319
+ description: '阿里云效 — DevOps 项目管理、代码仓库、流水线集成',
1320
+ env: { YUNXIAO_ACCESS_TOKEN: '<YOUR_TOKEN>' },
1321
+ recommended: false,
1322
+ },
1323
+ {
1324
+ name: 'yuque',
1325
+ package: 'yuque-mcp',
1326
+ description: '语雀 — 知识库文档读写、搜索、团队协作',
1327
+ env: { YUQUE_TOKEN: '<YOUR_TOKEN>' },
1328
+ recommended: false,
1329
+ },
1330
+ ];
1331
+
1332
+ /** MCP 配置文件路径映射 */
1333
+ const MCP_CONFIG_PATHS = {
1334
+ claude: { file: '.claude/settings.json', key: 'mcpServers' },
1335
+ cursor: { file: '.cursor/mcp.json', key: 'mcpServers' },
1336
+ };
1337
+
1338
+ /** 检测项目中已有的工具配置目录 */
1339
+ function detectMcpTools() {
1340
+ const tools = [];
1341
+ if (isRealDir(path.join(targetDir, '.claude'))) tools.push('claude');
1342
+ if (isRealDir(path.join(targetDir, '.cursor'))) tools.push('cursor');
1343
+ return tools;
1344
+ }
1345
+
1346
+ /** 读取指定工具的 MCP 已配置服务器 */
1347
+ function getMcpServers(toolName) {
1348
+ const config = MCP_CONFIG_PATHS[toolName];
1349
+ if (!config) return {};
1350
+ const filePath = path.join(targetDir, config.file);
1351
+ try {
1352
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
1353
+ return data[config.key] || {};
1354
+ } catch { return {}; }
1355
+ }
1356
+
1357
+ /** 写入指定工具的 MCP 配置(保留文件其他字段) */
1358
+ function setMcpServers(toolName, mcpServers) {
1359
+ const config = MCP_CONFIG_PATHS[toolName];
1360
+ if (!config) return;
1361
+ const filePath = path.join(targetDir, config.file);
1362
+ let data = {};
1363
+ try { data = JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { /* 新建 */ }
1364
+ data[config.key] = mcpServers;
1365
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
1366
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
1367
+ }
1368
+
1369
+ /** 构建单个 MCP 服务器的配置对象 */
1370
+ function buildMcpServerConfig(entry) {
1371
+ const config = {
1372
+ command: 'npx',
1373
+ args: ['-y', entry.package],
1374
+ };
1375
+ if (Object.keys(entry.env).length > 0) {
1376
+ config.env = { ...entry.env };
1377
+ }
1378
+ return config;
1379
+ }
1380
+
1381
+ /** 获取所有工具中已安装的 MCP 服务器名称集合 */
1382
+ function getInstalledMcpNames(tools) {
1383
+ const names = new Set();
1384
+ for (const t of tools) {
1385
+ const servers = getMcpServers(t);
1386
+ for (const name of Object.keys(servers)) names.add(name);
1387
+ }
1388
+ return names;
1389
+ }
1390
+
1391
+ function runMcp() {
1392
+ if (!process.stdin.isTTY) {
1393
+ console.error(fmt('red', '错误:mcp 命令需要交互式终端'));
1394
+ process.exit(1);
1395
+ }
1396
+
1397
+ const tools = detectMcpTools();
1398
+ if (tools.length === 0) {
1399
+ console.log(fmt('yellow', '⚠ 当前目录未检测到 .claude/ 或 .cursor/ 配置目录。'));
1400
+ console.log(` 请先运行: ${fmt('bold', hintCmd('init --tool claude'))}`);
1401
+ console.log('');
1402
+ process.exit(1);
1403
+ }
1404
+
1405
+ console.log(` 检测到工具: ${fmt('bold', tools.join(', '))}`);
1406
+ console.log('');
1407
+
1408
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1409
+ const ask = (question) => new Promise((resolve) => {
1410
+ rl.question(question, (answer) => resolve(answer.trim()));
1411
+ });
1412
+
1413
+ (async () => {
1414
+ try {
1415
+ console.log(fmt('cyan', '请选择 MCP 操作:'));
1416
+ console.log('');
1417
+ console.log(` ${fmt('bold', '1')}) ${fmt('green', '安装 MCP 服务器')} — 从预置列表选择并安装到配置`);
1418
+ console.log(` ${fmt('bold', '2')}) ${fmt('red', '卸载 MCP 服务器')} — 从已安装列表中移除`);
1419
+ console.log(` ${fmt('bold', '3')}) ${fmt('cyan', '查看状态')} — 检查已配置的 MCP 服务器`);
1420
+ console.log(` ${fmt('bold', '4')}) ${fmt('yellow', '一键推荐安装')} — 安装所有推荐的 MCP 服务器`);
1421
+ console.log('');
1422
+ const action = await ask(fmt('bold', '请输入选项 [1-4]: '));
1423
+ console.log('');
1424
+
1425
+ switch (action) {
1426
+ case '1': await mcpInstall(tools, ask); break;
1427
+ case '2': await mcpUninstall(tools, ask); break;
1428
+ case '3': mcpStatus(tools); break;
1429
+ case '4': await mcpRecommend(tools, ask); break;
1430
+ default:
1431
+ console.error(fmt('red', '无效选项,退出。'));
1432
+ process.exit(1);
1433
+ }
1434
+ } finally {
1435
+ rl.close();
1436
+ }
1437
+ })();
1438
+ }
1439
+
1440
+ /** 安装 MCP 服务器 */
1441
+ async function mcpInstall(tools, ask) {
1442
+ const installed = getInstalledMcpNames(tools);
1443
+
1444
+ console.log(fmt('cyan', '可用的 MCP 服务器:'));
1445
+ console.log('');
1446
+ for (let i = 0; i < MCP_REGISTRY.length; i++) {
1447
+ const entry = MCP_REGISTRY[i];
1448
+ const tags = [];
1449
+ if (installed.has(entry.name)) tags.push(fmt('green', '[已安装]'));
1450
+ if (entry.recommended) tags.push(fmt('yellow', '[推荐]'));
1451
+ const tagStr = tags.length > 0 ? ' ' + tags.join(' ') : '';
1452
+ console.log(` ${fmt('bold', String(i + 1))}) ${fmt('bold', entry.name)}${tagStr}`);
1453
+ console.log(` ${entry.description}`);
1454
+ }
1455
+ console.log('');
1456
+ const answer = await ask(fmt('bold', '请选择要安装的服务器(逗号分隔,如 1,2,3): '));
1457
+ const indices = answer.split(',').map(s => parseInt(s.trim(), 10) - 1).filter(i => i >= 0 && i < MCP_REGISTRY.length);
1458
+
1459
+ if (indices.length === 0) {
1460
+ console.log(fmt('yellow', '未选择任何服务器,退出。'));
1461
+ return;
1462
+ }
1463
+
1464
+ const selected = indices.map(i => MCP_REGISTRY[i]);
1465
+ console.log('');
1466
+
1467
+ // 处理需要 env 的服务器
1468
+ for (const entry of selected) {
1469
+ if (Object.keys(entry.env).length > 0) {
1470
+ console.log(fmt('cyan', `── ${entry.name} 环境变量配置 ──`));
1471
+ for (const [key, defaultVal] of Object.entries(entry.env)) {
1472
+ const val = await ask(` ${key} [${defaultVal}]: `);
1473
+ if (val) entry.env[key] = val;
1474
+ }
1475
+ console.log('');
1476
+ }
1477
+ }
1478
+
1479
+ // 写入所有检测到的工具配置
1480
+ for (const toolName of tools) {
1481
+ const servers = getMcpServers(toolName);
1482
+ for (const entry of selected) {
1483
+ servers[entry.name] = buildMcpServerConfig(entry);
1484
+ }
1485
+ setMcpServers(toolName, servers);
1486
+ console.log(` ${fmt('green', '✓')} ${toolName}: 已写入 ${selected.map(e => e.name).join(', ')}`);
1487
+ }
1488
+
1489
+ console.log('');
1490
+ console.log(fmt('green', fmt('bold', `✅ 已安装 ${selected.length} 个 MCP 服务器!`)));
1491
+ console.log('');
1492
+ }
1493
+
1494
+ /** 卸载 MCP 服务器 */
1495
+ async function mcpUninstall(tools, ask) {
1496
+ // 收集所有已安装的服务器(合并去重)
1497
+ const allServers = new Map(); // name → 出现在哪些工具中
1498
+ for (const toolName of tools) {
1499
+ const servers = getMcpServers(toolName);
1500
+ for (const name of Object.keys(servers)) {
1501
+ if (!allServers.has(name)) allServers.set(name, []);
1502
+ allServers.get(name).push(toolName);
1503
+ }
1504
+ }
1505
+
1506
+ if (allServers.size === 0) {
1507
+ console.log(fmt('yellow', ' 当前没有已安装的 MCP 服务器。'));
1508
+ console.log(` 运行 ${fmt('bold', hintCmd('mcp'))} 安装服务器。`);
1509
+ console.log('');
1510
+ return;
1511
+ }
1512
+
1513
+ const serverNames = [...allServers.keys()];
1514
+ console.log(fmt('cyan', '已安装的 MCP 服务器:'));
1515
+ console.log('');
1516
+ for (let i = 0; i < serverNames.length; i++) {
1517
+ const name = serverNames[i];
1518
+ const toolList = allServers.get(name).join(', ');
1519
+ console.log(` ${fmt('bold', String(i + 1))}) ${fmt('bold', name)} ${fmt('magenta', `(${toolList})`)}`);
1520
+ }
1521
+ console.log('');
1522
+ const answer = await ask(fmt('bold', '请选择要卸载的服务器(逗号分隔): '));
1523
+ const indices = answer.split(',').map(s => parseInt(s.trim(), 10) - 1).filter(i => i >= 0 && i < serverNames.length);
1524
+
1525
+ if (indices.length === 0) {
1526
+ console.log(fmt('yellow', '未选择任何服务器,退出。'));
1527
+ return;
1528
+ }
1529
+
1530
+ const toRemove = indices.map(i => serverNames[i]);
1531
+ console.log('');
1532
+
1533
+ for (const toolName of tools) {
1534
+ const servers = getMcpServers(toolName);
1535
+ let removed = 0;
1536
+ for (const name of toRemove) {
1537
+ if (name in servers) {
1538
+ delete servers[name];
1539
+ removed++;
1540
+ }
1541
+ }
1542
+ if (removed > 0) {
1543
+ setMcpServers(toolName, servers);
1544
+ console.log(` ${fmt('green', '✓')} ${toolName}: 已移除 ${toRemove.filter(n => !servers[n]).join(', ')}`);
1545
+ }
1546
+ }
1547
+
1548
+ console.log('');
1549
+ console.log(fmt('green', fmt('bold', `✅ 已卸载 ${toRemove.length} 个 MCP 服务器!`)));
1550
+ console.log('');
1551
+ }
1552
+
1553
+ /** 查看 MCP 状态 */
1554
+ function mcpStatus(tools) {
1555
+ let hasAny = false;
1556
+
1557
+ for (const toolName of tools) {
1558
+ const servers = getMcpServers(toolName);
1559
+ const names = Object.keys(servers);
1560
+
1561
+ console.log(fmt('cyan', `[${toolName}]`) + ` ${MCP_CONFIG_PATHS[toolName].file}`);
1562
+
1563
+ if (names.length === 0) {
1564
+ console.log(` ${fmt('yellow', '(无已安装的 MCP 服务器)')}`);
1565
+ } else {
1566
+ hasAny = true;
1567
+ for (const name of names) {
1568
+ const srv = servers[name];
1569
+ const pkg = (srv.args || []).find(a => a.startsWith('@')) || '—';
1570
+ const envKeys = srv.env ? Object.keys(srv.env).join(', ') : '—';
1571
+ console.log(` ${fmt('green', '●')} ${fmt('bold', name)}`);
1572
+ console.log(` 包: ${pkg} | 环境变量: ${envKeys}`);
1573
+ }
1574
+ }
1575
+ console.log('');
1576
+ }
1577
+
1578
+ if (!hasAny) {
1579
+ console.log(fmt('yellow', '💡 未安装任何 MCP 服务器。'));
1580
+ console.log(` 运行 ${fmt('bold', hintCmd('mcp'))} 开始安装。`);
1581
+ console.log('');
1582
+ }
1583
+ }
1584
+
1585
+ /** 一键推荐安装 */
1586
+ async function mcpRecommend(tools, ask) {
1587
+ const installed = getInstalledMcpNames(tools);
1588
+ const toInstall = MCP_REGISTRY.filter(e => e.recommended && !installed.has(e.name));
1589
+
1590
+ if (toInstall.length === 0) {
1591
+ console.log(fmt('green', ' ✓ 所有推荐的 MCP 服务器已安装!'));
1592
+ console.log('');
1593
+ mcpStatus(tools);
1594
+ return;
1595
+ }
1596
+
1597
+ console.log(fmt('cyan', '将安装以下推荐服务器:'));
1598
+ console.log('');
1599
+ for (const entry of toInstall) {
1600
+ console.log(` ${fmt('green', '●')} ${fmt('bold', entry.name)} — ${entry.description}`);
1601
+ }
1602
+ console.log('');
1603
+
1604
+ // 处理需要 env 的服务器
1605
+ for (const entry of toInstall) {
1606
+ if (Object.keys(entry.env).length > 0) {
1607
+ console.log(fmt('cyan', `── ${entry.name} 环境变量配置 ──`));
1608
+ for (const [key, defaultVal] of Object.entries(entry.env)) {
1609
+ const val = await ask(` ${key} [${defaultVal}]: `);
1610
+ if (val) entry.env[key] = val;
1611
+ }
1612
+ console.log('');
1613
+ }
1614
+ }
1615
+
1616
+ // 写入配置
1617
+ for (const toolName of tools) {
1618
+ const servers = getMcpServers(toolName);
1619
+ for (const entry of toInstall) {
1620
+ servers[entry.name] = buildMcpServerConfig(entry);
1621
+ }
1622
+ setMcpServers(toolName, servers);
1623
+ console.log(` ${fmt('green', '✓')} ${toolName}: 已写入 ${toInstall.map(e => e.name).join(', ')}`);
1624
+ }
1625
+
1626
+ console.log('');
1627
+ console.log(fmt('green', fmt('bold', `✅ 已安装 ${toInstall.length} 个推荐 MCP 服务器!`)));
1628
+ console.log('');
1629
+ }
1630
+
1631
+ // ── 工具选择菜单(init 用)─────────────────────────────────────────────────
1632
+ function showToolMenu() {
1117
1633
  if (!process.stdin.isTTY) {
1118
1634
  console.error(fmt('red', '错误:非交互环境下必须指定 --tool 参数'));
1119
- console.error(` 示例: ${fmt('bold', hintCmd('--tool claude'))}`);
1635
+ console.error(` 示例: ${fmt('bold', hintCmd('init --tool claude'))}`);
1120
1636
  process.exit(1);
1121
1637
  }
1122
1638
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1123
- console.log(fmt('cyan', '请选择操作:'));
1639
+ console.log(fmt('cyan', '请选择要初始化的工具:'));
1124
1640
  console.log('');
1125
- console.log(` ${fmt('bold', '1')}) ${fmt('green', 'Claude Code')} — 初始化到当前项目 .claude/ + CLAUDE.md`);
1126
- console.log(` ${fmt('bold', '2')}) ${fmt('cyan', 'Cursor')} — 初始化到当前项目 .cursor/(Skills + Agents)`);
1127
- console.log(` ${fmt('bold', '3')}) ${fmt('yellow', 'OpenAI Codex')} — 初始化到当前项目 .codex/ + AGENTS.md`);
1128
- console.log(` ${fmt('bold', '4')}) ${fmt('blue', '全部工具')} — 同时初始化 Claude + Cursor + Codex 到当前项目`);
1129
- console.log(` ${fmt('bold', '5')}) ${fmt('magenta', '全局安装')} — 安装到 ~/.claude / ~/.cursor,对所有项目生效`);
1641
+ console.log(` ${fmt('bold', '1')}) ${fmt('green', 'Claude Code')} — .claude/ + CLAUDE.md`);
1642
+ console.log(` ${fmt('bold', '2')}) ${fmt('cyan', 'Cursor')} — .cursor/(Skills + Agents)`);
1643
+ console.log(` ${fmt('bold', '3')}) ${fmt('yellow', 'OpenAI Codex')} — .codex/ + AGENTS.md`);
1644
+ console.log(` ${fmt('bold', '4')}) ${fmt('blue', '全部工具')} — 同时初始化 Claude + Cursor + Codex`);
1130
1645
  console.log('');
1131
- rl.question(fmt('bold', '请输入选项 [1-5]: '), (answer) => {
1646
+ rl.question(fmt('bold', '请输入选项 [1-4]: '), (answer) => {
1132
1647
  rl.close();
1133
1648
  const map = { '1': 'claude', '2': 'cursor', '3': 'codex', '4': 'all' };
1134
1649
  const selected = map[answer.trim()];
1135
1650
  console.log('');
1136
- if (answer.trim() === '5') {
1137
- runGlobal('all');
1138
- } else if (selected) {
1651
+ if (selected) {
1139
1652
  run(selected);
1140
1653
  } else {
1141
1654
  console.error(fmt('red', '无效选项,退出。'));
@@ -1143,3 +1656,76 @@ if (command === 'update') {
1143
1656
  }
1144
1657
  });
1145
1658
  }
1659
+
1660
+ // ── 主菜单(无命令时展示)──────────────────────────────────────────────────
1661
+ function showMainMenu() {
1662
+ if (!process.stdin.isTTY) {
1663
+ console.error(fmt('red', '错误:非交互环境下必须指定命令'));
1664
+ console.error(` 示例: ${fmt('bold', hintCmd('init --tool claude'))}`);
1665
+ console.error(` 运行 ${fmt('bold', hintCmd('--help'))} 查看所有命令`);
1666
+ process.exit(1);
1667
+ }
1668
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1669
+ console.log(fmt('cyan', '请选择操作:'));
1670
+ console.log('');
1671
+ console.log(` ${fmt('bold', '1')}) ${fmt('green', '初始化')} — 安装 AI 工具配置到当前项目`);
1672
+ console.log(` ${fmt('bold', '2')}) ${fmt('cyan', '更新')} — 更新已安装的框架文件`);
1673
+ console.log(` ${fmt('bold', '3')}) ${fmt('yellow', '全局安装')} — 安装到 ~/.claude 等,对所有项目生效`);
1674
+ console.log(` ${fmt('bold', '4')}) ${fmt('magenta', '技能同步反馈')} — 对比本地技能修改,生成 diff`);
1675
+ console.log(` ${fmt('bold', '5')}) ${fmt('blue', '数据库配置')} — 初始化 mysql-config.json(数据库连接信息)`);
1676
+ console.log(` ${fmt('bold', '6')}) ${fmt('green', 'MCP 管理')} — MCP 服务器安装/卸载/状态检查`);
1677
+ console.log('');
1678
+ rl.question(fmt('bold', '请输入选项 [1-6]: '), (answer) => {
1679
+ rl.close();
1680
+ console.log('');
1681
+ switch (answer.trim()) {
1682
+ case '1':
1683
+ showToolMenu();
1684
+ break;
1685
+ case '2':
1686
+ runUpdate(tool);
1687
+ break;
1688
+ case '3':
1689
+ runGlobal(tool || 'all');
1690
+ break;
1691
+ case '4':
1692
+ runSyncBack(tool, skillFilter, submitIssue);
1693
+ break;
1694
+ case '5':
1695
+ runConfig();
1696
+ break;
1697
+ case '6':
1698
+ runMcp();
1699
+ break;
1700
+ default:
1701
+ console.error(fmt('red', '无效选项,退出。'));
1702
+ process.exit(1);
1703
+ }
1704
+ });
1705
+ }
1706
+
1707
+ // ── 主入口 ────────────────────────────────────────────────────────────────
1708
+ if (command === 'init') {
1709
+ // 显式 init 子命令
1710
+ if (tool) {
1711
+ run(tool);
1712
+ } else {
1713
+ showToolMenu();
1714
+ }
1715
+ } else if (command === 'update') {
1716
+ runUpdate(tool);
1717
+ } else if (command === 'global') {
1718
+ runGlobal(tool);
1719
+ } else if (command === 'sync-back') {
1720
+ runSyncBack(tool, skillFilter, submitIssue);
1721
+ } else if (command === 'config') {
1722
+ runConfig();
1723
+ } else if (command === 'mcp') {
1724
+ runMcp();
1725
+ } else if (tool) {
1726
+ // 向后兼容:无 command 但有 --tool,当作 init 执行
1727
+ run(tool);
1728
+ } else {
1729
+ // 无命令无参数:显示主菜单
1730
+ showMainMenu();
1731
+ }