ai-engineering-init 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,5 +37,11 @@
37
37
  }
38
38
  ]
39
39
  },
40
- "mcpServers": {}
40
+ "mcpServers": {
41
+ "codex": {
42
+ "command": "/Users/xujiajun/.nvm/versions/node/v20.19.6/bin/codex",
43
+ "args": ["mcp-server"],
44
+ "description": "OpenAI Codex CLI - 代码分析/算法实现/代码审查"
45
+ }
46
+ }
41
47
  }
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  > 一键初始化 AI 工程化配置,支持 Claude Code、Cursor、OpenAI Codex 等主流 AI 开发工具。
4
4
 
5
+ [![npm version](https://img.shields.io/npm/v/ai-engineering-init)](https://www.npmjs.com/package/ai-engineering-init)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
7
+
5
8
  ## 快速开始
6
9
 
7
10
  ### 方式一:npx(推荐,无需克隆)
@@ -84,12 +87,15 @@ cd ai-engineering-init
84
87
  | `skills/` | Codex 技能配置 |
85
88
  | `AGENTS.md` | AI Agent 项目规范说明 |
86
89
 
87
- ## Skills 列表(68个)
90
+ > **MCP Server 支持**:Codex CLI 可通过 `codex mcp-server` 作为 MCP Server 暴露给 Claude Code,
91
+ > 配置写入 `.claude/settings.json` 的 `mcpServers` 后,Claude 可直接调用 `codex` / `codex-reply` 工具进行代码审查。
92
+
93
+ ## Skills 列表(69个)
88
94
 
89
95
  <details>
90
96
  <summary>展开查看完整列表</summary>
91
97
 
92
- **通用后端技能(33个)**
98
+ **通用后端技能(34个)**
93
99
 
94
100
  | 技能 | 触发场景 |
95
101
  |------|---------|
@@ -120,7 +126,7 @@ cd ai-engineering-init
120
126
  | `tech-decision` | 技术选型、方案对比 |
121
127
  | `task-tracker` | 任务进度跟踪 |
122
128
  | `project-navigator` | 项目结构导航、文件定位 |
123
- | `collaborating-with-codex` | 与 Codex 协同开发 |
129
+ | `collaborating-with-codex` | 与 Codex 协同开发(支持 MCP Server 直调) |
124
130
  | `collaborating-with-gemini` | 与 Gemini 协同开发 |
125
131
  | `banana-image` | AI 图片生成、海报、缩略图 |
126
132
  | `add-skill` | 创建新技能 |
@@ -139,6 +145,7 @@ cd ai-engineering-init
139
145
  | `leniu-backend-annotations` | `@RequiresAuthentication`、分组校验 |
140
146
  | `leniu-utils-toolkit` | BeanUtil、CollUtil、StrUtil、RedisUtil |
141
147
  | `leniu-code-patterns` | net.xnzn 包名规范、禁止事项 |
148
+ | `leniu-brainstorm` | 云食堂方案头脑风暴 |
142
149
  | `leniu-data-permission` | 云食堂数据权限控制 |
143
150
  | `leniu-java-entity` | Entity/VO/DTO/Param 数据类规范 |
144
151
  | `leniu-java-mybatis` | MyBatis Plus、LambdaQueryWrapper、XML 映射 |
@@ -184,39 +191,13 @@ cd ai-engineering-init
184
191
 
185
192
  1. 修改 `AGENTS.md` 中的项目说明
186
193
  2. 使用 `.codex/skills/` 下的技能辅助开发
194
+ 3. (可选)以 MCP Server 接入 Claude Code:`.claude/settings.json` → `mcpServers.codex`,重启后 Claude 可直接调用 `codex` / `codex-reply` 工具
187
195
 
188
196
  ## 更新日志
189
197
 
190
- ### v1.2.0(2026-03-01)
191
-
192
- - 新增 **Cursor Hooks 支持**(`.cursor/hooks.json` + `.cursor/hooks/`)
193
- - `beforeSubmitPrompt`:检测用户意图,自动注入相关技能文档路径引导 Agent 阅读(对应 Claude 的 `UserPromptSubmit`)
194
- - `preToolUse`:拦截危险 Shell 命令(`rm -rf /`、`drop database` 等),兼容 Cursor `Shell` 工具名
195
- - `stop`:复用 Claude 的 `stop.js`,支持 nul 文件清理和完成音效
196
- - 修复 **leniu-java-export** 技能示例代码:移除错误的 `Executors.readInSystem()` 包装(业务查询默认在商户库执行)
197
- - 修复 **leniu-java-total-line** 技能:同步修正双库架构说明,`Executors.doInSystem()` 仅用于访问系统库
198
-
199
- ### v1.1.1(2026-02-24)
200
-
201
- - 优化 **npm 发布流程**
202
- - 预发布版本(含 `-`)自动发布到 `test` 标签
203
- - 正式版本自动发布到 `latest` 标签
204
- - GitHub Release 自动标记预发布版本(`prerelease: true`)
205
-
206
- ### v1.1.0(2026-02-24)
207
-
208
- - 新增 **Cursor** 工具支持(`.cursor/` 目录)
209
- - 同步 68 个 Skills 到 `.cursor/skills/`
210
- - 新增 Subagents 配置(`code-reviewer`、`project-manager`)
211
- - 新增 MCP 服务器配置(`sequential-thinking`、`context7`、`github`)
212
- - 新增 **25 个 leniu 云食堂专项技能**
213
- - 覆盖金额处理、并发、MQ、定时任务、报表、餐次、营销规则等场景
214
-
215
- ### v1.0.0
198
+ 查看完整更新历史:[CHANGELOG.md](./CHANGELOG.md)
216
199
 
217
- - 初始版本,支持 Claude Code OpenAI Codex
218
- - 内置通用后端技能、OpenSpec 工作流技能
219
- - 自动化 Hooks(技能强制评估、代码规范检查)
200
+ **v1.2.1 新增**:`update` 命令一键更新框架文件;Codex MCP Server 集成;拆分独立 CHANGELOG.md。
220
201
 
221
202
  ## License
222
203
 
package/bin/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * AI Engineering 初始化 CLI
3
+ * AI Engineering 初始化 / 更新 CLI
4
4
  * 用法:
5
- * npx ai-engineering-init # 交互式
5
+ * npx ai-engineering-init # 交互式初始化
6
6
  * npx ai-engineering-init --tool claude
7
- * npx ai-engineering-init --tool codex
8
7
  * npx ai-engineering-init --tool all
8
+ * npx ai-engineering-init update # 自动检测已安装工具并更新
9
+ * npx ai-engineering-init update --tool claude
9
10
  */
10
11
  'use strict';
11
12
 
@@ -17,43 +18,58 @@ const readline = require('readline');
17
18
  const c = {
18
19
  reset: '\x1b[0m', bold: '\x1b[1m',
19
20
  red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m',
20
- blue: '\x1b[34m', cyan: '\x1b[36m',
21
+ blue: '\x1b[34m', cyan: '\x1b[36m', magenta: '\x1b[35m',
21
22
  };
22
23
  const fmt = (color, text) => `${c[color]}${text}${c.reset}`;
23
24
 
25
+ // ── 版本 ───────────────────────────────────────────────────────────────────
26
+ const PKG_VERSION = require('../package.json').version;
27
+
24
28
  // ── Banner ─────────────────────────────────────────────────────────────────
25
29
  console.log('');
26
30
  console.log(fmt('blue', fmt('bold', '┌─────────────────────────────────────────┐')));
27
- console.log(fmt('blue', fmt('bold', '│ AI Engineering 初始化工具 v1.1 │')));
31
+ console.log(fmt('blue', fmt('bold', `│ AI Engineering 工具 v${PKG_VERSION} │`)));
28
32
  console.log(fmt('blue', fmt('bold', '└─────────────────────────────────────────┘')));
29
33
  console.log('');
30
34
 
31
35
  // ── 参数解析 ───────────────────────────────────────────────────────────────
32
36
  const args = process.argv.slice(2);
37
+ let command = ''; // 'init' | 'update'
33
38
  let tool = '';
34
39
  let targetDir = process.cwd();
35
40
  let force = false;
36
41
 
37
42
  for (let i = 0; i < args.length; i++) {
38
43
  switch (args[i]) {
39
- case '--tool': case '-t': tool = args[++i]; break;
44
+ case 'update': command = 'update'; break;
45
+ case '--tool': case '-t': tool = args[++i]; break;
40
46
  case '--dir': case '-d': targetDir = path.resolve(args[++i]); break;
41
- case '--force':case '-f': force = true; break;
47
+ case '--force':case '-f': force = true; break;
42
48
  case '--help': case '-h':
43
- console.log(`用法: ${fmt('bold', 'npx ai-engineering-init')} [选项]\n`);
44
- console.log('选项:');
45
- console.log(' --tool, -t <工具> 指定工具: claude | cursor | codex | all');
46
- console.log(' --dir, -d <目录> 目标目录(默认:当前目录)');
47
- console.log(' --force,-f 强制覆盖已有文件');
48
- console.log(' --help, -h 显示此帮助\n');
49
- console.log('示例:');
50
- console.log(' npx ai-engineering-init --tool claude');
51
- console.log(' npx ai-engineering-init --tool all --dir /path/to/project\n');
49
+ printHelp();
52
50
  process.exit(0);
53
51
  }
54
52
  }
55
53
 
56
- // ── 工具定义 ───────────────────────────────────────────────────────────────
54
+ function printHelp() {
55
+ console.log(`用法: ${fmt('bold', 'npx ai-engineering-init')} [命令] [选项]\n`);
56
+ console.log('命令:');
57
+ console.log(` ${fmt('bold', '(无)') } 交互式初始化`);
58
+ console.log(` ${fmt('bold', 'update')} 更新已安装的框架文件(跳过用户自定义文件)\n`);
59
+ console.log('选项:');
60
+ console.log(' --tool, -t <工具> 指定工具: claude | cursor | codex | all');
61
+ console.log(' --dir, -d <目录> 目标目录(默认:当前目录)');
62
+ console.log(' --force,-f 强制覆盖(init 时覆盖已有文件;update 时同时更新保留文件)');
63
+ console.log(' --help, -h 显示此帮助\n');
64
+ console.log('示例:');
65
+ console.log(' npx ai-engineering-init --tool claude');
66
+ console.log(' npx ai-engineering-init --tool all --dir /path/to/project');
67
+ console.log(' npx ai-engineering-init update # 自动检测已安装工具');
68
+ console.log(' npx ai-engineering-init update --tool claude # 只更新 Claude');
69
+ console.log(' npx ai-engineering-init update --force # 强制更新,包括保留文件\n');
70
+ }
71
+
72
+ // ── 工具定义(init 用) ──────────────────────────────────────────────────────
57
73
  const TOOLS = {
58
74
  claude: {
59
75
  label: 'Claude Code',
@@ -77,9 +93,66 @@ const TOOLS = {
77
93
  },
78
94
  };
79
95
 
80
- // ── 工具函数 ───────────────────────────────────────────────────────────────
96
+ // ── 更新规则(update 用) ────────────────────────────────────────────────────
97
+ // update: 框架文件,始终从 npm 包最新版本覆盖
98
+ // preserve: 用户自定义文件,默认跳过(--force 时强制更新)
99
+ const UPDATE_RULES = {
100
+ claude: {
101
+ label: 'Claude Code',
102
+ detect: '.claude', // 检测目录,判断是否已安装
103
+ update: [
104
+ { src: '.claude/skills', dest: '.claude/skills', label: 'Skills(技能库)', isDir: true },
105
+ { src: '.claude/commands', dest: '.claude/commands', label: 'Commands(快捷命令)', isDir: true },
106
+ { src: '.claude/agents', dest: '.claude/agents', label: 'Agents(子代理)', isDir: true },
107
+ { src: '.claude/hooks', dest: '.claude/hooks', label: 'Hooks(钩子脚本)', isDir: true },
108
+ { src: '.claude/templates', dest: '.claude/templates', label: 'Templates', isDir: true },
109
+ { src: '.claude/framework-config.json', dest: '.claude/framework-config.json', label: 'framework-config.json' },
110
+ ],
111
+ preserve: [
112
+ { dest: '.claude/settings.json', reason: '包含用户 MCP 配置和权限设置' },
113
+ { dest: 'CLAUDE.md', reason: '包含项目自定义规范' },
114
+ ],
115
+ },
116
+ cursor: {
117
+ label: 'Cursor',
118
+ detect: '.cursor',
119
+ update: [
120
+ { src: '.cursor/skills', dest: '.cursor/skills', label: 'Skills(技能库)', isDir: true },
121
+ { src: '.cursor/agents', dest: '.cursor/agents', label: 'Agents(子代理)', isDir: true },
122
+ { src: '.cursor/hooks', dest: '.cursor/hooks', label: 'Hooks(钩子脚本)', isDir: true },
123
+ { src: '.cursor/hooks.json', dest: '.cursor/hooks.json', label: 'hooks.json(Hooks 配置)' },
124
+ ],
125
+ preserve: [
126
+ { dest: '.cursor/mcp.json', reason: '包含用户 MCP 服务器配置' },
127
+ ],
128
+ },
129
+ codex: {
130
+ label: 'OpenAI Codex',
131
+ detect: '.codex',
132
+ update: [
133
+ { src: '.codex/skills', dest: '.codex/skills', label: 'Skills(技能库)', isDir: true },
134
+ ],
135
+ preserve: [
136
+ { dest: 'AGENTS.md', reason: '包含项目自定义 Agent 规范' },
137
+ ],
138
+ },
139
+ };
140
+
141
+ // ── 公共工具函数 ───────────────────────────────────────────────────────────
81
142
  const SOURCE_DIR = path.join(__dirname, '..');
82
143
 
144
+ /** 统计目录中的文件总数 */
145
+ function countFiles(dir) {
146
+ if (!fs.existsSync(dir)) return 0;
147
+ let count = 0;
148
+ for (const entry of fs.readdirSync(dir)) {
149
+ const full = path.join(dir, entry);
150
+ count += fs.statSync(full).isDirectory() ? countFiles(full) : 1;
151
+ }
152
+ return count;
153
+ }
154
+
155
+ /** 递归复制目录 */
83
156
  function copyDir(src, dest) {
84
157
  if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
85
158
  for (const entry of fs.readdirSync(src)) {
@@ -89,6 +162,7 @@ function copyDir(src, dest) {
89
162
  }
90
163
  }
91
164
 
165
+ // ── INIT 逻辑 ──────────────────────────────────────────────────────────────
92
166
  function copyItem({ src, dest, label, isDir }) {
93
167
  const srcPath = path.join(SOURCE_DIR, src);
94
168
  const destPath = path.join(targetDir, dest);
@@ -137,7 +211,6 @@ function showDoneHint(toolKey) {
137
211
  }
138
212
  }
139
213
 
140
- // ── 主逻辑 ────────────────────────────────────────────────────────────────
141
214
  function run(selectedTool) {
142
215
  if (!['claude', 'cursor', 'codex', 'all'].includes(selectedTool)) {
143
216
  console.error(fmt('red', `无效工具: ${selectedTool}。有效选项: claude | cursor | codex | all`));
@@ -157,16 +230,152 @@ function run(selectedTool) {
157
230
  showDoneHint(selectedTool);
158
231
  }
159
232
 
160
- if (tool) {
233
+ // ── UPDATE 逻辑 ─────────────────────────────────────────────────────────────
234
+
235
+ /** 检测当前目录已安装了哪些工具 */
236
+ function detectInstalledTools() {
237
+ return Object.keys(UPDATE_RULES).filter(key => {
238
+ const detectPath = path.join(targetDir, UPDATE_RULES[key].detect);
239
+ return fs.existsSync(detectPath);
240
+ });
241
+ }
242
+
243
+ /** 更新单个工具的框架文件 */
244
+ function updateTool(toolKey) {
245
+ const rule = UPDATE_RULES[toolKey];
246
+ console.log(fmt('cyan', `[${rule.label}]`));
247
+
248
+ let updatedCount = 0;
249
+ let skippedCount = 0;
250
+
251
+ // 更新框架文件
252
+ for (const item of rule.update) {
253
+ const srcPath = path.join(SOURCE_DIR, item.src);
254
+ const destPath = path.join(targetDir, item.dest);
255
+
256
+ if (!fs.existsSync(srcPath)) {
257
+ console.log(` ${fmt('yellow', '⚠')} ${item.label} 源文件不存在,跳过`);
258
+ continue;
259
+ }
260
+
261
+ const fileCount = item.isDir ? countFiles(srcPath) : 1;
262
+ if (item.isDir) {
263
+ copyDir(srcPath, destPath);
264
+ } else {
265
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
266
+ fs.copyFileSync(srcPath, destPath);
267
+ }
268
+ console.log(` ${fmt('green', '✓')} ${item.label} ${fmt('magenta', `(${fileCount} 个文件)`)}`);
269
+ updatedCount += fileCount;
270
+ }
271
+
272
+ // 处理保留文件
273
+ for (const item of rule.preserve) {
274
+ const destPath = path.join(targetDir, item.dest);
275
+ const srcPath = path.join(SOURCE_DIR, item.dest);
276
+
277
+ if (force) {
278
+ // --force 时强制更新保留文件
279
+ if (fs.existsSync(srcPath)) {
280
+ const stat = fs.statSync(srcPath);
281
+ if (stat.isDirectory()) {
282
+ copyDir(srcPath, destPath);
283
+ } else {
284
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
285
+ fs.copyFileSync(srcPath, destPath);
286
+ }
287
+ console.log(` ${fmt('green', '✓')} ${item.dest} ${fmt('yellow', '(强制更新)')}`);
288
+ updatedCount++;
289
+ }
290
+ } else {
291
+ if (fs.existsSync(destPath)) {
292
+ console.log(` ${fmt('yellow', '⊘')} ${item.dest} ${fmt('yellow', `已保留`)} — ${item.reason}`);
293
+ skippedCount++;
294
+ }
295
+ }
296
+ }
297
+
298
+ return { updatedCount, skippedCount };
299
+ }
300
+
301
+ /** update 命令主流程 */
302
+ function runUpdate(selectedTool) {
303
+ console.log(` 目标目录: ${fmt('bold', targetDir)}`);
304
+ console.log(` 来源版本: ${fmt('bold', `v${PKG_VERSION}`)} (npm latest)`);
305
+ if (force) console.log(` ${fmt('yellow', '⚠ --force 模式:将同时更新用户保留文件')}`);
306
+ console.log('');
307
+
308
+ // 确定要更新的工具列表
309
+ let toolsToUpdate = [];
310
+ if (selectedTool && selectedTool !== 'all') {
311
+ if (!UPDATE_RULES[selectedTool]) {
312
+ console.error(fmt('red', `无效工具: ${selectedTool}。有效选项: claude | cursor | codex | all`));
313
+ process.exit(1);
314
+ }
315
+ const detectPath = path.join(targetDir, UPDATE_RULES[selectedTool].detect);
316
+ if (!fs.existsSync(detectPath)) {
317
+ console.log(fmt('yellow', `⚠ ${selectedTool} 未在当前目录初始化,请先运行:`));
318
+ console.log(` ${fmt('bold', `npx ai-engineering-init --tool ${selectedTool}`)}\n`);
319
+ process.exit(1);
320
+ }
321
+ toolsToUpdate = [selectedTool];
322
+ } else if (selectedTool === 'all') {
323
+ toolsToUpdate = Object.keys(UPDATE_RULES);
324
+ } else {
325
+ // 自动检测
326
+ toolsToUpdate = detectInstalledTools();
327
+ if (toolsToUpdate.length === 0) {
328
+ console.log(fmt('yellow', '⚠ 当前目录未检测到已安装的 AI 工具配置。'));
329
+ console.log(` 请先运行 ${fmt('bold', 'npx ai-engineering-init')} 进行初始化。\n`);
330
+ process.exit(1);
331
+ }
332
+ console.log(` 检测到已安装: ${fmt('bold', toolsToUpdate.join(', '))}`);
333
+ console.log('');
334
+ }
335
+
336
+ console.log(fmt('bold', '正在更新框架文件...'));
337
+ console.log('');
338
+
339
+ let totalUpdated = 0;
340
+ let totalSkipped = 0;
341
+
342
+ for (let i = 0; i < toolsToUpdate.length; i++) {
343
+ const { updatedCount, skippedCount } = updateTool(toolsToUpdate[i]);
344
+ totalUpdated += updatedCount;
345
+ totalSkipped += skippedCount;
346
+ if (i < toolsToUpdate.length - 1) console.log('');
347
+ }
348
+
349
+ // 汇总
350
+ console.log('');
351
+ console.log(fmt('green', fmt('bold', '✅ 更新完成!')));
352
+ console.log('');
353
+ console.log(` ${fmt('green', `✓ 更新文件: ${totalUpdated} 个`)}`);
354
+ if (totalSkipped > 0) {
355
+ console.log(` ${fmt('yellow', `⊘ 已保留文件: ${totalSkipped} 个`)}(用户自定义,使用 --force 可强制更新)`);
356
+ }
357
+ console.log('');
358
+ console.log(fmt('cyan', '提示:'));
359
+ console.log(' 重启 Claude Code / Cursor 使新技能生效');
360
+ if (!force && totalSkipped > 0) {
361
+ console.log(` 如需同步保留文件,运行: ${fmt('bold', `npx ai-engineering-init update --force`)}`);
362
+ }
363
+ console.log('');
364
+ }
365
+
366
+ // ── 主入口 ─────────────────────────────────────────────────────────────────
367
+ if (command === 'update') {
368
+ runUpdate(tool);
369
+ } else if (tool) {
161
370
  run(tool);
162
371
  } else {
163
372
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
164
373
  console.log(fmt('cyan', '请选择要初始化的 AI 工具:'));
165
374
  console.log('');
166
- console.log(` ${fmt('bold', '1')}) ${fmt('green', 'Claude Code')} — 初始化 .claude/ + CLAUDE.md`);
167
- console.log(` ${fmt('bold', '2')}) ${fmt('cyan', 'Cursor')} — 初始化 .cursor/(Skills + Agents + MCP)`);
168
- console.log(` ${fmt('bold', '3')}) ${fmt('yellow', 'OpenAI Codex')} — 初始化 .codex/ + AGENTS.md`);
169
- console.log(` ${fmt('bold', '4')}) ${fmt('blue', '全部工具')} — 同时初始化 Claude + Cursor + Codex`);
375
+ console.log(` ${fmt('bold', '1')}) ${fmt('green', 'Claude Code')} — 初始化 .claude/ + CLAUDE.md`);
376
+ console.log(` ${fmt('bold', '2')}) ${fmt('cyan', 'Cursor')} — 初始化 .cursor/(Skills + Agents + MCP)`);
377
+ console.log(` ${fmt('bold', '3')}) ${fmt('yellow', 'OpenAI Codex')} — 初始化 .codex/ + AGENTS.md`);
378
+ console.log(` ${fmt('bold', '4')}) ${fmt('blue', '全部工具')} — 同时初始化 Claude + Cursor + Codex`);
170
379
  console.log('');
171
380
  rl.question(fmt('bold', '请输入选项 [1-4]: '), (answer) => {
172
381
  rl.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-engineering-init",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "AI 工程化配置初始化工具 — 一键为 Claude Code、OpenAI Codex 等 AI 工具初始化 Skills 和项目规范",
5
5
  "keywords": [
6
6
  "claude-code",