ai-engineering-init 1.2.8 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +1 -7
- package/bin/index.js +55 -16
- package/package.json +1 -1
package/.claude/settings.json
CHANGED
package/bin/index.js
CHANGED
|
@@ -190,30 +190,28 @@ const GLOBAL_RULES = {
|
|
|
190
190
|
label: 'Claude Code',
|
|
191
191
|
targetDir: path.join(HOME_DIR, '.claude'),
|
|
192
192
|
files: [
|
|
193
|
-
{ src: '.claude/skills', dest: 'skills', label: 'Skills(全局技能库)',
|
|
194
|
-
{ src: '.claude/commands', dest: 'commands', label: 'Commands(全局命令)',
|
|
195
|
-
{ src: '.claude/agents', dest: 'agents', label: 'Agents(全局子代理)',
|
|
196
|
-
{ src: '.claude/hooks', dest: 'hooks', label: 'Hooks(全局钩子)',
|
|
193
|
+
{ src: '.claude/skills', dest: 'skills', label: 'Skills(全局技能库)', isDir: true },
|
|
194
|
+
{ src: '.claude/commands', dest: 'commands', label: 'Commands(全局命令)', isDir: true },
|
|
195
|
+
{ src: '.claude/agents', dest: 'agents', label: 'Agents(全局子代理)', isDir: true },
|
|
196
|
+
{ src: '.claude/hooks', dest: 'hooks', label: 'Hooks(全局钩子)', isDir: true },
|
|
197
197
|
{ src: '.claude/framework-config.json', dest: 'framework-config.json', label: 'framework-config.json' },
|
|
198
|
+
{ src: '.claude/settings.json', dest: 'settings.json', label: 'settings.json(Hooks + MCP 配置)', merge: true },
|
|
198
199
|
],
|
|
199
|
-
preserve: [
|
|
200
|
-
|
|
201
|
-
],
|
|
202
|
-
note: `Skills/Commands/Hooks 已安装到 ~/.claude,对所有项目自动生效`,
|
|
200
|
+
preserve: [],
|
|
201
|
+
note: `Skills/Commands/Hooks/Settings 已安装到 ~/.claude,对所有项目自动生效`,
|
|
203
202
|
},
|
|
204
203
|
cursor: {
|
|
205
204
|
label: 'Cursor',
|
|
206
205
|
targetDir: path.join(HOME_DIR, '.cursor'),
|
|
207
206
|
files: [
|
|
208
|
-
{ src: '.cursor/skills',
|
|
209
|
-
{ src: '.cursor/agents',
|
|
210
|
-
{ src: '.cursor/hooks',
|
|
207
|
+
{ src: '.cursor/skills', dest: 'skills', label: 'Skills(全局技能库)', isDir: true },
|
|
208
|
+
{ src: '.cursor/agents', dest: 'agents', label: 'Agents(全局子代理)', isDir: true },
|
|
209
|
+
{ src: '.cursor/hooks', dest: 'hooks', label: 'Hooks(全局钩子脚本)', isDir: true },
|
|
210
|
+
{ src: '.cursor/hooks.json', dest: 'hooks.json', label: 'hooks.json(Hooks 触发配置)' },
|
|
211
|
+
{ src: '.cursor/mcp.json', dest: 'mcp.json', label: 'mcp.json(MCP 服务器配置)', merge: true },
|
|
211
212
|
],
|
|
212
|
-
preserve: [
|
|
213
|
-
|
|
214
|
-
{ dest: 'hooks.json', reason: '包含用户 Hooks 配置(项目级优先)' },
|
|
215
|
-
],
|
|
216
|
-
note: `Skills/Hooks 已安装到 ~/.cursor,重启 Cursor 后在全局规则中生效`,
|
|
213
|
+
preserve: [],
|
|
214
|
+
note: `Skills/Hooks/MCP 已安装到 ~/.cursor,重启 Cursor 后生效`,
|
|
217
215
|
},
|
|
218
216
|
codex: {
|
|
219
217
|
label: 'OpenAI Codex',
|
|
@@ -226,6 +224,39 @@ const GLOBAL_RULES = {
|
|
|
226
224
|
},
|
|
227
225
|
};
|
|
228
226
|
|
|
227
|
+
/** 合并 JSON 文件:将 src 的键补充到 dest,已有的键保留不覆盖 */
|
|
228
|
+
function mergeJsonFile(srcPath, destPath, label) {
|
|
229
|
+
try {
|
|
230
|
+
const srcData = JSON.parse(fs.readFileSync(srcPath, 'utf8'));
|
|
231
|
+
let destData = {};
|
|
232
|
+
if (fs.existsSync(destPath)) {
|
|
233
|
+
try { destData = JSON.parse(fs.readFileSync(destPath, 'utf8')); } catch { destData = {}; }
|
|
234
|
+
}
|
|
235
|
+
// 深度合并第一层对象键(如 mcpServers),已有的不覆盖
|
|
236
|
+
let added = 0;
|
|
237
|
+
for (const [key, value] of Object.entries(srcData)) {
|
|
238
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
239
|
+
if (!destData[key]) destData[key] = {};
|
|
240
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
241
|
+
if (!(subKey in destData[key])) {
|
|
242
|
+
destData[key][subKey] = subValue;
|
|
243
|
+
added++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} else if (!(key in destData)) {
|
|
247
|
+
destData[key] = value;
|
|
248
|
+
added++;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
fs.writeFileSync(destPath, JSON.stringify(destData, null, 2) + '\n');
|
|
252
|
+
console.log(` ${fmt('green', '✓')} ${label} ${fmt('magenta', `(合并 +${added} 项,已有配置保留)`)}`);
|
|
253
|
+
return added > 0 ? 1 : 0;
|
|
254
|
+
} catch (e) {
|
|
255
|
+
console.log(` ${fmt('red', '✗')} ${label} 合并失败: ${e.message}`);
|
|
256
|
+
return -1;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
229
260
|
/** 全局安装单个工具 */
|
|
230
261
|
function globalInstallTool(toolKey) {
|
|
231
262
|
const rule = GLOBAL_RULES[toolKey];
|
|
@@ -244,6 +275,14 @@ function globalInstallTool(toolKey) {
|
|
|
244
275
|
console.log(` ${fmt('yellow', '⚠')} ${item.label} 源文件不存在,跳过`);
|
|
245
276
|
continue;
|
|
246
277
|
}
|
|
278
|
+
|
|
279
|
+
// merge 模式:合并 JSON 而非覆盖(保留用户已有配置)
|
|
280
|
+
if (item.merge) {
|
|
281
|
+
const result = mergeJsonFile(srcPath, destPath, item.label);
|
|
282
|
+
if (result >= 0) installed++; else failed++;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
|
|
247
286
|
if (fs.existsSync(destPath) && !force) {
|
|
248
287
|
console.log(` ${fmt('yellow', '⚠')} ${item.label} 已存在,跳过(--force 可强制覆盖)`);
|
|
249
288
|
continue;
|