yg-team-cli 2.5.2 → 2.5.3

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/README.md CHANGED
@@ -46,6 +46,10 @@
46
46
  **v2.5.2** - init 命令新增 prd-docs 目录
47
47
  - **新增**: `team-cli init` 现在默认创建 `docs/prd-docs/` 目录供存放 PRD 需求文档
48
48
 
49
+ **v2.5.3** - 优化 breakdown 命令合并逻辑
50
+ - **改进**: `breakdown` 现在仅请求生成里程碑部分,并精确合并到原 Spec 文件
51
+ - **修复**: 解决了 `breakdown` 命令可能会覆盖原文件技术设计内容的问题 (防止 Claude 的内容截断)
52
+
49
53
  **v2.4.10** - 修复 Claude 返回权限确认而非实际内容问题
50
54
  - **修复**: 添加 `--dangerously-skip-permissions` 参数跳过权限确认
51
55
  - **问题**: v2.4.9 中 Claude CLI 在新目录首次运行时返回权限确认提示而非 spec 内容
package/dist/cli.js CHANGED
@@ -2517,6 +2517,58 @@ import { Command as Command2 } from "commander";
2517
2517
  import inquirer2 from "inquirer";
2518
2518
  import path8 from "path";
2519
2519
  import { Listr as Listr2 } from "listr2";
2520
+ function mergeMilestones(original, milestones) {
2521
+ const milestoneHeader = "## \u91CC\u7A0B\u7891 (Milestones)";
2522
+ const lines = original.split("\n");
2523
+ const headerIndex = lines.findIndex((l) => l.trim().startsWith(milestoneHeader));
2524
+ let cleanedMilestones = milestones.trim();
2525
+ if (!cleanedMilestones.startsWith("## ")) {
2526
+ const firstHeaderIndex = cleanedMilestones.indexOf("## ");
2527
+ if (firstHeaderIndex !== -1) {
2528
+ cleanedMilestones = cleanedMilestones.substring(firstHeaderIndex);
2529
+ } else {
2530
+ cleanedMilestones = `${milestoneHeader}
2531
+
2532
+ ${cleanedMilestones}`;
2533
+ }
2534
+ }
2535
+ if (headerIndex !== -1) {
2536
+ const beforePart = lines.slice(0, headerIndex).join("\n");
2537
+ const afterPart = lines.slice(headerIndex + 1);
2538
+ const nextHeaderIndex = afterPart.findIndex((l) => l.trim().startsWith("## "));
2539
+ if (nextHeaderIndex !== -1) {
2540
+ const remaining = afterPart.slice(nextHeaderIndex).join("\n");
2541
+ return `${beforePart.trim()}
2542
+
2543
+ ${cleanedMilestones}
2544
+
2545
+ ${remaining.trim()}`;
2546
+ } else {
2547
+ return `${beforePart.trim()}
2548
+
2549
+ ${cleanedMilestones}`;
2550
+ }
2551
+ }
2552
+ const techDesignHeader = "## \u6280\u672F\u8BBE\u8BA1";
2553
+ const techIndex = lines.findIndex((l) => l.trim().startsWith(techDesignHeader));
2554
+ if (techIndex !== -1) {
2555
+ const afterTech = lines.slice(techIndex + 1);
2556
+ const nextHeaderIndex = afterTech.findIndex((l) => l.trim().startsWith("## "));
2557
+ if (nextHeaderIndex !== -1) {
2558
+ const splitPoint = techIndex + 1 + nextHeaderIndex;
2559
+ const before = lines.slice(0, splitPoint).join("\n");
2560
+ const after = lines.slice(splitPoint).join("\n");
2561
+ return `${before.trim()}
2562
+
2563
+ ${cleanedMilestones}
2564
+
2565
+ ${after.trim()}`;
2566
+ }
2567
+ }
2568
+ return `${original.trim()}
2569
+
2570
+ ${cleanedMilestones}`;
2571
+ }
2520
2572
  function buildBreakdownPrompt(specContent) {
2521
2573
  return `Role: Senior Technical Lead and Agile Coach
2522
2574
 
@@ -2534,18 +2586,21 @@ ${specContent}
2534
2586
  \`\`\`
2535
2587
 
2536
2588
  Output Requirements:
2537
- 1. Parse the existing spec content
2538
- 2. Break it down into 2-5 milestones
2589
+ 1. Parse the existing spec content and identify technical requirements.
2590
+ 2. Break it down into 2-5 milestones.
2539
2591
  3. Each milestone should have:
2540
2592
  - Clear name and objective
2541
2593
  - Estimated days (1-3 days per milestone)
2542
2594
  - Todo list with 3-8 actionable items
2543
2595
  4. Todo items should be:
2544
- - Concrete and specific
2545
- - Testable
2546
- - Independent as much as possible
2596
+ - Concrete, specific, and testable.
2597
+ - Independent as much as possible.
2547
2598
 
2548
- Format the milestones section as:
2599
+ IMPORTANT:
2600
+ - Output ONLY the "## \u91CC\u7A0B\u7891 (Milestones)" section.
2601
+ - Do NOT output the entire spec file.
2602
+ - Do NOT output any preamble or postamble text.
2603
+ - Follow this exact format:
2549
2604
 
2550
2605
  \`\`\`markdown
2551
2606
  ## \u91CC\u7A0B\u7891 (Milestones)
@@ -2559,24 +2614,9 @@ Format the milestones section as:
2559
2614
  - [ ] Todo 3 - \u5177\u4F53\u53EF\u6267\u884C\u7684\u4EFB\u52A1
2560
2615
 
2561
2616
  ### Milestone 2: [\u91CC\u7A0B\u7891\u540D\u79F0]
2562
- **\u76EE\u6807**: [\u7B80\u77ED\u63CF\u8FF0\u8FD9\u4E2A\u91CC\u7A0B\u7891\u7684\u76EE\u6807]
2563
- **\u9884\u4F30**: 3 \u5929
2564
-
2565
- - [ ] Todo 1
2566
- - [ ] Todo 2
2567
- - [ ] Todo 3
2568
- - [ ] Todo 4
2617
+ ...
2569
2618
  \`\`\`
2570
-
2571
- Important Instructions:
2572
- 1. Update the spec file directly with the milestone breakdown
2573
- 2. Keep all existing content, just add/update the milestones section
2574
- 3. If milestones section exists, replace it with new breakdown
2575
- 4. If milestones section doesn't exist, add it after "\u6280\u672F\u8BBE\u8BA1" section
2576
- 5. After updating the file, exit immediately
2577
- 6. Do not ask any questions
2578
- 7. Make sure todos are actionable and can be completed independently
2579
- 8. Consider dependencies when ordering todos within a milestone`;
2619
+ `;
2580
2620
  }
2581
2621
  var breakdownCommand;
2582
2622
  var init_breakdown = __esm({
@@ -2669,7 +2709,8 @@ var init_breakdown = __esm({
2669
2709
  {
2670
2710
  title: "\u66F4\u65B0 spec \u6587\u4EF6",
2671
2711
  task: async (ctx) => {
2672
- await FileUtils.write(ctx.selectedFile, ctx.breakdownResult);
2712
+ const mergedContent = mergeMilestones(ctx.specContent, ctx.breakdownResult);
2713
+ await FileUtils.write(ctx.selectedFile, mergedContent);
2673
2714
  }
2674
2715
  }
2675
2716
  ]);