ethan-skill 1.10.4 → 1.11.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 (41) hide show
  1. package/README.md +10 -10
  2. package/dist/cli/index.js +248 -4
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/context/builder.d.ts +7 -0
  5. package/dist/context/builder.d.ts.map +1 -1
  6. package/dist/context/builder.js +31 -0
  7. package/dist/context/builder.js.map +1 -1
  8. package/dist/mcp/server.d.ts.map +1 -1
  9. package/dist/mcp/server.js +212 -1
  10. package/dist/mcp/server.js.map +1 -1
  11. package/dist/skills/25-spec-proposal.d.ts +3 -0
  12. package/dist/skills/25-spec-proposal.d.ts.map +1 -0
  13. package/dist/skills/25-spec-proposal.js +157 -0
  14. package/dist/skills/25-spec-proposal.js.map +1 -0
  15. package/dist/skills/26-spec-review.d.ts +3 -0
  16. package/dist/skills/26-spec-review.d.ts.map +1 -0
  17. package/dist/skills/26-spec-review.js +126 -0
  18. package/dist/skills/26-spec-review.js.map +1 -0
  19. package/dist/skills/index.d.ts +2 -0
  20. package/dist/skills/index.d.ts.map +1 -1
  21. package/dist/skills/index.js +9 -1
  22. package/dist/skills/index.js.map +1 -1
  23. package/dist/skills/pipeline.d.ts.map +1 -1
  24. package/dist/skills/pipeline.js +12 -0
  25. package/dist/skills/pipeline.js.map +1 -1
  26. package/dist/spec/index.d.ts +57 -0
  27. package/dist/spec/index.d.ts.map +1 -0
  28. package/dist/spec/index.js +303 -0
  29. package/dist/spec/index.js.map +1 -0
  30. package/package.json +1 -1
  31. package/rules/claude-code/CLAUDE.md +246 -3
  32. package/rules/cline/.clinerules +216 -2
  33. package/rules/codebuddy/CODEBUDDY.md +236 -2
  34. package/rules/continue/.continuerules +216 -2
  35. package/rules/copilot/copilot-instructions.md +230 -2
  36. package/rules/cursor/.cursorrules +243 -2
  37. package/rules/cursor/smart-flow.mdc +243 -2
  38. package/rules/jetbrains/smart-flow.md +230 -2
  39. package/rules/lingma/smart-flow.md +235 -3
  40. package/rules/windsurf/.windsurf/rules/smart-flow.md +231 -3
  41. package/rules/zed/smart-flow.rules +213 -1
package/README.md CHANGED
@@ -19,7 +19,7 @@
19
19
  | **6 个 Pipeline** | 链式工作流(开发 / 汇报 / 质量 / 完整周期 / 故障响应 / 新功能),有状态持久化推进 |
20
20
  | **23 个 MCP 工具** | AI 编辑器原生调用 Skill、Pipeline、Git、记忆库、估算 |
21
21
  | **40+ CLI 命令** | Git 集成、开发工具、记忆库、估算、插件 OS 全覆盖 |
22
- | **Slash 命令生成** | `ethan slash-install` 一键为 Claude Code 生成 `/ethan-xxx` 原生命令,其他平台生成速查表 |
22
+ | **Slash 命令生成** | `ethan slash` 一键为 Claude Code 生成 `/ethan-xxx` 原生命令,其他平台生成速查表 |
23
23
  | **自动升级** | 检测到新版本时自动后台 `npm install -g` 静默升级,重启终端即用新版 |
24
24
  | **自定义 Skill** | `.ethan/skills/*.yaml/.md`,YAML frontmatter + Markdown body |
25
25
  | **自定义 Pipeline** | `.ethan/pipelines/*.yaml`,引用内置或自定义 Skill 自由组合 |
@@ -141,7 +141,7 @@ ethan install --platform cursor
141
141
 
142
142
  ```bash
143
143
  ethan install [--platform <platform>] [--lang en] # 安装规则文件
144
- ethan slash-install [--platform <platform>] # 生成平台专属 Slash 命令文件
144
+ ethan slash [--platform <platform>] # 生成平台专属 Slash 命令文件
145
145
  ethan list [--json] # 列出所有 Skill(含自定义)
146
146
  ethan run # 交互式 Skill 执行向导
147
147
  ethan init # 生成 .ethanrc.json 配置文件
@@ -271,23 +271,23 @@ ethan plugin search <keyword> [-n <limit>] # 搜索社区插件(eth
271
271
 
272
272
  ---
273
273
 
274
- ## Slash 命令生成(`ethan slash-install`)
274
+ ## Slash 命令生成(`ethan slash`)
275
275
 
276
276
  为各 AI 平台生成专属 Slash 命令配置文件,让 `/ethan-commit`、`/ethan-review` 等命令直接在 AI 聊天中可用:
277
277
 
278
278
  ```bash
279
279
  # Claude Code:生成 .claude/commands/ethan-{skill}.md × 36 个原生 slash 命令
280
- ethan slash-install --platform claude-code
280
+ ethan slash --platform claude-code
281
281
 
282
282
  # CodeBuddy:生成 .codebuddy/commands/ethan-{skill}.md × 36 个命令文件
283
- ethan slash-install --platform codebuddy
283
+ ethan slash --platform codebuddy
284
284
 
285
285
  # Cursor / Copilot / Windsurf 等:生成 ethan-commands.md 速查表
286
- ethan slash-install --platform cursor
287
- ethan slash-install --platform copilot
286
+ ethan slash --platform cursor
287
+ ethan slash --platform copilot
288
288
 
289
289
  # 全平台一键生成
290
- ethan slash-install
290
+ ethan slash
291
291
  ```
292
292
 
293
293
  **Claude Code 使用方式**:安装后在对话中直接输入 `/ethan-commit`、`/ethan-review`、`/ethan-auto` 等,共 **36 个命令**(24 Skills + 12 工作流)。
@@ -506,8 +506,8 @@ npm run test:coverage # 覆盖率报告
506
506
  |------|---------|
507
507
  | **v1.10.3** | 修正 CodeBuddy slash 命令安装目录为 `.codebuddy/commands/`,生成 36 个独立命令文件(同 Claude Code 模式) |
508
508
  | **v1.10.2** | Claude Code 工作流 Slash 命令改为动态注入(`$(!ethan commit --no-copy)` bash 替换),执行时自动读取 git diff / 项目上下文并注入对话,无需手动复制粘贴 |
509
- | **v1.10.1** | `ethan slash-install` 新增 12 个工作流 Slash 命令(commit/review/pr/standup/changelog/workflow-start/done/status/auto/explain/test-case/estimate)|
510
- | **v1.10.0** | Node 版本过低时友好提示;新增 `ethan slash-install` 为各平台生成专属 Slash 命令文件;检测到新版本时自动后台静默升级 |
509
+ | **v1.10.1** | `ethan slash` 新增 12 个工作流 Slash 命令(commit/review/pr/standup/changelog/workflow-start/done/status/auto/explain/test-case/estimate)|
510
+ | **v1.10.0** | Node 版本过低时友好提示;新增 `ethan slash` 为各平台生成专属 Slash 命令文件;检测到新版本时自动后台静默升级 |
511
511
  | **v1.9.0** | `ethan autopilot` 命令重命名为 `ethan auto`(原命令保留为别名兼容) |
512
512
  | **v1.8.0** | 新增 10 个 Skill(Git 工作流/单元测试/系统设计/数据库优化/Docker/CI/CD/性能优化/代码重构/可观测性/设计模式);Skills 14 → 24;docs ReactBits 风格重设计 |
513
513
  | **v1.7.0** | 新增 4 个 Skill(接口设计/安全审查/部署上线/PRD 编写);新增 3 条 Pipeline(full-dev-cycle/incident-response/new-feature);自定义 Pipeline 加载(`.ethan/pipelines/`);MCP 工具 19 → 23 |
package/dist/cli/index.js CHANGED
@@ -293,7 +293,7 @@ program
293
293
  console.log('Restart your AI editor to apply the new rules.');
294
294
  }
295
295
  });
296
- // ─── slash-install 命令 ──────────────────────────────────────────────────────
296
+ // ─── slash 命令 ──────────────────────────────────────────────────────────────
297
297
  /** 工作流 Slash 命令定义(不依赖 SkillDefinition,直接内联) */
298
298
  const WORKFLOW_SLASH_COMMANDS = [
299
299
  // ── Git 集成 ──────────────────────────────────────────────
@@ -372,7 +372,7 @@ const WORKFLOW_SLASH_COMMANDS = [
372
372
  description: '启动指定 Pipeline 的有状态工作流会话',
373
373
  prompt: `# Ethan — 启动工作流\n\n` +
374
374
  `我需要启动一个 Ethan 有状态工作流会话。请告诉我:\n\n` +
375
- `1. 选择 Pipeline:dev-workflow | reporting | quality-workflow | full-dev-cycle | incident-response | new-feature\n` +
375
+ `1. 选择 Pipeline:dev-workflow | reporting | quality-workflow | full-dev-cycle | incident-response | new-feature | spec-workflow\n` +
376
376
  `2. 描述任务上下文(如"实现用户登录功能")\n\n` +
377
377
  `启动后,逐步执行每个 Skill 步骤,完成后用 \`ethan workflow done\` 推进。\n\n` +
378
378
  `CLI 用法:\`ethan workflow start <pipeline> -c "任务描述"\``,
@@ -465,9 +465,58 @@ const WORKFLOW_SLASH_COMMANDS = [
465
465
  `同时给出 T-shirt Size(XS/S/M/L/XL)和主要风险点。\n\n` +
466
466
  `CLI 用法:\`ethan estimate --style hours|story-points|days\``,
467
467
  },
468
+ // ── OpenSpec 集成 ────────────────────────────────────────────
469
+ {
470
+ id: 'spec-proposal',
471
+ name: 'Spec 变更提案',
472
+ category: 'OpenSpec',
473
+ description: '在编码前生成完整 OpenSpec 变更提案包(proposal + design + tasks + spec delta)',
474
+ prompt: `# Ethan — Spec Proposal\n\n` +
475
+ `请基于 OpenSpec 规范,为本次变更生成完整提案包。在开始编码之前,先对齐需求意图和实现范围。\n\n` +
476
+ `**请提供**:\n` +
477
+ `1. 变更描述(做什么、为什么)\n` +
478
+ `2. 涉及的功能模块(capability)\n\n` +
479
+ `**将生成文件**:\n` +
480
+ `- \`openspec/changes/[id]/proposal.md\`(变更提案)\n` +
481
+ `- \`openspec/changes/[id]/design.md\`(技术方案)\n` +
482
+ `- \`openspec/changes/[id]/tasks.md\`(分阶段任务)\n` +
483
+ `- \`openspec/changes/[id]/specs/[capability].md\`(spec delta)\n\n` +
484
+ `原则:**Review intent, not just code**\n\n` +
485
+ `CLI 用法:\`ethan spec proposal <capability> -c "变更描述"\``,
486
+ },
487
+ {
488
+ id: 'spec-review',
489
+ name: 'Spec 意图审查',
490
+ category: 'OpenSpec',
491
+ description: '对比 spec delta 与代码实现,执行意图级 Review,输出对齐矩阵和偏差报告',
492
+ prompt: `# Ethan — Spec Review(意图审查)\n\n` +
493
+ `请执行意图级 Spec Review,对照 openspec/changes/ 中的 spec delta 与代码变更:\n\n` +
494
+ `**审查维度**:\n` +
495
+ `1. 🗺️ **意图对齐矩阵**:每个 spec 需求/场景 → 对应代码位置 → ✅/⚠️/❌\n` +
496
+ `2. 🔴 **意图偏差(Critical)**:实现与 spec 意图相反或严重不符\n` +
497
+ `3. 🟡 **遗漏需求(Warning)**:spec 中有但代码未实现的场景\n` +
498
+ `4. 💡 **超范围实现(Info)**:代码实现了 spec 未定义的功能\n\n` +
499
+ `请先读取 openspec/changes/ 中最新的变更提案,再对照代码变更执行审查。\n\n` +
500
+ `CLI 用法:\`ethan spec review\``,
501
+ },
502
+ {
503
+ id: 'spec-validate',
504
+ name: 'Spec 规范校验',
505
+ category: 'OpenSpec',
506
+ description: '校验 openspec/ 目录结构完整性:Requirements 编号、GIVEN/WHEN/THEN 格式',
507
+ prompt: `# Ethan — Spec Validate\n\n` +
508
+ `请校验项目 openspec/ 目录的规范完整性,检查:\n\n` +
509
+ `- 每个 capability 是否包含 Purpose / Requirements / Scenarios 章节\n` +
510
+ `- Requirements 编号是否连续(REQ-001, REQ-002...)\n` +
511
+ `- Scenario 是否使用完整的 GIVEN/WHEN/THEN 格式\n` +
512
+ `- 是否存在空内容的占位模板\n\n` +
513
+ `输出:问题列表(按严重程度分级)+ 合格/不合格摘要\n\n` +
514
+ `CLI 用法:\`ethan spec validate [capability]\``,
515
+ },
468
516
  ];
469
517
  program
470
- .command('slash-install')
518
+ .command('slash')
519
+ .alias('slash-install')
471
520
  .description('为各平台生成专属 Slash 命令文件(Skills + 工作流指令,Claude Code 原生 /ethan-xxx、其他平台速查表)')
472
521
  .option('-p, --platform <platform>', '目标平台:claude-code | cursor | codebuddy | copilot | cline | windsurf | zed | jetbrains | continue | lingma | all', 'all')
473
522
  .option('-d, --dir <dir>', '目标目录(默认为当前目录)', process.cwd())
@@ -539,6 +588,9 @@ program
539
588
  'explain': 'ethan explain $ARGUMENTS --no-copy',
540
589
  'test-case': 'ethan test-case $ARGUMENTS --no-copy',
541
590
  'estimate': 'ethan estimate --no-copy $ARGUMENTS',
591
+ 'spec-proposal': 'ethan spec proposal --no-copy $ARGUMENTS',
592
+ 'spec-review': 'ethan spec review --no-copy',
593
+ 'spec-validate': 'ethan spec validate --no-copy $ARGUMENTS',
542
594
  };
543
595
  // 需要参数的命令:无参调用时显示用法说明(printf 内 \n 为换行)
544
596
  const PIPELINE_LIST = 'dev-workflow: 需求理解->拆解->设计->实现\\n' +
@@ -546,7 +598,8 @@ program
546
598
  '- new-feature: PRD->技术调研->接口->拆解->实现\\n' +
547
599
  '- quality-workflow: 代码审查->故障排查\\n' +
548
600
  '- reporting: 进度跟踪->任务报告->周报\\n' +
549
- '- incident-response: 故障排查->技术调研->任务报告';
601
+ '- incident-response: 故障排查->技术调研->任务报告\\n' +
602
+ '- spec-workflow: Spec提案->方案设计->任务拆解->实现->意图审查';
550
603
  const SLASH_USAGE_FALLBACKS = {
551
604
  'auto': '## Ethan Auto-Pilot — 缺少参数\\n\\n' +
552
605
  '用法: /ethan-auto <pipeline> [-c 任务描述]\\n\\n' +
@@ -3546,5 +3599,196 @@ skillIds:
3546
3599
  console.log(`\n✅ 自定义 Pipeline 模板已生成:${filePath}`);
3547
3600
  console.log(`\n💡 编辑后运行:ethan workflow start ${options.name} -c "任务描述"\n`);
3548
3601
  });
3602
+ // ─── spec 命令组 ─────────────────────────────────────────────────────────────
3603
+ const specCmd = program.command('spec').description('OpenSpec 规范驱动开发工具集');
3604
+ specCmd
3605
+ .command('init <capability>')
3606
+ .description('初始化 openspec/specs/[capability]/spec.md 规范文件')
3607
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3608
+ .action(async (capability, options) => {
3609
+ const { writeSpecFile, specTemplate } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3610
+ const filePath = writeSpecFile(capability, specTemplate(capability), options.dir);
3611
+ console.log(`\n✅ Spec 文件已创建:${filePath}`);
3612
+ console.log(`\n💡 编辑文件填写需求和场景,再运行 ethan spec validate ${capability} 检查格式\n`);
3613
+ });
3614
+ specCmd
3615
+ .command('list')
3616
+ .description('列出所有 openspec/specs/ 下的 capability')
3617
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3618
+ .action(async (options) => {
3619
+ const { hasOpenSpec, listSpecs, listChanges } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3620
+ if (!hasOpenSpec(options.dir)) {
3621
+ console.log('\n⚠️ 当前项目未检测到 openspec/ 目录。');
3622
+ console.log('运行 ethan spec init <capability> 初始化第一个 spec 文件。\n');
3623
+ return;
3624
+ }
3625
+ const specs = listSpecs(options.dir);
3626
+ const changes = listChanges(options.dir);
3627
+ console.log('\n📋 OpenSpec 规范目录\n');
3628
+ if (specs.length === 0) {
3629
+ console.log(' (openspec/specs/ 暂无 spec 文件)');
3630
+ }
3631
+ else {
3632
+ for (const spec of specs) {
3633
+ const lines = spec.content.split('\n').filter(Boolean);
3634
+ const reqCount = (spec.content.match(/### REQ-/g) || []).length;
3635
+ const scenCount = (spec.content.match(/### Scenario/g) || []).length;
3636
+ console.log(` 📄 ${spec.capability} (${reqCount} 需求, ${scenCount} 场景)`);
3637
+ if (lines[0])
3638
+ console.log(` ${lines[0].replace(/^#+\s*/, '')}`);
3639
+ }
3640
+ }
3641
+ console.log(`\n📁 变更提案:${changes.length} 个`);
3642
+ for (const c of changes.slice(0, 5)) {
3643
+ const title = c.proposalContent?.split('\n').find((l) => l.startsWith('# '))?.replace('# ', '') || c.id;
3644
+ console.log(` 📝 ${c.id} ${title}`);
3645
+ }
3646
+ console.log('');
3647
+ });
3648
+ specCmd
3649
+ .command('show <capability>')
3650
+ .description('显示指定 capability 的 spec.md 内容')
3651
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3652
+ .action(async (capability, options) => {
3653
+ const { listSpecs } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3654
+ const specs = listSpecs(options.dir);
3655
+ const spec = specs.find((s) => s.capability === capability);
3656
+ if (!spec) {
3657
+ console.error(`\n❌ 未找到 capability: ${capability}`);
3658
+ console.error(`可用:${specs.map((s) => s.capability).join(', ') || '(无)'}\n`);
3659
+ process.exit(1);
3660
+ }
3661
+ console.log(`\n📄 ${capability}\n\n${spec.content}\n`);
3662
+ });
3663
+ specCmd
3664
+ .command('validate [capability]')
3665
+ .description('校验 openspec/ 规范完整性(Requirements 编号、GIVEN/WHEN/THEN 格式)')
3666
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3667
+ .option('--no-copy', '不复制到剪贴板', false)
3668
+ .action(async (capability, options) => {
3669
+ const { hasOpenSpec, listSpecs } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3670
+ if (!hasOpenSpec(options.dir)) {
3671
+ console.error('\n❌ 当前项目未检测到 openspec/ 目录。\n');
3672
+ process.exit(1);
3673
+ }
3674
+ const specs = listSpecs(options.dir);
3675
+ const filtered = capability ? specs.filter((s) => s.capability === capability) : specs;
3676
+ if (filtered.length === 0) {
3677
+ console.error(capability ? `\n❌ 未找到 capability: ${capability}\n` : '\n⚠️ openspec/specs/ 下没有任何 spec 文件\n');
3678
+ process.exit(1);
3679
+ }
3680
+ let totalIssues = 0;
3681
+ for (const spec of filtered) {
3682
+ const issues = [];
3683
+ const content = spec.content;
3684
+ if (!content.includes('## Purpose') && !content.includes('## 用途'))
3685
+ issues.push('缺少 ## Purpose 章节');
3686
+ if (!content.includes('## Requirements') && !content.includes('## 需求'))
3687
+ issues.push('缺少 ## Requirements 章节');
3688
+ if (!content.includes('## Scenarios') && !content.includes('## 场景'))
3689
+ issues.push('缺少 ## Scenarios 章节');
3690
+ const gwtRegex = /GIVEN[\s\S]*?WHEN[\s\S]*?THEN/i;
3691
+ if (content.includes('Scenario') && !gwtRegex.test(content))
3692
+ issues.push('存在 Scenario 但未使用 GIVEN/WHEN/THEN 格式');
3693
+ totalIssues += issues.length;
3694
+ const icon = issues.length === 0 ? '✅' : issues.length <= 2 ? '⚠️ ' : '❌';
3695
+ console.log(`\n${icon} ${spec.capability}`);
3696
+ if (issues.length === 0) {
3697
+ console.log(' 规范结构完整,无问题。');
3698
+ }
3699
+ else {
3700
+ issues.forEach((issue) => console.log(` - ${issue}`));
3701
+ }
3702
+ }
3703
+ console.log(`\n汇总:${filtered.length} 个 capability,发现 ${totalIssues} 个问题。${totalIssues === 0 ? ' 🎉 全部通过!' : ''}\n`);
3704
+ });
3705
+ specCmd
3706
+ .command('proposal <capability>')
3707
+ .description('生成 OpenSpec 变更提案包(proposal.md + design.md + tasks.md + spec delta)')
3708
+ .option('-c, --context <context>', '变更描述(如"新增用户邮箱二次验证")', '')
3709
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3710
+ .option('--no-copy', '不复制到剪贴板', false)
3711
+ .action(async (capability, options) => {
3712
+ const description = options.context || capability;
3713
+ const { listSpecs, generateChangeId, proposalTemplate, designTemplate, tasksTemplate, specDeltaTemplate, writeChangeFiles, hasOpenSpec, } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3714
+ if (!hasOpenSpec(options.dir)) {
3715
+ console.log('\n⚠️ 未检测到 openspec/ 目录,自动初始化...');
3716
+ const { writeSpecFile, specTemplate } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3717
+ writeSpecFile(capability, specTemplate(capability), options.dir);
3718
+ console.log(` 已创建 openspec/specs/${capability}/spec.md\n`);
3719
+ }
3720
+ const changeId = generateChangeId();
3721
+ const proposal = proposalTemplate(changeId, description);
3722
+ const design = designTemplate(description);
3723
+ const tasks = tasksTemplate(description);
3724
+ const specDelta = specDeltaTemplate(capability, description);
3725
+ const changeDir = writeChangeFiles(changeId, { proposal, design, tasks, specDeltas: [{ capability, content: specDelta }] }, options.dir);
3726
+ const specs = listSpecs(options.dir);
3727
+ console.log(`\n✅ 变更提案包已生成:${changeDir}`);
3728
+ console.log(` 📝 proposal.md — 填写变更描述和影响范围`);
3729
+ console.log(` 🏗️ design.md — 填写技术方案和架构决策`);
3730
+ console.log(` 📋 tasks.md — 填写分阶段任务列表`);
3731
+ console.log(` 📄 specs/${capability}.md — 填写需求变更 delta`);
3732
+ console.log(`\n💡 编辑完成后运行 ethan spec review 执行意图审查\n`);
3733
+ console.log(` Change ID: ${changeId}`);
3734
+ if (specs.length > 0) {
3735
+ console.log(` 已有 Capability: ${specs.map((s) => s.capability).join(', ')}`);
3736
+ }
3737
+ console.log('');
3738
+ });
3739
+ specCmd
3740
+ .command('review')
3741
+ .description('意图级 Spec Review:对比 spec delta 与代码变更,输出对齐矩阵和偏差报告')
3742
+ .option('--change-id <id>', '指定 Change ID(不填则取最新)', '')
3743
+ .option('-d, --dir <dir>', '项目目录', process.cwd())
3744
+ .option('--no-copy', '不复制到剪贴板', false)
3745
+ .action(async (options) => {
3746
+ const { hasOpenSpec, loadLatestChange, listChanges, truncateSpec } = await Promise.resolve().then(() => __importStar(require('../spec/index')));
3747
+ if (!hasOpenSpec(options.dir)) {
3748
+ console.error('\n❌ 当前项目未检测到 openspec/ 目录。先运行 ethan spec init <capability> 初始化。\n');
3749
+ process.exit(1);
3750
+ }
3751
+ const changes = listChanges(options.dir);
3752
+ if (changes.length === 0) {
3753
+ console.error('\n⚠️ 未找到任何变更提案(openspec/changes/ 为空)。先运行 ethan spec proposal <capability> 创建提案。\n');
3754
+ process.exit(1);
3755
+ }
3756
+ const change = options.changeId
3757
+ ? (changes.find((c) => c.id === options.changeId) ?? loadLatestChange(options.dir))
3758
+ : loadLatestChange(options.dir);
3759
+ if (!change) {
3760
+ console.error(`\n❌ 未找到 Change ID: ${options.changeId}\n`);
3761
+ process.exit(1);
3762
+ }
3763
+ const gitDiff = (0, utils_1.isGitRepo)(options.dir) ? (0, utils_1.getBranchDiff)(options.dir) : '';
3764
+ const truncatedDiff = gitDiff ? (0, utils_1.truncateDiff)(gitDiff, 6000) : '(非 git 仓库或无代码变更)';
3765
+ let prompt = `# Spec Review — ${change.id}\n\n`;
3766
+ if (change.proposalContent) {
3767
+ prompt += `## 变更提案\n\n${truncateSpec(change.proposalContent, 800)}\n\n`;
3768
+ }
3769
+ if (change.specDeltas.length > 0) {
3770
+ prompt += `## Spec Delta(需求变更)\n\n`;
3771
+ for (const delta of change.specDeltas) {
3772
+ prompt += `### ${delta.capability}\n\n${truncateSpec(delta.content, 600)}\n\n`;
3773
+ }
3774
+ }
3775
+ prompt += `## 代码变更(Diff)\n\n\`\`\`diff\n${truncatedDiff}\n\`\`\`\n\n`;
3776
+ prompt += `---\n\n## 意图审查任务\n\n`;
3777
+ prompt += `请对照上方 spec delta 与代码 diff,执行意图级 Review:\n\n`;
3778
+ prompt += `1. **意图对齐矩阵**\n\n | Spec 需求/场景 | 代码位置 | 状态 | 说明 |\n |---|---|---|---|\n\n`;
3779
+ prompt += `2. **🔴 意图偏差(Critical)**:实现与 spec 意图严重不符,必须修复\n`;
3780
+ prompt += `3. **🟡 遗漏需求(Warning)**:spec 有但代码未实现\n`;
3781
+ prompt += `4. **💡 超范围实现(Info)**:代码实现了 spec 未定义的功能\n`;
3782
+ prompt += `5. **审查结论**:可合并 / 需要修复 / 需要更新 spec\n\n`;
3783
+ prompt += `> Review intent, not just code。`;
3784
+ if (options.copy !== false) {
3785
+ copyToClipboard(prompt);
3786
+ console.log(`\n✅ Spec Review 提示词已复制到剪贴板(Change: ${change.id})`);
3787
+ console.log(' 粘贴到 AI 编辑器执行意图审查。\n');
3788
+ }
3789
+ else {
3790
+ console.log(prompt);
3791
+ }
3792
+ });
3549
3793
  program.parse(process.argv);
3550
3794
  //# sourceMappingURL=index.js.map