ai-engineering-init 1.13.0 → 1.14.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.
- package/.claude/hooks/stop.js +1 -2
- package/.claude/skills/analyze-requirements/SKILL.md +5 -38
- package/.claude/skills/auto-test/SKILL.md +182 -10
- package/.claude/skills/code-patterns/SKILL.md +119 -0
- package/.claude/skills/codex-code-review/SKILL.md +39 -0
- package/.claude/skills/collaborating-with-codex/SKILL.md +119 -96
- package/.claude/skills/leniu-code-patterns/SKILL.md +179 -2
- package/.codex/skills/analyze-requirements/SKILL.md +5 -38
- package/.codex/skills/code-patterns/SKILL.md +119 -0
- package/.codex/skills/collaborating-with-codex/SKILL.md +119 -96
- package/.codex/skills/leniu-code-patterns/SKILL.md +179 -2
- package/.cursor/skills/analyze-requirements/SKILL.md +5 -38
- package/.cursor/skills/code-patterns/SKILL.md +119 -0
- package/.cursor/skills/collaborating-with-codex/SKILL.md +119 -96
- package/.cursor/skills/leniu-code-patterns/SKILL.md +179 -2
- package/bin/index.js +144 -51
- package/package.json +1 -1
- package/src/skills/collaborating-with-codex/SKILL.md +119 -96
package/bin/index.js
CHANGED
|
@@ -1327,6 +1327,14 @@ const MCP_REGISTRY = [
|
|
|
1327
1327
|
env: { YUQUE_TOKEN: '<YOUR_TOKEN>' },
|
|
1328
1328
|
recommended: false,
|
|
1329
1329
|
},
|
|
1330
|
+
{
|
|
1331
|
+
name: 'codex',
|
|
1332
|
+
command: 'uvx',
|
|
1333
|
+
args: ['--from', 'git+https://github.com/GuDaStudio/codexmcp.git', 'codexmcp'],
|
|
1334
|
+
description: 'Codex 协作 — 代码审查、算法分析、生成补丁(需安装 uv)',
|
|
1335
|
+
env: {},
|
|
1336
|
+
recommended: false,
|
|
1337
|
+
},
|
|
1330
1338
|
];
|
|
1331
1339
|
|
|
1332
1340
|
/** MCP 配置文件路径映射 */
|
|
@@ -1335,43 +1343,73 @@ const MCP_CONFIG_PATHS = {
|
|
|
1335
1343
|
cursor: { file: '.cursor/mcp.json', key: 'mcpServers' },
|
|
1336
1344
|
};
|
|
1337
1345
|
|
|
1338
|
-
/**
|
|
1339
|
-
function
|
|
1346
|
+
/** 解析 MCP 配置文件绝对路径 */
|
|
1347
|
+
function resolveMcpConfigPath(toolName, scope = 'project') {
|
|
1348
|
+
const config = MCP_CONFIG_PATHS[toolName];
|
|
1349
|
+
if (!config) return '';
|
|
1350
|
+
const baseDir = scope === 'global' ? HOME_DIR : targetDir;
|
|
1351
|
+
return path.join(baseDir, config.file);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
/** 检测指定作用域中已有的工具配置目录 */
|
|
1355
|
+
function detectMcpTools(scope = 'project') {
|
|
1356
|
+
const baseDir = scope === 'global' ? HOME_DIR : targetDir;
|
|
1340
1357
|
const tools = [];
|
|
1341
|
-
if (isRealDir(path.join(
|
|
1342
|
-
if (isRealDir(path.join(
|
|
1358
|
+
if (isRealDir(path.join(baseDir, '.claude'))) tools.push('claude');
|
|
1359
|
+
if (isRealDir(path.join(baseDir, '.cursor'))) tools.push('cursor');
|
|
1343
1360
|
return tools;
|
|
1344
1361
|
}
|
|
1345
1362
|
|
|
1346
1363
|
/** 读取指定工具的 MCP 已配置服务器 */
|
|
1347
|
-
function getMcpServers(toolName) {
|
|
1364
|
+
function getMcpServers(toolName, filePath) {
|
|
1348
1365
|
const config = MCP_CONFIG_PATHS[toolName];
|
|
1349
1366
|
if (!config) return {};
|
|
1350
|
-
const
|
|
1367
|
+
const resolvedPath = filePath || resolveMcpConfigPath(toolName, 'project');
|
|
1351
1368
|
try {
|
|
1352
|
-
const data = JSON.parse(fs.readFileSync(
|
|
1369
|
+
const data = JSON.parse(fs.readFileSync(resolvedPath, 'utf8'));
|
|
1353
1370
|
return data[config.key] || {};
|
|
1354
1371
|
} catch { return {}; }
|
|
1355
1372
|
}
|
|
1356
1373
|
|
|
1357
1374
|
/** 写入指定工具的 MCP 配置(保留文件其他字段) */
|
|
1358
|
-
function setMcpServers(toolName, mcpServers) {
|
|
1375
|
+
function setMcpServers(toolName, mcpServers, filePath) {
|
|
1359
1376
|
const config = MCP_CONFIG_PATHS[toolName];
|
|
1360
1377
|
if (!config) return;
|
|
1361
|
-
const
|
|
1378
|
+
const resolvedPath = filePath || resolveMcpConfigPath(toolName, 'project');
|
|
1362
1379
|
let data = {};
|
|
1363
|
-
try { data = JSON.parse(fs.readFileSync(
|
|
1380
|
+
try { data = JSON.parse(fs.readFileSync(resolvedPath, 'utf8')); } catch { /* 新建 */ }
|
|
1364
1381
|
data[config.key] = mcpServers;
|
|
1365
|
-
fs.mkdirSync(path.dirname(
|
|
1366
|
-
fs.writeFileSync(
|
|
1382
|
+
fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
|
|
1383
|
+
fs.writeFileSync(resolvedPath, JSON.stringify(data, null, 2) + '\n');
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/** 生成等效的手动安装 CLI 命令提示 */
|
|
1387
|
+
function buildCliHints(entry, scope) {
|
|
1388
|
+
const scopeFlag = scope === 'global' ? '-s user ' : '';
|
|
1389
|
+
const hints = [];
|
|
1390
|
+
|
|
1391
|
+
// Claude Code CLI
|
|
1392
|
+
if (entry.command && entry.command !== 'npx') {
|
|
1393
|
+
hints.push(`claude: claude mcp add ${entry.name} ${scopeFlag}--transport stdio -- ${entry.command} ${entry.args.join(' ')}`);
|
|
1394
|
+
} else {
|
|
1395
|
+
hints.push(`claude: claude mcp add ${entry.name} ${scopeFlag}-- npx -y ${entry.package}`);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// Cursor:无官方 CLI,提示手动编辑
|
|
1399
|
+
const cursorFile = scope === 'global' ? '~/.cursor/mcp.json' : '.cursor/mcp.json';
|
|
1400
|
+
hints.push(`cursor: 手动编辑 ${cursorFile},在 mcpServers 中添加 "${entry.name}" 配置`);
|
|
1401
|
+
|
|
1402
|
+
return hints;
|
|
1367
1403
|
}
|
|
1368
1404
|
|
|
1369
1405
|
/** 构建单个 MCP 服务器的配置对象 */
|
|
1370
1406
|
function buildMcpServerConfig(entry) {
|
|
1371
|
-
const
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1407
|
+
const command = entry.command || 'npx';
|
|
1408
|
+
const args = Array.isArray(entry.args) && entry.args.length > 0
|
|
1409
|
+
? [...entry.args]
|
|
1410
|
+
: ['-y', entry.package];
|
|
1411
|
+
|
|
1412
|
+
const config = { command, args };
|
|
1375
1413
|
if (Object.keys(entry.env).length > 0) {
|
|
1376
1414
|
config.env = { ...entry.env };
|
|
1377
1415
|
}
|
|
@@ -1379,10 +1417,11 @@ function buildMcpServerConfig(entry) {
|
|
|
1379
1417
|
}
|
|
1380
1418
|
|
|
1381
1419
|
/** 获取所有工具中已安装的 MCP 服务器名称集合 */
|
|
1382
|
-
function getInstalledMcpNames(tools) {
|
|
1420
|
+
function getInstalledMcpNames(tools, scope = 'project') {
|
|
1383
1421
|
const names = new Set();
|
|
1384
1422
|
for (const t of tools) {
|
|
1385
|
-
const
|
|
1423
|
+
const configPath = resolveMcpConfigPath(t, scope);
|
|
1424
|
+
const servers = getMcpServers(t, configPath);
|
|
1386
1425
|
for (const name of Object.keys(servers)) names.add(name);
|
|
1387
1426
|
}
|
|
1388
1427
|
return names;
|
|
@@ -1394,17 +1433,6 @@ function runMcp() {
|
|
|
1394
1433
|
process.exit(1);
|
|
1395
1434
|
}
|
|
1396
1435
|
|
|
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
1436
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1409
1437
|
const ask = (question) => new Promise((resolve) => {
|
|
1410
1438
|
rl.question(question, (answer) => resolve(answer.trim()));
|
|
@@ -1412,6 +1440,42 @@ function runMcp() {
|
|
|
1412
1440
|
|
|
1413
1441
|
(async () => {
|
|
1414
1442
|
try {
|
|
1443
|
+
// 第一步:选择作用域
|
|
1444
|
+
console.log(fmt('cyan', '请选择 MCP 作用域:'));
|
|
1445
|
+
console.log('');
|
|
1446
|
+
console.log(` ${fmt('bold', '1')}) ${fmt('green', '项目级')} — 写入当前项目 .claude/.cursor`);
|
|
1447
|
+
console.log(` ${fmt('bold', '2')}) ${fmt('yellow', '全局(~/.claude / ~/.cursor)')} — 对当前用户所有项目生效`);
|
|
1448
|
+
console.log('');
|
|
1449
|
+
const scopeAnswer = await ask(fmt('bold', '请输入选项 [1-2]: '));
|
|
1450
|
+
const scopeMap = { '1': 'project', '2': 'global' };
|
|
1451
|
+
const scope = scopeMap[scopeAnswer];
|
|
1452
|
+
if (!scope) {
|
|
1453
|
+
console.error(fmt('red', '无效作用域选项,退出。'));
|
|
1454
|
+
process.exit(1);
|
|
1455
|
+
}
|
|
1456
|
+
console.log('');
|
|
1457
|
+
|
|
1458
|
+
const tools = detectMcpTools(scope);
|
|
1459
|
+
if (tools.length === 0) {
|
|
1460
|
+
if (scope === 'global') {
|
|
1461
|
+
console.log(fmt('yellow', '⚠ 全局目录未检测到 ~/.claude/ 或 ~/.cursor/ 配置目录。'));
|
|
1462
|
+
console.log(` 请先运行: ${fmt('bold', 'npx ai-engineering-init global --tool claude')}`);
|
|
1463
|
+
} else {
|
|
1464
|
+
console.log(fmt('yellow', '⚠ 当前目录未检测到 .claude/ 或 .cursor/ 配置目录。'));
|
|
1465
|
+
console.log(` 请先运行: ${fmt('bold', hintCmd('init --tool claude'))}`);
|
|
1466
|
+
}
|
|
1467
|
+
console.log('');
|
|
1468
|
+
process.exit(1);
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
const scopeLabel = scope === 'global'
|
|
1472
|
+
? `全局(${HOME_DIR}/.claude / ${HOME_DIR}/.cursor)`
|
|
1473
|
+
: `项目级(${targetDir})`;
|
|
1474
|
+
console.log(` 作用域: ${fmt('bold', scopeLabel)}`);
|
|
1475
|
+
console.log(` 检测到工具: ${fmt('bold', tools.join(', '))}`);
|
|
1476
|
+
console.log('');
|
|
1477
|
+
|
|
1478
|
+
// 第二步:选择操作
|
|
1415
1479
|
console.log(fmt('cyan', '请选择 MCP 操作:'));
|
|
1416
1480
|
console.log('');
|
|
1417
1481
|
console.log(` ${fmt('bold', '1')}) ${fmt('green', '安装 MCP 服务器')} — 从预置列表选择并安装到配置`);
|
|
@@ -1423,10 +1487,10 @@ function runMcp() {
|
|
|
1423
1487
|
console.log('');
|
|
1424
1488
|
|
|
1425
1489
|
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;
|
|
1490
|
+
case '1': await mcpInstall(tools, ask, scope); break;
|
|
1491
|
+
case '2': await mcpUninstall(tools, ask, scope); break;
|
|
1492
|
+
case '3': mcpStatus(tools, scope); break;
|
|
1493
|
+
case '4': await mcpRecommend(tools, ask, scope); break;
|
|
1430
1494
|
default:
|
|
1431
1495
|
console.error(fmt('red', '无效选项,退出。'));
|
|
1432
1496
|
process.exit(1);
|
|
@@ -1438,8 +1502,8 @@ function runMcp() {
|
|
|
1438
1502
|
}
|
|
1439
1503
|
|
|
1440
1504
|
/** 安装 MCP 服务器 */
|
|
1441
|
-
async function mcpInstall(tools, ask) {
|
|
1442
|
-
const installed = getInstalledMcpNames(tools);
|
|
1505
|
+
async function mcpInstall(tools, ask, scope = 'project') {
|
|
1506
|
+
const installed = getInstalledMcpNames(tools, scope);
|
|
1443
1507
|
|
|
1444
1508
|
console.log(fmt('cyan', '可用的 MCP 服务器:'));
|
|
1445
1509
|
console.log('');
|
|
@@ -1478,25 +1542,38 @@ async function mcpInstall(tools, ask) {
|
|
|
1478
1542
|
|
|
1479
1543
|
// 写入所有检测到的工具配置
|
|
1480
1544
|
for (const toolName of tools) {
|
|
1481
|
-
const
|
|
1545
|
+
const configPath = resolveMcpConfigPath(toolName, scope);
|
|
1546
|
+
const servers = getMcpServers(toolName, configPath);
|
|
1482
1547
|
for (const entry of selected) {
|
|
1483
1548
|
servers[entry.name] = buildMcpServerConfig(entry);
|
|
1484
1549
|
}
|
|
1485
|
-
setMcpServers(toolName, servers);
|
|
1550
|
+
setMcpServers(toolName, servers, configPath);
|
|
1486
1551
|
console.log(` ${fmt('green', '✓')} ${toolName}: 已写入 ${selected.map(e => e.name).join(', ')}`);
|
|
1487
1552
|
}
|
|
1488
1553
|
|
|
1489
1554
|
console.log('');
|
|
1490
1555
|
console.log(fmt('green', fmt('bold', `✅ 已安装 ${selected.length} 个 MCP 服务器!`)));
|
|
1491
1556
|
console.log('');
|
|
1557
|
+
|
|
1558
|
+
// 输出等效手动安装命令供参考
|
|
1559
|
+
console.log(fmt('cyan', '💡 等效手动安装命令(仅供参考):'));
|
|
1560
|
+
console.log('');
|
|
1561
|
+
for (const entry of selected) {
|
|
1562
|
+
console.log(` ${fmt('bold', entry.name)}:`);
|
|
1563
|
+
for (const hint of buildCliHints(entry, scope)) {
|
|
1564
|
+
console.log(` ${fmt('yellow', hint)}`);
|
|
1565
|
+
}
|
|
1566
|
+
console.log('');
|
|
1567
|
+
}
|
|
1492
1568
|
}
|
|
1493
1569
|
|
|
1494
1570
|
/** 卸载 MCP 服务器 */
|
|
1495
|
-
async function mcpUninstall(tools, ask) {
|
|
1571
|
+
async function mcpUninstall(tools, ask, scope = 'project') {
|
|
1496
1572
|
// 收集所有已安装的服务器(合并去重)
|
|
1497
1573
|
const allServers = new Map(); // name → 出现在哪些工具中
|
|
1498
1574
|
for (const toolName of tools) {
|
|
1499
|
-
const
|
|
1575
|
+
const configPath = resolveMcpConfigPath(toolName, scope);
|
|
1576
|
+
const servers = getMcpServers(toolName, configPath);
|
|
1500
1577
|
for (const name of Object.keys(servers)) {
|
|
1501
1578
|
if (!allServers.has(name)) allServers.set(name, []);
|
|
1502
1579
|
allServers.get(name).push(toolName);
|
|
@@ -1531,7 +1608,8 @@ async function mcpUninstall(tools, ask) {
|
|
|
1531
1608
|
console.log('');
|
|
1532
1609
|
|
|
1533
1610
|
for (const toolName of tools) {
|
|
1534
|
-
const
|
|
1611
|
+
const configPath = resolveMcpConfigPath(toolName, scope);
|
|
1612
|
+
const servers = getMcpServers(toolName, configPath);
|
|
1535
1613
|
let removed = 0;
|
|
1536
1614
|
for (const name of toRemove) {
|
|
1537
1615
|
if (name in servers) {
|
|
@@ -1540,7 +1618,7 @@ async function mcpUninstall(tools, ask) {
|
|
|
1540
1618
|
}
|
|
1541
1619
|
}
|
|
1542
1620
|
if (removed > 0) {
|
|
1543
|
-
setMcpServers(toolName, servers);
|
|
1621
|
+
setMcpServers(toolName, servers, configPath);
|
|
1544
1622
|
console.log(` ${fmt('green', '✓')} ${toolName}: 已移除 ${toRemove.filter(n => !servers[n]).join(', ')}`);
|
|
1545
1623
|
}
|
|
1546
1624
|
}
|
|
@@ -1551,14 +1629,15 @@ async function mcpUninstall(tools, ask) {
|
|
|
1551
1629
|
}
|
|
1552
1630
|
|
|
1553
1631
|
/** 查看 MCP 状态 */
|
|
1554
|
-
function mcpStatus(tools) {
|
|
1632
|
+
function mcpStatus(tools, scope = 'project') {
|
|
1555
1633
|
let hasAny = false;
|
|
1556
1634
|
|
|
1557
1635
|
for (const toolName of tools) {
|
|
1558
|
-
const
|
|
1636
|
+
const configPath = resolveMcpConfigPath(toolName, scope);
|
|
1637
|
+
const servers = getMcpServers(toolName, configPath);
|
|
1559
1638
|
const names = Object.keys(servers);
|
|
1560
1639
|
|
|
1561
|
-
console.log(fmt('cyan', `[${toolName}]`) + ` ${
|
|
1640
|
+
console.log(fmt('cyan', `[${toolName}]`) + ` ${configPath}`);
|
|
1562
1641
|
|
|
1563
1642
|
if (names.length === 0) {
|
|
1564
1643
|
console.log(` ${fmt('yellow', '(无已安装的 MCP 服务器)')}`);
|
|
@@ -1566,10 +1645,12 @@ function mcpStatus(tools) {
|
|
|
1566
1645
|
hasAny = true;
|
|
1567
1646
|
for (const name of names) {
|
|
1568
1647
|
const srv = servers[name];
|
|
1569
|
-
const
|
|
1648
|
+
const args = srv.args || [];
|
|
1649
|
+
const pkg = args.find(a => a.startsWith('@'))
|
|
1650
|
+
|| (srv.command !== 'npx' ? `${srv.command} ${args.join(' ')}` : '—');
|
|
1570
1651
|
const envKeys = srv.env ? Object.keys(srv.env).join(', ') : '—';
|
|
1571
1652
|
console.log(` ${fmt('green', '●')} ${fmt('bold', name)}`);
|
|
1572
|
-
console.log(`
|
|
1653
|
+
console.log(` 命令: ${pkg} | 环境变量: ${envKeys}`);
|
|
1573
1654
|
}
|
|
1574
1655
|
}
|
|
1575
1656
|
console.log('');
|
|
@@ -1583,14 +1664,14 @@ function mcpStatus(tools) {
|
|
|
1583
1664
|
}
|
|
1584
1665
|
|
|
1585
1666
|
/** 一键推荐安装 */
|
|
1586
|
-
async function mcpRecommend(tools, ask) {
|
|
1587
|
-
const installed = getInstalledMcpNames(tools);
|
|
1667
|
+
async function mcpRecommend(tools, ask, scope = 'project') {
|
|
1668
|
+
const installed = getInstalledMcpNames(tools, scope);
|
|
1588
1669
|
const toInstall = MCP_REGISTRY.filter(e => e.recommended && !installed.has(e.name));
|
|
1589
1670
|
|
|
1590
1671
|
if (toInstall.length === 0) {
|
|
1591
1672
|
console.log(fmt('green', ' ✓ 所有推荐的 MCP 服务器已安装!'));
|
|
1592
1673
|
console.log('');
|
|
1593
|
-
mcpStatus(tools);
|
|
1674
|
+
mcpStatus(tools, scope);
|
|
1594
1675
|
return;
|
|
1595
1676
|
}
|
|
1596
1677
|
|
|
@@ -1615,17 +1696,29 @@ async function mcpRecommend(tools, ask) {
|
|
|
1615
1696
|
|
|
1616
1697
|
// 写入配置
|
|
1617
1698
|
for (const toolName of tools) {
|
|
1618
|
-
const
|
|
1699
|
+
const configPath = resolveMcpConfigPath(toolName, scope);
|
|
1700
|
+
const servers = getMcpServers(toolName, configPath);
|
|
1619
1701
|
for (const entry of toInstall) {
|
|
1620
1702
|
servers[entry.name] = buildMcpServerConfig(entry);
|
|
1621
1703
|
}
|
|
1622
|
-
setMcpServers(toolName, servers);
|
|
1704
|
+
setMcpServers(toolName, servers, configPath);
|
|
1623
1705
|
console.log(` ${fmt('green', '✓')} ${toolName}: 已写入 ${toInstall.map(e => e.name).join(', ')}`);
|
|
1624
1706
|
}
|
|
1625
1707
|
|
|
1626
1708
|
console.log('');
|
|
1627
1709
|
console.log(fmt('green', fmt('bold', `✅ 已安装 ${toInstall.length} 个推荐 MCP 服务器!`)));
|
|
1628
1710
|
console.log('');
|
|
1711
|
+
|
|
1712
|
+
// 输出等效手动安装命令供参考
|
|
1713
|
+
console.log(fmt('cyan', '💡 等效手动安装命令(仅供参考):'));
|
|
1714
|
+
console.log('');
|
|
1715
|
+
for (const entry of toInstall) {
|
|
1716
|
+
console.log(` ${fmt('bold', entry.name)}:`);
|
|
1717
|
+
for (const hint of buildCliHints(entry, scope)) {
|
|
1718
|
+
console.log(` ${fmt('yellow', hint)}`);
|
|
1719
|
+
}
|
|
1720
|
+
console.log('');
|
|
1721
|
+
}
|
|
1629
1722
|
}
|
|
1630
1723
|
|
|
1631
1724
|
// ── 工具选择菜单(init 用)─────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: collaborating-with-codex
|
|
3
3
|
description: |
|
|
4
|
-
与
|
|
5
|
-
|
|
4
|
+
与 Codex MCP 协同开发。通过 GuDaStudio/codexmcp 集成,使用 mcp__codex__codex 工具。
|
|
5
|
+
默认沙箱:read-only(严禁 codex 修改真实代码)。
|
|
6
6
|
|
|
7
7
|
触发场景:
|
|
8
8
|
- 需要算法实现或复杂逻辑分析
|
|
@@ -14,110 +14,128 @@ description: |
|
|
|
14
14
|
触发词:Codex、协作、多模型、原型、Diff、算法分析、代码审查、codex协同
|
|
15
15
|
|
|
16
16
|
前置要求:
|
|
17
|
-
-
|
|
18
|
-
-
|
|
17
|
+
- 已通过 `claude mcp add codex -s user --transport stdio -- uvx --from git+https://github.com/GuDaStudio/codexmcp.git codexmcp` 注册
|
|
18
|
+
- ~/.claude/settings.json 的 permissions.allow 已加入 mcp__codex__codex
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
# 与 Codex
|
|
21
|
+
# 与 Codex MCP 协同开发
|
|
22
22
|
|
|
23
|
-
>
|
|
23
|
+
> 通过 `mcp__codex__codex` 工具直接调用,无需命令行。始终使用 `read-only` 沙箱,要求 codex 只输出 unified diff patch。
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
##
|
|
27
|
+
## MCP 工具说明
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### 工具名
|
|
30
|
+
`mcp__codex__codex`
|
|
30
31
|
|
|
31
|
-
###
|
|
32
|
+
### 参数
|
|
32
33
|
|
|
33
|
-
|
|
|
34
|
-
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
35
|
+
|------|------|------|--------|------|
|
|
36
|
+
| `PROMPT` | string | ✅ | - | 发送给 Codex 的任务指令(建议用英语) |
|
|
37
|
+
| `cd` | Path | ✅ | - | 工作目录根路径(必须存在) |
|
|
38
|
+
| `sandbox` | string | ❌ | `read-only` | `read-only` / `workspace-write` / `danger-full-access` |
|
|
39
|
+
| `SESSION_ID` | UUID | ❌ | None | 继续之前的会话,保持上下文 |
|
|
40
|
+
| `return_all_messages` | bool | ❌ | False | 是否返回推理过程和工具调用详情 |
|
|
41
|
+
| `model` | string | ❌ | None | 指定模型(None 使用用户默认配置) |
|
|
42
|
+
| `image` | List[Path] | ❌ | None | 附加图片文件 |
|
|
43
|
+
| `yolo` | bool | ❌ | False | 跳过沙箱审批(危险,不推荐) |
|
|
44
|
+
| `profile` | string | ❌ | None | 从 `~/.codex/config.toml` 加载的配置名 |
|
|
45
|
+
| `skip_git_repo_check` | bool | ❌ | False | 允许在非 Git 仓库中运行 |
|
|
46
|
+
|
|
47
|
+
### 返回值
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
// 成功
|
|
51
|
+
{
|
|
52
|
+
"success": true,
|
|
53
|
+
"SESSION_ID": "uuid-string", // 必须保存,用于多轮交互
|
|
54
|
+
"agent_messages": "codex回复内容"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 失败
|
|
58
|
+
{
|
|
59
|
+
"success": false,
|
|
60
|
+
"error": "错误信息"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
- "用 codex 工具分析 OrderInfoService 的业务逻辑"
|
|
44
|
-
- "用 codex review 检查当前未提交的代码变更"
|
|
45
|
-
- "用 codex 生成这个方法的单元测试,模型用 gpt-5.3-codex"
|
|
64
|
+
---
|
|
46
65
|
|
|
47
|
-
|
|
66
|
+
## 标准协作流程
|
|
48
67
|
|
|
49
|
-
|
|
68
|
+
```
|
|
69
|
+
1. 需求分析阶段
|
|
70
|
+
Claude 形成初步分析 → 告知 codex → codex 完善方案
|
|
50
71
|
|
|
51
|
-
|
|
72
|
+
2. 编码前(原型阶段)
|
|
73
|
+
调用 codex(read-only)→ 要求输出 unified diff patch
|
|
74
|
+
Claude 以 diff 为逻辑参考 → 重写为生产级代码
|
|
52
75
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
~/.codex/config.toml → profiles(review/analyze/prototype)
|
|
76
|
+
3. 编码后(审查阶段)
|
|
77
|
+
调用 codex review 改动 → 验证需求完成度和代码质量
|
|
56
78
|
```
|
|
57
79
|
|
|
58
80
|
---
|
|
59
81
|
|
|
60
|
-
##
|
|
82
|
+
## 调用示例
|
|
61
83
|
|
|
62
|
-
|
|
84
|
+
### 场景一:需求分析完善
|
|
63
85
|
|
|
64
|
-
|
|
86
|
+
```
|
|
87
|
+
PROMPT: "Here is my requirement: [需求描述]. My initial approach: [初步思路].
|
|
88
|
+
Please review and improve the analysis and implementation plan.
|
|
89
|
+
Output: structured analysis with potential risks."
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
--cd . --model gpt-5.3-codex --PROMPT "Your task"
|
|
91
|
+
cd: /path/to/project
|
|
92
|
+
sandbox: read-only
|
|
69
93
|
```
|
|
70
94
|
|
|
71
|
-
###
|
|
95
|
+
### 场景二:获取代码原型(Diff)
|
|
72
96
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
| `--SESSION_ID` | UUID | ❌ | `None` | 会话 ID(继续之前的对话) |
|
|
80
|
-
| `--profile` | str | ❌ | `None` | Codex profile(review/analyze/prototype) |
|
|
81
|
-
| `--return-all-messages` | bool | ❌ | `False` | 返回完整推理信息 |
|
|
82
|
-
| `--image` | List[Path] | ❌ | `None` | 附加图片 |
|
|
83
|
-
| `--yolo` | bool | ❌ | `False` | 跳过审批(危险) |
|
|
84
|
-
|
|
85
|
-
### 使用示例
|
|
97
|
+
```
|
|
98
|
+
PROMPT: "Generate a unified diff patch to implement [功能描述].
|
|
99
|
+
File: [目标文件路径]
|
|
100
|
+
Requirements:
|
|
101
|
+
- [要求1]
|
|
102
|
+
- [要求2]
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# 代码审查
|
|
94
|
-
python .claude/skills/collaborating-with-codex/scripts/codex_bridge.py \
|
|
95
|
-
--cd . --model gpt-5.3-codex --profile review \
|
|
96
|
-
--PROMPT "Review OrderWebBusiness.java for bugs. OUTPUT: Review with line numbers."
|
|
97
|
-
|
|
98
|
-
# 生成 Diff 补丁
|
|
99
|
-
python .claude/skills/collaborating-with-codex/scripts/codex_bridge.py \
|
|
100
|
-
--cd . --model gpt-5.3-codex \
|
|
101
|
-
--PROMPT "Generate unified diff to add logging. OUTPUT: Unified Diff Patch ONLY."
|
|
102
|
-
|
|
103
|
-
# 多轮会话
|
|
104
|
-
python .claude/skills/collaborating-with-codex/scripts/codex_bridge.py \
|
|
105
|
-
--cd . --model gpt-5.3-codex \
|
|
106
|
-
--SESSION_ID "uuid-from-previous" \
|
|
107
|
-
--PROMPT "Now write unit tests for the method we discussed"
|
|
104
|
+
IMPORTANT: Output unified diff patch ONLY. Do NOT modify any real files.
|
|
105
|
+
IMPORTANT: All Java comments and SQL COMMENTs MUST be in Chinese."
|
|
106
|
+
|
|
107
|
+
cd: /path/to/project
|
|
108
|
+
sandbox: read-only
|
|
108
109
|
```
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
### 场景三:代码审查
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
PROMPT: "Review the following code changes for correctness, performance, and security.
|
|
115
|
+
[粘贴代码或说明文件路径]
|
|
116
|
+
|
|
117
|
+
Check:
|
|
118
|
+
1. Logic correctness
|
|
119
|
+
2. Edge cases
|
|
120
|
+
3. Performance issues
|
|
121
|
+
4. Security vulnerabilities
|
|
122
|
+
|
|
123
|
+
Output: review with line numbers and severity (CRITICAL/WARNING/INFO)."
|
|
124
|
+
|
|
125
|
+
cd: /path/to/project
|
|
126
|
+
sandbox: read-only
|
|
127
|
+
```
|
|
111
128
|
|
|
112
|
-
|
|
129
|
+
### 场景四:多轮交互(继续会话)
|
|
113
130
|
|
|
114
|
-
|
|
131
|
+
```
|
|
132
|
+
// 第一轮
|
|
133
|
+
SESSION_ID: None → 保存返回的 SESSION_ID
|
|
115
134
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
| `prototype` | gpt-5.3-codex | workspace-write | high | 原型生成 |
|
|
135
|
+
// 第二轮
|
|
136
|
+
SESSION_ID: "上一轮返回的 uuid"
|
|
137
|
+
PROMPT: "Now refine the diff based on the feedback: [反馈内容]"
|
|
138
|
+
```
|
|
121
139
|
|
|
122
140
|
---
|
|
123
141
|
|
|
@@ -125,24 +143,18 @@ python .claude/skills/collaborating-with-codex/scripts/codex_bridge.py \
|
|
|
125
143
|
|
|
126
144
|
| 角色 | Claude Code 负责 | Codex 负责 |
|
|
127
145
|
|------|-----------------|-----------|
|
|
128
|
-
| **架构** |
|
|
129
|
-
| **开发** |
|
|
130
|
-
| **审查** | 规范检查、最终判定 |
|
|
131
|
-
| **调试** |
|
|
146
|
+
| **架构** | 设计决策、规范审校 | 分析现有代码结构 |
|
|
147
|
+
| **开发** | 规范重写、最终代码实施 | 输出原型 diff(只读参考) |
|
|
148
|
+
| **审查** | 规范检查、最终判定 | 逐文件逻辑审查 |
|
|
149
|
+
| **调试** | 日志分析、问题定位 | 深度代码分析、补丁建议 |
|
|
132
150
|
|
|
133
151
|
### 重要约束
|
|
134
152
|
|
|
135
|
-
1.
|
|
136
|
-
2. **英语 Prompt
|
|
137
|
-
3.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
- All SQL COMMENT values MUST be in Chinese
|
|
141
|
-
- All Java/code comments MUST be in Chinese
|
|
142
|
-
- Variable names and class names remain in English
|
|
143
|
-
```
|
|
144
|
-
4. **脏原型思维**: Codex 输出视为草稿,Claude 按项目规范重构
|
|
145
|
-
5. **后台运行**: 长时间任务用 subagent `run_in_background`
|
|
153
|
+
1. **只读优先**:始终使用 `sandbox="read-only"`
|
|
154
|
+
2. **英语 Prompt**:与 codex 交互用英语,代码注释要求中文
|
|
155
|
+
3. **脏原型思维**:codex 输出视为草稿,Claude 按项目规范重构
|
|
156
|
+
4. **保存 SESSION_ID**:每次调用后记录,多轮对话时传入
|
|
157
|
+
5. **质疑 codex**:codex 仅供参考,必须有独立判断
|
|
146
158
|
|
|
147
159
|
---
|
|
148
160
|
|
|
@@ -150,8 +162,19 @@ python .claude/skills/collaborating-with-codex/scripts/codex_bridge.py \
|
|
|
150
162
|
|
|
151
163
|
| 问题 | 解决方案 |
|
|
152
164
|
|------|---------|
|
|
153
|
-
|
|
|
154
|
-
| `
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
|
|
|
165
|
+
| 工具未出现 | 重启 Claude Code,检查 `~/.claude.json` 中 codex 配置 |
|
|
166
|
+
| `cd` 参数报错 | 确认目录存在,使用绝对路径 |
|
|
167
|
+
| 连接超时 | 检查网络,`uvx --from git+https://github.com/GuDaStudio/codexmcp.git codexmcp` 手动测试 |
|
|
168
|
+
| SESSION_ID 失效 | 重新开启新会话(不传 SESSION_ID) |
|
|
169
|
+
| codex 修改了文件 | 确认 `sandbox="read-only"` 已设置 |
|
|
170
|
+
|
|
171
|
+
## 安装验证
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# 查看 MCP 配置
|
|
175
|
+
cat ~/.claude.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('mcpServers', {}).get('codex', 'not found'))"
|
|
176
|
+
|
|
177
|
+
# 重启后运行
|
|
178
|
+
claude mcp list
|
|
179
|
+
# 期望看到: codex: uvx ... - ✓ Connected
|
|
180
|
+
```
|