ethan-skill 1.13.0 → 1.15.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 (42) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -0
  3. package/dist/agents/orchestrator.d.ts.map +1 -1
  4. package/dist/agents/orchestrator.js +423 -2
  5. package/dist/agents/orchestrator.js.map +1 -1
  6. package/dist/agents/orchestrator.test.js +5 -6
  7. package/dist/agents/orchestrator.test.js.map +1 -1
  8. package/dist/agents/presets.d.ts +1 -1
  9. package/dist/agents/presets.d.ts.map +1 -1
  10. package/dist/agents/presets.js +42 -1
  11. package/dist/agents/presets.js.map +1 -1
  12. package/dist/agents/types.d.ts +4 -0
  13. package/dist/agents/types.d.ts.map +1 -1
  14. package/dist/cli/index.js +413 -26
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +54 -0
  17. package/dist/extension/index.d.ts.map +1 -0
  18. package/dist/extension/index.js +198 -0
  19. package/dist/extension/index.js.map +1 -0
  20. package/dist/mcp/server.d.ts.map +1 -1
  21. package/dist/mcp/server.js +90 -2
  22. package/dist/mcp/server.js.map +1 -1
  23. package/dist/memory/index.d.ts +42 -0
  24. package/dist/memory/index.d.ts.map +1 -0
  25. package/dist/memory/index.js +320 -0
  26. package/dist/memory/index.js.map +1 -0
  27. package/dist/memory/types.d.ts +47 -0
  28. package/dist/memory/types.d.ts.map +1 -0
  29. package/dist/memory/types.js +7 -0
  30. package/dist/memory/types.js.map +1 -0
  31. package/package.json +1 -1
  32. package/rules/claude-code/CLAUDE.md +2 -2
  33. package/rules/cline/.clinerules +2 -2
  34. package/rules/codebuddy/CODEBUDDY.md +2 -2
  35. package/rules/continue/.continuerules +2 -2
  36. package/rules/copilot/copilot-instructions.md +2 -2
  37. package/rules/cursor/.cursorrules +2 -2
  38. package/rules/cursor/smart-flow.mdc +2 -2
  39. package/rules/jetbrains/smart-flow.md +2 -2
  40. package/rules/lingma/smart-flow.md +2 -2
  41. package/rules/windsurf/.windsurf/rules/smart-flow.md +2 -2
  42. package/rules/zed/smart-flow.rules +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 内置 Agent 预设定义
3
- * 5 个标准 Agent,覆盖全部 36 Skill
3
+ * 8 个标准 Agent:5 个通用 + 3 个专业化(QA / Security / Data)
4
4
  */
5
5
  import type { AgentDefinition } from './types';
6
6
  export declare const BUILT_IN_AGENTS: AgentDefinition[];
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/agents/presets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,eAAe,EAAE,eAAe,EAkF5C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQnF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,eAAe,EAAE,CAcnB"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/agents/presets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,eAAe,EAAE,eAAe,EA2H5C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQnF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,eAAe,EAAE,CAcnB"}
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * 内置 Agent 预设定义
4
- * 5 个标准 Agent,覆盖全部 36 Skill
4
+ * 8 个标准 Agent:5 个通用 + 3 个专业化(QA / Security / Data)
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.BUILT_IN_AGENTS = void 0;
@@ -89,6 +89,47 @@ exports.BUILT_IN_AGENTS = [
89
89
  'service-catalog',
90
90
  ],
91
91
  },
92
+ // ── 专业化 Agent(可按需在 Pipeline 中独立使用)──────────────────────────
93
+ {
94
+ id: 'qa',
95
+ name: 'QA Agent',
96
+ nameEn: 'qa-agent',
97
+ emoji: '🧪',
98
+ role: '负责质量保障:单元测试、代码审查、Spec 审查与移动端合规',
99
+ skillIds: [
100
+ 'unit-testing',
101
+ 'code-review',
102
+ 'spec-review',
103
+ 'mobile-review',
104
+ 'security-review',
105
+ ],
106
+ },
107
+ {
108
+ id: 'security',
109
+ name: 'Security Agent',
110
+ nameEn: 'security-agent',
111
+ emoji: '🔐',
112
+ role: '负责安全专项:威胁建模、安全审查与安全变更提案',
113
+ skillIds: [
114
+ 'threat-model',
115
+ 'security-review',
116
+ 'spec-proposal',
117
+ ],
118
+ },
119
+ {
120
+ id: 'data',
121
+ name: 'Data Agent',
122
+ nameEn: 'data-agent',
123
+ emoji: '📈',
124
+ role: '负责数据工程:数据管道、ML 实验、数据库优化与可观测性',
125
+ skillIds: [
126
+ 'data-pipeline',
127
+ 'ml-experiment',
128
+ 'database-optimize',
129
+ 'observability',
130
+ 'llm-feature',
131
+ ],
132
+ },
92
133
  ];
93
134
  /**
94
135
  * 构建 skillId → agentId 的路由映射表
@@ -1 +1 @@
1
- {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/agents/presets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/agents/presets.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,8 @@ export interface AgentDefinition {
16
16
  /** 此 Agent 可执行的 Skill ID 列表 */
17
17
  skillIds: string[];
18
18
  }
19
+ /** Agent 协作模式 */
20
+ export type AgentCollaborationMode = 'sequential' | 'parallel' | 'review-loop' | 'consensus';
19
21
  export interface AgentOrchestrationOptions {
20
22
  /** 任务背景描述 */
21
23
  context: string;
@@ -25,5 +27,7 @@ export interface AgentOrchestrationOptions {
25
27
  withContext?: boolean;
26
28
  /** ProjectSnapshot 的格式化字符串(已渲染) */
27
29
  snapshot?: string;
30
+ /** Agent 协作模式,默认 sequential */
31
+ mode?: AgentCollaborationMode;
28
32
  }
29
33
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,YAAY;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,YAAY;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,iBAAiB;AACjB,MAAM,MAAM,sBAAsB,GAC9B,YAAY,GACZ,UAAU,GACV,aAAa,GACb,WAAW,CAAC;AAEhB,MAAM,WAAW,yBAAyB;IACxC,aAAa;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,sBAAsB,CAAC;CAC/B"}
package/dist/cli/index.js CHANGED
@@ -752,6 +752,32 @@ program
752
752
  console.log(` ✅ claude-code → 工作流: ${cmdDir}/ethan-{cmd}.md × ${WORKFLOW_SLASH_COMMANDS.length}`);
753
753
  console.log(` 使用方式:在 Claude Code 聊天中输入 /ethan-commit、/ethan-auto 等`);
754
754
  console.log(` ⚡ 动态注入:提示词自动注入对话,无需复制粘贴`);
755
+ // ── Agent 命令(Claude Code 专属:每个 Agent 一个 .md 文件)─────────────
756
+ const { getActiveAgents } = await Promise.resolve().then(() => __importStar(require('../agents/index')));
757
+ const agents = getActiveAgents(dir);
758
+ // ethan-agent-list.md
759
+ const agentListContent = `---\ndescription: "Ethan — 查看所有可用 Agent 及其 Skill 分配"\n---\n\n` +
760
+ `$(ethan agent list 2>/dev/null)\n`;
761
+ fs.writeFileSync(path.join(outDir, 'ethan-agent-list.md'), agentListContent, 'utf-8');
762
+ // ethan-agent-run.md
763
+ const agentRunContent = `---\ndescription: "Ethan — Multi-Agent 编排:将任务分配给多个专业 Agent 协作执行"\n---\n\n` +
764
+ `$(![ -n "$ARGUMENTS" ] && ethan agent run $ARGUMENTS --no-copy 2>/dev/null || printf "## Ethan Multi-Agent 编排\\n\\n用法: /ethan-agent-run <pipeline> -c \\"任务描述\\"\\n\\n示例:\\n /ethan-agent-run dev-workflow -c \\"实现用户登录功能\\"\\n\\n可用模式: sequential / parallel / review-loop / consensus")\n`;
765
+ fs.writeFileSync(path.join(outDir, 'ethan-agent-run.md'), agentRunContent, 'utf-8');
766
+ // ethan-agent-new.md
767
+ const agentNewContent = `---\ndescription: "Ethan — 创建自定义 Agent,生成 .ethan/agents/<id>.yaml"\n---\n\n` +
768
+ `$(ethan agent new $ARGUMENTS 2>/dev/null)\n`;
769
+ fs.writeFileSync(path.join(outDir, 'ethan-agent-new.md'), agentNewContent, 'utf-8');
770
+ // 每个内置 Agent 生成独立快捷命令
771
+ let agentFileCount = 3;
772
+ for (const agent of agents) {
773
+ const agentSkillList = agent.skillIds.slice(0, 8).join('、') + (agent.skillIds.length > 8 ? '...' : '');
774
+ const agentContent = `---\ndescription: "Ethan — ${agent.emoji} ${agent.name}:${agent.role}"\n---\n\n` +
775
+ `$(![ -n "$ARGUMENTS" ] && ethan agent run --no-copy -c "$ARGUMENTS" 2>/dev/null || printf "## ${agent.emoji} ${agent.name}\\n\\n**职责**: ${agent.role}\\n\\n**负责 Skill**: ${agentSkillList}\\n\\n用法: /ethan-agent-${agent.id} <任务描述>")\n`;
776
+ fs.writeFileSync(path.join(outDir, `ethan-agent-${agent.id}.md`), agentContent, 'utf-8');
777
+ agentFileCount++;
778
+ total++;
779
+ }
780
+ console.log(` ✅ claude-code → Agents: ${cmdDir}/ethan-agent-*.md × ${agentFileCount}(含 ${agents.length} 个 Agent 快捷键)`);
755
781
  }
756
782
  else {
757
783
  // CodeBuddy:静态提示词(各 /ethan-xxx 命令文件)
@@ -797,14 +823,28 @@ program
797
823
  continue: 'Continue(@ethan 触发)',
798
824
  lingma: '灵码(@ethan 触发)',
799
825
  };
826
+ // ── Agent 速查表章节 ─────────────────────────────────────────────────
827
+ const { getActiveAgents: getAgentsForOther } = await Promise.resolve().then(() => __importStar(require('../agents/index')));
828
+ const otherAgents = getAgentsForOther(dir);
829
+ const agentRows = otherAgents
830
+ .map((a) => `| \`/ethan-agent-${a.id}\` | \`@ethan agent ${a.id}\` | ${a.emoji} ${a.name} | Agent | ${a.role} |`)
831
+ .join('\n');
832
+ const agentSection = `## Multi-Agent 命令\n\n` +
833
+ `| Slash 命令 | @ethan 形式 | Agent | 类型 | 职责 |\n` +
834
+ `|-----------|------------|-------|------|------|\n` +
835
+ `| \`/ethan-agent-list\` | \`@ethan agent list\` | — | Agent | 查看所有可用 Agent |\n` +
836
+ `| \`/ethan-agent-run\` | \`@ethan agent run\` | — | Agent | Multi-Agent 编排执行 |\n` +
837
+ `| \`/ethan-agent-new\` | \`@ethan agent new\` | — | Agent | 创建自定义 Agent |\n` +
838
+ `${agentRows}\n`;
800
839
  const content = `# Ethan Slash 命令速查表 — ${platformLabel[p] ?? p}\n\n` +
801
840
  `> 生成时间:${new Date().toISOString()}\n\n` +
802
- `## Skills 命令(24 个)\n\n` +
841
+ `## Skills 命令(${skills.length} 个)\n\n` +
803
842
  `| Slash 命令 | @ethan 形式 | Skill 名称 | 类型 | 说明 |\n` +
804
843
  `|-----------|------------|-----------|------|------|\n` +
805
844
  `${skillRows}\n\n` +
806
845
  `## 工作流命令\n\n` +
807
846
  `${wfSections}\n\n` +
847
+ `${agentSection}\n` +
808
848
  `## 快速示例\n\n` +
809
849
  `\`\`\`\n` +
810
850
  `/ethan-code-review # Skill:代码审查\n` +
@@ -812,7 +852,8 @@ program
812
852
  `/ethan-commit # 工作流:生成提交信息\n` +
813
853
  `/ethan-review # 工作流:Code Review\n` +
814
854
  `/ethan-auto # 工作流:Auto-Pilot 超级 Prompt\n` +
815
- `/ethan-workflow-start # 工作流:启动有状态工作流\n` +
855
+ `/ethan-agent-run # Agent:Multi-Agent 协作编排\n` +
856
+ `/ethan-agent-architect # Agent:架构师 Agent 直接对话\n` +
816
857
  `\`\`\`\n`;
817
858
  const destFile = path.join(outDir, 'ethan-commands.md');
818
859
  fs.writeFileSync(destFile, content, 'utf-8');
@@ -1267,7 +1308,27 @@ program
1267
1308
  const nodeOk = nodeMajor >= 18;
1268
1309
  console.log(`\n[环境检查]`);
1269
1310
  console.log(` Node.js: v${nodeVersion} ${nodeOk ? '✅' : '❌ (需要 Node.js >= 18)'}`);
1270
- // 2. MCP SDK check
1311
+ // 2. Windows 专项检查
1312
+ if (process.platform === 'win32') {
1313
+ console.log('\n[Windows 环境检查]');
1314
+ // 检查 PowerShell 执行策略
1315
+ try {
1316
+ const psPolicy = (0, child_process_1.spawnSync)('powershell', ['-Command', 'Get-ExecutionPolicy'], { encoding: 'utf-8' });
1317
+ const policy = (psPolicy.stdout ?? '').trim();
1318
+ const policyOk = !['Restricted', 'AllSigned'].includes(policy);
1319
+ console.log(` PowerShell 执行策略: ${policy} ${policyOk ? '✅' : '⚠️ 需设置(Set-ExecutionPolicy RemoteSigned -Scope CurrentUser)'}`);
1320
+ }
1321
+ catch { /* PowerShell not available */ }
1322
+ // 检查 npm 全局路径是否在 PATH 中
1323
+ const npmGlobal = (0, child_process_1.spawnSync)('npm', ['config', 'get', 'prefix'], { encoding: 'utf-8', shell: true });
1324
+ const npmPrefix = (npmGlobal.stdout ?? '').trim();
1325
+ if (npmPrefix) {
1326
+ const inPath = (process.env.PATH ?? '').includes(npmPrefix);
1327
+ console.log(` npm global prefix: ${npmPrefix} ${inPath ? '✅ (在 PATH 中)' : '⚠️ 不在 PATH 中(需手动添加)'}`);
1328
+ }
1329
+ console.log(` UTF-8 编码: ${process.env.CHCP === '65001' || process.env.LC_ALL?.includes('UTF') ? '✅' : '⚠️ 建议 chcp 65001'}`);
1330
+ }
1331
+ // 3. MCP SDK check
1271
1332
  const sdkOk = fs.existsSync(path.join(__dirname, '../../node_modules/@modelcontextprotocol/sdk'));
1272
1333
  console.log(` @modelcontextprotocol/sdk: ${sdkOk ? '✅ 已安装' : '❌ 未安装'}`);
1273
1334
  // 3. Rules files status
@@ -1471,6 +1532,166 @@ program
1471
1532
  console.log(`\n文件路径:${configPath}`);
1472
1533
  console.log('\n💡 提示:现在运行 ethan install --platform <platform> 将使用此配置\n');
1473
1534
  });
1535
+ // ─── setup 命令(零门槛一键安装向导) ────────────────────────────────────────
1536
+ // 面向产品、测试等非技术用户,自动检测环境,提供最简安装体验
1537
+ program
1538
+ .command('setup')
1539
+ .description('一键安装向导:自动检测编辑器,为非技术用户提供最简配置体验')
1540
+ .option('--role <role>', '用户角色:dev(开发)/ pm(产品)/ qa(测试)/ design(设计)')
1541
+ .option('--platform <platform>', '强制指定平台(跳过自动检测)')
1542
+ .option('--lang <lang>', '界面语言:zh(默认)/ en')
1543
+ .option('-y, --yes', '跳过所有确认,使用推荐配置')
1544
+ .action(async (options) => {
1545
+ const readline = await Promise.resolve().then(() => __importStar(require('readline')));
1546
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1547
+ const ask = (q, def) => new Promise((resolve) => rl.question(def !== undefined ? `${q} [${def}]: ` : `${q}: `, (a) => resolve(a.trim() || def || '')));
1548
+ const isEn = options.lang === 'en';
1549
+ const isAuto = !!options.yes;
1550
+ const t = {
1551
+ title: isEn ? 'Ethan Setup Wizard' : 'Ethan 快速安装向导',
1552
+ welcome: isEn
1553
+ ? 'This wizard will configure Ethan for your editor in 3 steps.'
1554
+ : '3 步完成配置,无需任何编程知识。',
1555
+ step1: isEn ? '[1/3] Detecting your editor...' : '[1/3] 检测你的编辑器...',
1556
+ step2: isEn ? '[2/3] Configuring your role...' : '[2/3] 配置你的角色...',
1557
+ step3: isEn ? '[3/3] Generating slash commands...' : '[3/3] 生成编辑器快捷指令...',
1558
+ done: isEn ? 'Setup complete!' : '安装完成!',
1559
+ };
1560
+ console.log(`\n${'═'.repeat(52)}`);
1561
+ console.log(` ${t.title}`);
1562
+ console.log(` ${t.welcome}`);
1563
+ console.log(`${'═'.repeat(52)}\n`);
1564
+ // ── 步骤 1:自动检测编辑器 ─────────────────────────────────────────────
1565
+ console.log(t.step1);
1566
+ // 检测逻辑:查找 .cursor / .vscode / .windsurf 等目录
1567
+ const detectedPlatforms = [];
1568
+ const checkDir = (d) => fs.existsSync(path.join(process.cwd(), d));
1569
+ if (checkDir('.cursor'))
1570
+ detectedPlatforms.push('cursor');
1571
+ if (checkDir('.vscode') || checkDir('.github'))
1572
+ detectedPlatforms.push('copilot');
1573
+ if (checkDir('.windsurf'))
1574
+ detectedPlatforms.push('windsurf');
1575
+ if (checkDir('.codebuddy'))
1576
+ detectedPlatforms.push('codebuddy');
1577
+ if (checkDir('.claude'))
1578
+ detectedPlatforms.push('claude-code');
1579
+ if (checkDir('.continue'))
1580
+ detectedPlatforms.push('continue');
1581
+ // 如果没有检测到任何编辑器,给出选项列表
1582
+ const ALL_PLATFORMS_SETUP = ['claude-code', 'cursor', 'copilot', 'codebuddy', 'windsurf', 'zed', 'jetbrains', 'continue', 'cline', 'lingma'];
1583
+ let chosenPlatform = options.platform ?? '';
1584
+ if (!chosenPlatform) {
1585
+ if (detectedPlatforms.length === 1 && isAuto) {
1586
+ chosenPlatform = detectedPlatforms[0];
1587
+ console.log(` ✅ 检测到 ${chosenPlatform},将自动配置`);
1588
+ }
1589
+ else if (detectedPlatforms.length > 0) {
1590
+ console.log(` 检测到以下编辑器:${detectedPlatforms.join(', ')}`);
1591
+ const detected = detectedPlatforms.join('/');
1592
+ if (isAuto) {
1593
+ chosenPlatform = detectedPlatforms[0];
1594
+ }
1595
+ else {
1596
+ const choice = await ask(isEn
1597
+ ? ` Which editor? (${ALL_PLATFORMS_SETUP.join('|')}|all)`
1598
+ : ` 选择编辑器(${ALL_PLATFORMS_SETUP.join('|')}|all)`, detectedPlatforms[0]);
1599
+ chosenPlatform = choice || detectedPlatforms[0];
1600
+ }
1601
+ }
1602
+ else {
1603
+ if (isAuto) {
1604
+ chosenPlatform = 'claude-code';
1605
+ }
1606
+ else {
1607
+ console.log(isEn ? ' No editor auto-detected. Common options:' : ' 未检测到编辑器,请选择:');
1608
+ ALL_PLATFORMS_SETUP.forEach((p, i) => console.log(` ${i + 1}. ${p}`));
1609
+ const choice = await ask(isEn ? ' Enter number or name' : ' 输入序号或名称', '1');
1610
+ const num = parseInt(choice, 10);
1611
+ chosenPlatform = (!isNaN(num) && num >= 1 && num <= ALL_PLATFORMS_SETUP.length)
1612
+ ? ALL_PLATFORMS_SETUP[num - 1]
1613
+ : (choice || 'claude-code');
1614
+ }
1615
+ }
1616
+ }
1617
+ console.log(` → 目标平台:${chosenPlatform}\n`);
1618
+ // ── 步骤 2:角色配置 ──────────────────────────────────────────────────
1619
+ console.log(t.step2);
1620
+ const ROLE_PRESETS = {
1621
+ pm: { lang: 'zh', disabledSkills: ['unit-testing', 'docker', 'cicd', 'observability', 'data-pipeline', 'ml-experiment'] },
1622
+ qa: { lang: 'zh', disabledSkills: ['docker', 'cicd', 'ml-experiment', 'green-code', 'api-mock'] },
1623
+ design: { lang: 'zh', disabledSkills: ['unit-testing', 'docker', 'cicd', 'database-optimize', 'data-pipeline', 'ml-experiment', 'observability'] },
1624
+ dev: { lang: 'zh', disabledSkills: [] },
1625
+ };
1626
+ let chosenRole = options.role ?? '';
1627
+ if (!chosenRole && !isAuto) {
1628
+ console.log(isEn ? ' Your role:' : ' 你的角色:');
1629
+ console.log(' 1. dev - 开发工程师(启用所有 36 个 Skill)');
1630
+ console.log(' 2. qa - 测试工程师(测试、审查相关 Skill)');
1631
+ console.log(' 3. pm - 产品经理(需求、设计、周报相关 Skill)');
1632
+ console.log(' 4. design - 设计师(流程、文档类 Skill)');
1633
+ const roleChoice = await ask(isEn ? ' Select (1-4)' : ' 选择(1-4)', '1');
1634
+ const roleMap = { '1': 'dev', '2': 'qa', '3': 'pm', '4': 'design' };
1635
+ chosenRole = roleMap[roleChoice] ?? roleChoice ?? 'dev';
1636
+ }
1637
+ chosenRole = chosenRole || 'dev';
1638
+ console.log(` → 角色:${chosenRole}\n`);
1639
+ const preset = ROLE_PRESETS[chosenRole] ?? ROLE_PRESETS.dev;
1640
+ // 语言选择
1641
+ let chosenLang = preset.lang;
1642
+ if (!isAuto && !options.lang) {
1643
+ const langChoice = await ask(isEn ? ' Output language (zh/en)' : ' 输出语言(zh/en)', 'zh');
1644
+ chosenLang = langChoice === 'en' ? 'en' : 'zh';
1645
+ }
1646
+ rl.close();
1647
+ // 写入 .ethanrc.json
1648
+ const existingConfig = (0, config_1.readConfig)(process.cwd());
1649
+ const newConfig = {
1650
+ ...existingConfig,
1651
+ lang: chosenLang,
1652
+ ...(preset.disabledSkills.length > 0 ? { disabledSkills: preset.disabledSkills } : {}),
1653
+ setup: { role: chosenRole, platform: chosenPlatform, setupAt: new Date().toISOString() },
1654
+ };
1655
+ (0, config_1.writeConfig)(newConfig, process.cwd());
1656
+ console.log(` ✅ .ethanrc.json 已生成(角色:${chosenRole},语言:${chosenLang})`);
1657
+ // ── 步骤 3:生成编辑器快捷指令 ───────────────────────────────────────
1658
+ console.log(`\n${t.step3}`);
1659
+ const slashPlatforms = chosenPlatform === 'all' ? 'all' : chosenPlatform;
1660
+ // 动态调用 slash 命令逻辑(通过 execSync,保持 tty)
1661
+ const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
1662
+ try {
1663
+ execSync(`ethan slash --platform ${slashPlatforms} --dir "${process.cwd()}"`, { stdio: 'inherit' });
1664
+ }
1665
+ catch {
1666
+ // 如果 ethan 还未在全局安装(开发模式),尝试直接调用 ts-node
1667
+ console.log(isEn ? ' Note: Run "ethan slash" manually if above failed.' : ' 提示:如以上失败,请手动运行 ethan slash。');
1668
+ }
1669
+ // ── 完成 ─────────────────────────────────────────────────────────────
1670
+ console.log(`\n${'═'.repeat(52)}`);
1671
+ console.log(` ${t.done}`);
1672
+ console.log('═'.repeat(52));
1673
+ console.log(isEn ? '\nNext steps:' : '\n下一步:');
1674
+ if (chosenPlatform === 'claude-code') {
1675
+ console.log(isEn
1676
+ ? ' 1. Restart Claude Code editor'
1677
+ : ' 1. 重启 Claude Code 编辑器');
1678
+ console.log(isEn
1679
+ ? ' 2. Type /ethan- in chat to see all commands'
1680
+ : ' 2. 在聊天中输入 /ethan- 即可看到所有快捷指令');
1681
+ }
1682
+ else {
1683
+ console.log(isEn
1684
+ ? ` 1. Open ethan-commands.md in your ${chosenPlatform} context`
1685
+ : ` 1. 将 ethan-commands.md 加入你的 ${chosenPlatform} 上下文`);
1686
+ console.log(isEn
1687
+ ? ' 2. Type /ethan-code-review or @ethan code-review to start'
1688
+ : ' 2. 输入 /ethan-code-review 或 @ethan code-review 开始使用');
1689
+ }
1690
+ console.log(isEn
1691
+ ? ' 3. Run "ethan agent run" for multi-agent collaboration'
1692
+ : ' 3. 运行 ethan agent run 体验多 Agent 协作');
1693
+ console.log('');
1694
+ });
1474
1695
  // ─── workflow 命令(有状态一键工作流) ──────────────────────────────────────
1475
1696
  const workflowCmd = program.command('workflow').description('有状态工作流执行:一键推进各阶段任务');
1476
1697
  workflowCmd
@@ -3014,36 +3235,34 @@ memoryCmd
3014
3235
  });
3015
3236
  memoryCmd
3016
3237
  .command('search <keyword>')
3017
- .description('在记忆库中搜索关键词(标题 + 内容 + 标签)')
3238
+ .description('在记忆库中全文检索(加权评分 + 片段高亮)')
3018
3239
  .option('--global', '搜索全局记忆库')
3019
- .option('--tag <tag>', '按标签过滤')
3240
+ .option('--tag <tag>', '按标签过滤(AND 语义)')
3241
+ .option('--type <type>', '按类型过滤:workflow|skill|manual|decision|knowledge')
3020
3242
  .option('-n, --limit <n>', '最多显示 N 条', '10')
3021
- .action((keyword, options) => {
3022
- const dir = getMemoryDir(!!options.global);
3023
- const entries = loadMemoryEntries(dir);
3024
- const kw = keyword.toLowerCase();
3025
- const limit = parseInt(options.limit, 10) || 10;
3026
- let results = entries.filter((e) => {
3027
- const matchKw = e.title.toLowerCase().includes(kw) ||
3028
- e.content.toLowerCase().includes(kw) ||
3029
- e.tags.some((t) => t.toLowerCase().includes(kw));
3030
- const matchTag = options.tag ? e.tags.includes(options.tag) : true;
3031
- return matchKw && matchTag;
3243
+ .action(async (keyword, options) => {
3244
+ const { searchMemory, getMemoryDir: getMemDir } = await Promise.resolve().then(() => __importStar(require('../memory/index')));
3245
+ const dir = getMemDir(!!options.global);
3246
+ const limit = parseInt(options.limit ?? '10', 10) || 10;
3247
+ const results = searchMemory(keyword, dir, {
3248
+ tags: options.tag ? [options.tag] : undefined,
3249
+ type: options.type,
3250
+ limit,
3032
3251
  });
3033
- results = results.slice(0, limit);
3034
3252
  if (results.length === 0) {
3035
3253
  console.log(`\n🔍 未找到匹配 "${keyword}" 的记忆\n`);
3254
+ console.log(' 💡 尝试更宽泛的关键词,或用 ethan memory list 查看所有记忆\n');
3036
3255
  return;
3037
3256
  }
3038
3257
  console.log(`\n🔍 找到 ${results.length} 条记忆(关键词:"${keyword}")\n`);
3039
- console.log('─'.repeat(60));
3040
- for (const e of results) {
3041
- const preview = e.content.length > 100 ? e.content.slice(0, 100) + '…' : e.content;
3042
- console.log(`\n 📌 ${e.title}`);
3043
- console.log(` ID: ${e.id} | ${e.createdAt.slice(0, 10)} | 标签:${e.tags.join(', ') || '无'}`);
3044
- console.log(` ${preview}`);
3258
+ console.log('─'.repeat(70));
3259
+ for (const { entry: e, score, matchedFields, snippet } of results) {
3260
+ console.log(`\n 📌 [${e.type}] ${e.title}`);
3261
+ console.log(` ID: ${e.id} | ${e.createdAt.slice(0, 10)} | 相关度: ${score} | 命中: ${matchedFields.join(', ')}`);
3262
+ console.log(` 标签:${e.tags.join(', ') || '无'}`);
3263
+ console.log(` 摘要:${snippet}`);
3045
3264
  }
3046
- console.log('\n' + '─'.repeat(60));
3265
+ console.log('\n' + '─'.repeat(70));
3047
3266
  console.log(`\n💡 用 ethan memory show <id> 查看完整内容\n`);
3048
3267
  });
3049
3268
  memoryCmd
@@ -4853,6 +5072,7 @@ agentCmd
4853
5072
  .description('生成 Multi-Agent 编排 Prompt,粘贴到 AI 编辑器执行')
4854
5073
  .option('-c, --context <context>', '任务背景描述(如"实现用户登录功能")', '')
4855
5074
  .option('--lang <lang>', '输出语言:zh(默认)或 en', '')
5075
+ .option('--mode <mode>', '协作模式:sequential(默认)/ parallel / review-loop / consensus', 'sequential')
4856
5076
  .option('--with-context', '自动采集项目上下文注入到提示词')
4857
5077
  .option('--no-copy', '不复制到剪贴板,直接打印到终端')
4858
5078
  .action(async (pipelineId, options) => {
@@ -4863,6 +5083,7 @@ agentCmd
4863
5083
  const lang = (options.lang || config.lang || 'zh');
4864
5084
  const isEn = lang === 'en';
4865
5085
  const agents = getActiveAgents(process.cwd());
5086
+ const mode = (options.mode || 'sequential');
4866
5087
  // 采集项目上下文快照
4867
5088
  let snapshotBlock;
4868
5089
  if (options.withContext) {
@@ -4930,14 +5151,21 @@ agentCmd
4930
5151
  process.exit(1);
4931
5152
  }
4932
5153
  const { pipeline, skills } = resolved;
5154
+ const modeLabels = {
5155
+ sequential: isEn ? 'Sequential' : '顺序执行',
5156
+ parallel: isEn ? 'Parallel' : '并行分析',
5157
+ 'review-loop': isEn ? 'Review-Loop' : '迭代审查',
5158
+ consensus: isEn ? 'Consensus' : '共识决策',
5159
+ };
4933
5160
  const prompt = buildMultiAgentPrompt(pipeline, skills, agents, {
4934
5161
  context,
4935
5162
  lang,
4936
5163
  snapshot: snapshotBlock,
5164
+ mode,
4937
5165
  });
4938
5166
  console.log(isEn
4939
- ? `\n🤖 Multi-Agent prompt generated: ${pipeline.name} (${skills.length} steps, ${agents.length} agents)`
4940
- : `\n🤖 Multi-Agent 编排 Prompt 已生成:${pipeline.name}(${skills.length} 步,${agents.length} 个 Agent)`);
5167
+ ? `\n🤖 Multi-Agent prompt generated: ${pipeline.name} (${skills.length} steps, ${agents.length} agents, mode: ${modeLabels[mode] ?? mode})`
5168
+ : `\n🤖 Multi-Agent 编排 Prompt 已生成:${pipeline.name}(${skills.length} 步,${agents.length} 个 Agent,模式:${modeLabels[mode] ?? mode})`);
4941
5169
  console.log('─'.repeat(60));
4942
5170
  if (options.copy !== false) {
4943
5171
  if (copyToClipboard(prompt)) {
@@ -4957,5 +5185,164 @@ agentCmd
4957
5185
  : '\n💡 每个 Agent 负责执行分配给自己的步骤,通过 Handoff 摘要将产出传递给下一个 Agent。\n');
4958
5186
  trackUsageWithStreak(`agent-run-${pipeline.id}`);
4959
5187
  });
5188
+ agentCmd
5189
+ .command('new [agentId]')
5190
+ .description('交互式创建自定义 Agent,生成 .ethan/agents/<id>.yaml')
5191
+ .action(async (agentIdArg) => {
5192
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
5193
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
5194
+ const readline = await Promise.resolve().then(() => __importStar(require('readline')));
5195
+ const { getActiveAgents } = await Promise.resolve().then(() => __importStar(require('../agents/index')));
5196
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
5197
+ const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
5198
+ console.log('\n🤖 创建自定义 Agent\n');
5199
+ console.log('─'.repeat(50));
5200
+ // 1. Agent ID
5201
+ let agentId = agentIdArg || '';
5202
+ if (!agentId) {
5203
+ agentId = await ask('Agent ID(唯一标识符,如 frontend-expert):\n> ');
5204
+ }
5205
+ if (!agentId || !/^[a-z0-9-]+$/.test(agentId)) {
5206
+ console.error('\n❌ Agent ID 只能包含小写字母、数字和连字符\n');
5207
+ rl.close();
5208
+ process.exit(1);
5209
+ }
5210
+ // 检查是否已存在同名 Agent
5211
+ const existingAgents = getActiveAgents(process.cwd());
5212
+ if (existingAgents.find((a) => a.id === agentId)) {
5213
+ const overwrite = await ask(`⚠️ Agent "${agentId}" 已存在。覆盖?(y/N):\n> `);
5214
+ if (overwrite.toLowerCase() !== 'y') {
5215
+ console.log('\n已取消。\n');
5216
+ rl.close();
5217
+ return;
5218
+ }
5219
+ }
5220
+ // 2. 中文名称
5221
+ const name = await ask('Agent 名称(中文,如 "前端专家 Agent"):\n> ') || `${agentId} Agent`;
5222
+ // 3. 英文名称
5223
+ const nameEn = await ask(`英文名称(如 "${agentId}-agent",默认 ${agentId}-agent):\n> `) || `${agentId}-agent`;
5224
+ // 4. Emoji
5225
+ const emoji = await ask('角色 Emoji(默认 🤖):\n> ') || '🤖';
5226
+ // 5. 职责描述
5227
+ const role = await ask('角色职责描述(一句话):\n> ') || `负责 ${agentId} 相关任务`;
5228
+ // 6. Skills 选择
5229
+ const allSkills = await getActiveSkills();
5230
+ console.log('\n可用 Skill ID 列表(共 ' + allSkills.length + ' 个):');
5231
+ const skillCols = Math.ceil(allSkills.length / 3);
5232
+ for (let i = 0; i < skillCols; i++) {
5233
+ const row = [0, 1, 2].map((col) => {
5234
+ const skill = allSkills[i + col * skillCols];
5235
+ return skill ? ` ${String(i + col * skillCols + 1).padStart(2, ' ')}. ${skill.id.padEnd(28, ' ')}` : '';
5236
+ }).join('');
5237
+ console.log(row);
5238
+ }
5239
+ const skillInput = await ask('\n输入 Skill ID(逗号分隔,或序号):\n> ');
5240
+ const skillIds = skillInput.split(',').map((s) => s.trim()).filter(Boolean).map((s) => {
5241
+ const num = parseInt(s, 10);
5242
+ if (!isNaN(num) && num >= 1 && num <= allSkills.length)
5243
+ return allSkills[num - 1].id;
5244
+ return s;
5245
+ });
5246
+ // 校验 skillIds
5247
+ const validIds = new Set(allSkills.map((s) => s.id));
5248
+ const invalid = skillIds.filter((id) => !validIds.has(id));
5249
+ if (invalid.length > 0) {
5250
+ console.error(`\n❌ 无效的 Skill ID:${invalid.join(', ')}\n`);
5251
+ rl.close();
5252
+ process.exit(1);
5253
+ }
5254
+ if (skillIds.length === 0) {
5255
+ console.error('\n❌ 至少需要指定一个 Skill ID\n');
5256
+ rl.close();
5257
+ process.exit(1);
5258
+ }
5259
+ rl.close();
5260
+ // 生成 YAML 内容
5261
+ const yaml = [
5262
+ `# Ethan 自定义 Agent — ${name}`,
5263
+ `id: ${agentId}`,
5264
+ `name: ${name}`,
5265
+ `nameEn: ${nameEn}`,
5266
+ `emoji: ${emoji}`,
5267
+ `role: ${role}`,
5268
+ `skillIds:`,
5269
+ ...skillIds.map((id) => ` - ${id}`),
5270
+ '',
5271
+ ].join('\n');
5272
+ // 写入文件
5273
+ const agentsDir = path.join(process.cwd(), '.ethan', 'agents');
5274
+ if (!fs.existsSync(agentsDir)) {
5275
+ fs.mkdirSync(agentsDir, { recursive: true });
5276
+ }
5277
+ const outPath = path.join(agentsDir, `${agentId}.yaml`);
5278
+ fs.writeFileSync(outPath, yaml, 'utf-8');
5279
+ console.log(`\n✅ 自定义 Agent 已创建:${outPath}`);
5280
+ console.log('\n后续用法:');
5281
+ console.log(` ethan agent show ${agentId} # 查看 Agent 详情`);
5282
+ console.log(` ethan agent run --context "任务" # 在编排中使用此 Agent`);
5283
+ console.log('');
5284
+ });
5285
+ // ─── extension 命令(事件钩子 + Webhook 扩展)─────────────────────────────────
5286
+ const extCmd = program
5287
+ .command('extension')
5288
+ .alias('ext')
5289
+ .description('扩展管理:事件钩子、Webhook 集成、Extension SDK');
5290
+ extCmd
5291
+ .command('list')
5292
+ .description('查看当前项目的钩子和 Webhook 配置')
5293
+ .action(async () => {
5294
+ const { readExtensionsConfig } = await Promise.resolve().then(() => __importStar(require('../extension/index')));
5295
+ const cfg = readExtensionsConfig(process.cwd());
5296
+ console.log('\n🔌 Ethan 扩展配置\n');
5297
+ console.log('─'.repeat(50));
5298
+ console.log(`\n钩子文件(${cfg.hooks.length} 个):`);
5299
+ if (cfg.hooks.length === 0)
5300
+ console.log(' (无)');
5301
+ cfg.hooks.forEach((h) => console.log(` ${h.enabled ? '✅' : '⏸️ '} ${h.file}`));
5302
+ console.log(`\nWebhook(${cfg.webhooks.length} 个):`);
5303
+ if (cfg.webhooks.length === 0)
5304
+ console.log(' (无)');
5305
+ cfg.webhooks.forEach((w) => console.log(` ${w.enabled ? '✅' : '⏸️ '} ${w.url} [${w.events.join(', ')}]`));
5306
+ console.log('');
5307
+ });
5308
+ extCmd
5309
+ .command('hook-init [name]')
5310
+ .description('在 .ethan/hooks/ 生成示例钩子文件')
5311
+ .action(async (name) => {
5312
+ const { generateHookTemplate } = await Promise.resolve().then(() => __importStar(require('../extension/index')));
5313
+ const hookName = name || 'my-hook';
5314
+ const file = generateHookTemplate(process.cwd(), hookName);
5315
+ console.log(`\n✅ 钩子文件已生成:${file}`);
5316
+ console.log('\n支持的事件:before:skill | after:skill | before:pipeline | after:pipeline | workflow:done | memory:save\n');
5317
+ });
5318
+ extCmd
5319
+ .command('webhook-add <url>')
5320
+ .description('添加 Webhook(在工作流事件后推送通知)')
5321
+ .option('--events <events>', '监听事件(逗号分隔)', 'after:skill,workflow:done')
5322
+ .option('--secret <secret>', 'HMAC 签名密钥(可选)')
5323
+ .action(async (url, opts) => {
5324
+ const { readExtensionsConfig, writeExtensionsConfig } = await Promise.resolve().then(() => __importStar(require('../extension/index')));
5325
+ const cfg = readExtensionsConfig(process.cwd());
5326
+ const events = opts.events.split(',').map((e) => e.trim());
5327
+ cfg.webhooks.push({ url, events, secret: opts.secret, enabled: true, headers: {} });
5328
+ writeExtensionsConfig(cfg, process.cwd());
5329
+ console.log(`\n✅ Webhook 已添加:${url}`);
5330
+ console.log(` 监听事件:${events.join(', ')}\n`);
5331
+ });
5332
+ extCmd
5333
+ .command('webhook-remove <url>')
5334
+ .description('移除 Webhook')
5335
+ .action(async (url) => {
5336
+ const { readExtensionsConfig, writeExtensionsConfig } = await Promise.resolve().then(() => __importStar(require('../extension/index')));
5337
+ const cfg = readExtensionsConfig(process.cwd());
5338
+ const before = cfg.webhooks.length;
5339
+ cfg.webhooks = cfg.webhooks.filter((w) => w.url !== url);
5340
+ if (cfg.webhooks.length === before) {
5341
+ console.error(`\n❌ 未找到 Webhook: ${url}\n`);
5342
+ process.exit(1);
5343
+ }
5344
+ writeExtensionsConfig(cfg, process.cwd());
5345
+ console.log(`\n✅ Webhook 已移除:${url}\n`);
5346
+ });
4960
5347
  program.parse(process.argv);
4961
5348
  //# sourceMappingURL=index.js.map