yg-team-cli 2.6.1 → 2.6.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/dist/cli.js CHANGED
@@ -460,6 +460,121 @@ var init_utils = __esm({
460
460
  }
461
461
  return milestones;
462
462
  }
463
+ /**
464
+ * 解析增强版里程碑信息(支持 [F]/[B]/[I] 前缀分类)
465
+ */
466
+ static parseMilestonesEnhanced(content) {
467
+ const milestones = [];
468
+ const lines = content.split("\n");
469
+ let currentMilestone = null;
470
+ let inMilestone = false;
471
+ for (const line of lines) {
472
+ if (line.match(/^###\s+Milestone\s+\d+:/)) {
473
+ if (currentMilestone) {
474
+ currentMilestone.totalCount = currentMilestone.todos.length;
475
+ milestones.push(currentMilestone);
476
+ }
477
+ const title = line.replace(/^###\s+/, "").trim();
478
+ currentMilestone = {
479
+ title,
480
+ todos: [],
481
+ frontendTodos: [],
482
+ backendTodos: [],
483
+ integrationTodos: [],
484
+ generalTodos: [],
485
+ completedCount: 0,
486
+ totalCount: 0
487
+ };
488
+ inMilestone = true;
489
+ continue;
490
+ }
491
+ if (inMilestone && currentMilestone) {
492
+ if (line.match(/^###\s+Milestone/)) {
493
+ currentMilestone.totalCount = currentMilestone.todos.length;
494
+ milestones.push(currentMilestone);
495
+ currentMilestone = null;
496
+ const title = line.replace(/^###\s+/, "").trim();
497
+ currentMilestone = {
498
+ title,
499
+ todos: [],
500
+ frontendTodos: [],
501
+ backendTodos: [],
502
+ integrationTodos: [],
503
+ generalTodos: [],
504
+ completedCount: 0,
505
+ totalCount: 0
506
+ };
507
+ continue;
508
+ }
509
+ const todoMatch = line.match(/^-\s+\[([ xX])\]\s*(\[[FBIN]\])?\s*(.+)/);
510
+ if (todoMatch) {
511
+ const isCompleted = todoMatch[1].toLowerCase() === "x";
512
+ const prefix = todoMatch[2]?.trim() || "";
513
+ const rawContent = todoMatch[3].trim();
514
+ let type = "general";
515
+ let apiAssociation;
516
+ let dependencies;
517
+ if (prefix === "[F]") {
518
+ type = "frontend";
519
+ } else if (prefix === "[B]") {
520
+ type = "backend";
521
+ const apiMatch = rawContent.match(/\(关联 API:\s*`([^`]+)`\)/);
522
+ if (apiMatch) {
523
+ apiAssociation = apiMatch[1];
524
+ }
525
+ } else if (prefix === "[I]") {
526
+ type = "integration";
527
+ const depMatch = rawContent.match(/\(依赖:\s*([^)]+)\)/);
528
+ if (depMatch) {
529
+ dependencies = depMatch[1].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
530
+ }
531
+ }
532
+ const todoItem = {
533
+ raw: line.trim(),
534
+ content: rawContent.replace(/\s*\(关联 API:\s*`[^`]+`\)/, "").replace(/\s*\(依赖:\s*[^)]+\)/, "").trim(),
535
+ type,
536
+ apiAssociation,
537
+ dependencies,
538
+ isCompleted
539
+ };
540
+ currentMilestone.todos.push(todoItem);
541
+ if (isCompleted) {
542
+ currentMilestone.completedCount++;
543
+ }
544
+ switch (type) {
545
+ case "frontend":
546
+ currentMilestone.frontendTodos.push(todoItem);
547
+ break;
548
+ case "backend":
549
+ currentMilestone.backendTodos.push(todoItem);
550
+ break;
551
+ case "integration":
552
+ currentMilestone.integrationTodos.push(todoItem);
553
+ break;
554
+ default:
555
+ currentMilestone.generalTodos.push(todoItem);
556
+ }
557
+ }
558
+ }
559
+ }
560
+ if (currentMilestone) {
561
+ currentMilestone.totalCount = currentMilestone.todos.length;
562
+ milestones.push(currentMilestone);
563
+ }
564
+ return milestones;
565
+ }
566
+ /**
567
+ * 解析增强版里程碑(向后兼容版 - 优先尝试增强解析,失败回退到简单解析)
568
+ */
569
+ static parseMilestonesEnhancedWithFallback(content) {
570
+ const enhanced = this.parseMilestonesEnhanced(content);
571
+ const hasEnhancedFormat = enhanced.some(
572
+ (m) => m.todos.some(
573
+ (t) => t.type !== "general" || t.apiAssociation || t.dependencies
574
+ )
575
+ );
576
+ return { enhanced, isEnhanced: hasEnhancedFormat };
577
+ }
463
578
  /**
464
579
  * 解析 spec 状态(基于进度动态推导)
465
580
  */
@@ -1633,22 +1748,22 @@ var init_gitlab_api = __esm({
1633
1748
  * 从 Git URL 中提取项目路径
1634
1749
  */
1635
1750
  static parseProjectPath(repository) {
1636
- let path20 = repository;
1637
- if (path20.startsWith("git@")) {
1638
- path20 = path20.replace(/^git@/, "");
1639
- const colonIndex = path20.indexOf(":");
1751
+ let path21 = repository;
1752
+ if (path21.startsWith("git@")) {
1753
+ path21 = path21.replace(/^git@/, "");
1754
+ const colonIndex = path21.indexOf(":");
1640
1755
  if (colonIndex !== -1) {
1641
- path20 = path20.substring(colonIndex + 1);
1756
+ path21 = path21.substring(colonIndex + 1);
1642
1757
  }
1643
1758
  } else {
1644
- path20 = path20.replace(/^https?:\/\//, "");
1645
- const parts = path20.split("/");
1759
+ path21 = path21.replace(/^https?:\/\//, "");
1760
+ const parts = path21.split("/");
1646
1761
  if (parts.length > 1) {
1647
- path20 = parts.slice(1).join("/");
1762
+ path21 = parts.slice(1).join("/");
1648
1763
  }
1649
1764
  }
1650
- path20 = path20.replace(/\.git$/, "");
1651
- return path20;
1765
+ path21 = path21.replace(/\.git$/, "");
1766
+ return path21;
1652
1767
  }
1653
1768
  /**
1654
1769
  * 编码项目路径用于 API 请求
@@ -2667,7 +2782,7 @@ ${cleanedMilestones}`;
2667
2782
  function buildBreakdownPrompt(specContent) {
2668
2783
  return `Role: Senior Technical Lead and Agile Coach
2669
2784
 
2670
- Task: Break down the following feature spec into milestones and todo lists.
2785
+ Task: Break down the following feature spec into milestones with frontend, backend, and integration tasks.
2671
2786
 
2672
2787
  Context:
2673
2788
  - Read TECH_STACK.md for technology constraints
@@ -2683,13 +2798,18 @@ ${specContent}
2683
2798
  Output Requirements:
2684
2799
  1. Parse the existing spec content and identify technical requirements.
2685
2800
  2. Break it down into 2-5 milestones.
2686
- 3. Each milestone should have:
2687
- - Clear name and objective
2688
- - Estimated days (1-3 days per milestone)
2689
- - Todo list with 3-8 actionable items
2801
+ 3. Each milestone must have three sections:
2802
+ - **\u524D\u7AEF\u4EFB\u52A1**: Frontend tasks marked with [F] prefix
2803
+ - **\u540E\u7AEF\u4EFB\u52A1**: Backend tasks marked with [B] prefix, include API associations
2804
+ - **\u8054\u8C03\u4EFB\u52A1**: Integration tasks marked with [I] prefix, include dependencies
2690
2805
  4. Todo items should be:
2691
- - Concrete, specific, and testable.
2692
- - Independent as much as possible.
2806
+ - Concrete, specific, and testable
2807
+ - Independent as much as possible
2808
+
2809
+ Task Prefix Format:
2810
+ - Frontend: \`- [ ] [F] \u5177\u4F53\u7684\u524D\u7AEF\u4EFB\u52A1\u63CF\u8FF0\`
2811
+ - Backend: \`- [ ] [B] \u5177\u4F53\u7684\u540E\u7AEF\u4EFB\u52A1\u63CF\u8FF0 (\u5173\u8054 API: \`METHOD /api/path\`)\`
2812
+ - Integration: \`- [ ] [I] \u8054\u8C03\u4EFB\u52A1\u63CF\u8FF0 (\u4F9D\u8D56: F-x, B-y)\`
2693
2813
 
2694
2814
  IMPORTANT:
2695
2815
  - Output ONLY the "## \u91CC\u7A0B\u7891 (Milestones)" section.
@@ -2704,9 +2824,16 @@ IMPORTANT:
2704
2824
  **\u76EE\u6807**: [\u7B80\u77ED\u63CF\u8FF0\u8FD9\u4E2A\u91CC\u7A0B\u7891\u7684\u76EE\u6807]
2705
2825
  **\u9884\u4F30**: 2 \u5929
2706
2826
 
2707
- - [ ] Todo 1 - \u5177\u4F53\u53EF\u6267\u884C\u7684\u4EFB\u52A1
2708
- - [ ] Todo 2 - \u5177\u4F53\u53EF\u6267\u884C\u7684\u4EFB\u52A1
2709
- - [ ] Todo 3 - \u5177\u4F53\u53EF\u6267\u884C\u7684\u4EFB\u52A1
2827
+ **\u524D\u7AEF\u4EFB\u52A1**:
2828
+ - [ ] [F] \u524D\u7AEF\u4EFB\u52A1\u63CF\u8FF0 1
2829
+ - [ ] [F] \u524D\u7AEF\u4EFB\u52A1\u63CF\u8FF0 2
2830
+
2831
+ **\u540E\u7AEF\u4EFB\u52A1**:
2832
+ - [ ] [B] \u540E\u7AEF\u4EFB\u52A1\u63CF\u8FF0 1 (\u5173\u8054 API: \`POST /api/xxx\`)
2833
+ - [ ] [B] \u540E\u7AEF\u4EFB\u52A1\u63CF\u8FF0 2 (\u5173\u8054 API: \`GET /api/yyy\`)
2834
+
2835
+ **\u8054\u8C03\u4EFB\u52A1**:
2836
+ - [ ] [I] \u8054\u8C03\u4EFB\u52A1\u63CF\u8FF0 1 (\u4F9D\u8D56: F-1, B-1)
2710
2837
 
2711
2838
  ### Milestone 2: [\u91CC\u7A0B\u7891\u540D\u79F0]
2712
2839
  ...
@@ -2899,8 +3026,8 @@ async function selectMilestone(specFile) {
2899
3026
  logger.step("\u6B65\u9AA4 2/3: \u89E3\u6790 milestones...");
2900
3027
  logger.newLine();
2901
3028
  const specContent = await FileUtils.read(specFile);
2902
- const milestones = SpecUtils.parseMilestones(specContent);
2903
- if (milestones.length === 0) {
3029
+ const { enhanced, isEnhanced } = SpecUtils.parseMilestonesEnhancedWithFallback(specContent);
3030
+ if (enhanced.length === 0) {
2904
3031
  logger.info("\u8BE5 spec \u5C1A\u672A\u62C6\u5206 milestones");
2905
3032
  const { breakdownNow } = await inquirer3.prompt([
2906
3033
  {
@@ -2918,19 +3045,32 @@ async function selectMilestone(specFile) {
2918
3045
  return "\u6574\u4E2A spec";
2919
3046
  }
2920
3047
  }
2921
- const choices = milestones.map((m, idx) => {
2922
- const isDone = m.completedCount === m.todos.length && m.todos.length > 0;
3048
+ const choices = enhanced.map((m, idx) => {
3049
+ const isDone = m.completedCount === m.totalCount && m.totalCount > 0;
2923
3050
  const statusIcon = isDone ? "\u2713" : m.completedCount > 0 ? "\u27F3" : "\u25CB";
2924
- const progress = `[${m.completedCount}/${m.todos.length}]`;
3051
+ const progress = `[${m.completedCount}/${m.totalCount}]`;
2925
3052
  const label = isDone ? `\u2713 ${m.title}` : `${statusIcon} ${progress} ${m.title}`;
3053
+ let detailInfo = `(${m.totalCount} \u4E2A\u4EFB\u52A1)`;
3054
+ if (isEnhanced) {
3055
+ const fCount = m.frontendTodos.filter((t) => !t.isCompleted).length;
3056
+ const bCount = m.backendTodos.filter((t) => !t.isCompleted).length;
3057
+ const iCount = m.integrationTodos.filter((t) => !t.isCompleted).length;
3058
+ const details = [];
3059
+ if (fCount > 0) details.push(`\u524D\u7AEF:${fCount}`);
3060
+ if (bCount > 0) details.push(`\u540E\u7AEF:${bCount}`);
3061
+ if (iCount > 0) details.push(`\u8054\u8C03:${iCount}`);
3062
+ if (details.length > 0) {
3063
+ detailInfo = `(${details.join(", ")} \u672A\u5B8C\u6210)`;
3064
+ }
3065
+ }
2926
3066
  return {
2927
- name: `${idx + 1}. ${label} (${m.todos.length} \u4E2A\u4EFB\u52A1)`,
3067
+ name: `${idx + 1}. ${label} ${detailInfo}`,
2928
3068
  value: m.title,
2929
3069
  short: m.title
2930
3070
  };
2931
3071
  });
2932
3072
  choices.push({
2933
- name: `${milestones.length + 1}. \u6574\u4E2A spec (\u5168\u90E8 milestones)`,
3073
+ name: `${enhanced.length + 1}. \u6574\u4E2A spec (\u5168\u90E8 milestones)`,
2934
3074
  value: "\u6574\u4E2A spec",
2935
3075
  short: "\u6574\u4E2A spec"
2936
3076
  });
@@ -2951,6 +3091,79 @@ async function selectTodo(specFile, milestone) {
2951
3091
  logger.newLine();
2952
3092
  logger.step("\u6B65\u9AA4 3/3: \u9009\u62E9 todo \u4EFB\u52A1...");
2953
3093
  logger.newLine();
3094
+ const specContent = await FileUtils.read(specFile);
3095
+ const { enhanced, isEnhanced } = SpecUtils.parseMilestonesEnhancedWithFallback(specContent);
3096
+ const targetMilestone = enhanced.find((m) => m.title === milestone);
3097
+ if (!targetMilestone || !isEnhanced) {
3098
+ return await selectTodoSimple(specFile, milestone);
3099
+ }
3100
+ return await selectTodoEnhanced(targetMilestone);
3101
+ }
3102
+ async function selectTodoEnhanced(milestone) {
3103
+ const choices = [];
3104
+ if (milestone.frontendTodos.length > 0) {
3105
+ choices.push({ name: `\u2501\u2501 \u524D\u7AEF\u4EFB\u52A1 (${milestone.frontendTodos.length}) \u2501\u2501`, disabled: true });
3106
+ milestone.frontendTodos.forEach((todo2, idx) => {
3107
+ const icon = todo2.isCompleted ? "[x]" : "[ ]";
3108
+ choices.push({
3109
+ name: ` [F] ${icon} ${todo2.content}`,
3110
+ value: todo2.content,
3111
+ short: `[F] ${todo2.content}`
3112
+ });
3113
+ });
3114
+ }
3115
+ if (milestone.backendTodos.length > 0) {
3116
+ choices.push({ name: `\u2501\u2501 \u540E\u7AEF\u4EFB\u52A1 (${milestone.backendTodos.length}) \u2501\u2501`, disabled: true });
3117
+ milestone.backendTodos.forEach((todo2, idx) => {
3118
+ const icon = todo2.isCompleted ? "[x]" : "[ ]";
3119
+ const apiInfo = todo2.apiAssociation ? ` (${todo2.apiAssociation})` : "";
3120
+ choices.push({
3121
+ name: ` [B] ${icon} ${todo2.content}${apiInfo}`,
3122
+ value: todo2.content,
3123
+ short: `[B] ${todo2.content}`
3124
+ });
3125
+ });
3126
+ }
3127
+ if (milestone.integrationTodos.length > 0) {
3128
+ choices.push({ name: `\u2501\u2501 \u8054\u8C03\u4EFB\u52A1 (${milestone.integrationTodos.length}) \u2501\u2501`, disabled: true });
3129
+ milestone.integrationTodos.forEach((todo2, idx) => {
3130
+ const icon = todo2.isCompleted ? "[x]" : "[ ]";
3131
+ const depsInfo = todo2.dependencies ? ` (\u4F9D\u8D56: ${todo2.dependencies.join(", ")})` : "";
3132
+ choices.push({
3133
+ name: ` [I] ${icon} ${todo2.content}${depsInfo}`,
3134
+ value: todo2.content,
3135
+ short: `[I] ${todo2.content}`
3136
+ });
3137
+ });
3138
+ }
3139
+ if (milestone.generalTodos.length > 0) {
3140
+ choices.push({ name: `\u2501\u2501 \u901A\u7528\u4EFB\u52A1 (${milestone.generalTodos.length}) \u2501\u2501`, disabled: true });
3141
+ milestone.generalTodos.forEach((todo2, idx) => {
3142
+ const icon = todo2.isCompleted ? "[x]" : "[ ]";
3143
+ choices.push({
3144
+ name: ` ${icon} ${todo2.content}`,
3145
+ value: todo2.content,
3146
+ short: todo2.content
3147
+ });
3148
+ });
3149
+ }
3150
+ choices.push({ name: "\u2501\u2501 \u5176\u4ED6 \u2501\u2501", disabled: true });
3151
+ choices.push({
3152
+ name: `\u5168\u90E8\u4EFB\u52A1 (\u6574\u4E2A milestone)`,
3153
+ value: "\u5168\u90E8\u4EFB\u52A1",
3154
+ short: "\u5168\u90E8\u4EFB\u52A1"
3155
+ });
3156
+ const { todo } = await inquirer3.prompt([
3157
+ {
3158
+ type: "list",
3159
+ name: "todo",
3160
+ message: "\u9009\u62E9 todo \u4EFB\u52A1:",
3161
+ choices
3162
+ }
3163
+ ]);
3164
+ return todo;
3165
+ }
3166
+ async function selectTodoSimple(specFile, milestone) {
2954
3167
  const specContent = await FileUtils.read(specFile);
2955
3168
  const milestones = SpecUtils.parseMilestones(specContent);
2956
3169
  const targetMilestone = milestones.find((m) => m.title === milestone);
@@ -3178,10 +3391,14 @@ async function askAndUpdateSpecStatus(specFile, milestone, todo) {
3178
3391
  break;
3179
3392
  }
3180
3393
  if (todo !== "\u5168\u90E8\u529F\u80FD" && todo !== "\u5168\u90E8\u4EFB\u52A1") {
3181
- const todoMatch = line.match(/^-\s+\[[ x ]\]\s*(.+)/);
3182
- if (todoMatch && todoMatch[1].trim() === todo) {
3183
- targetTodoIndex = i;
3184
- break;
3394
+ const todoMatch = line.match(/^-\s+\[ \]\s*(\[[FBIN]\]\s*)?(.+)/);
3395
+ if (todoMatch) {
3396
+ const todoContent = todoMatch[2].trim();
3397
+ const cleanContent = todoContent.replace(/\s*\(关联 API:\s*`[^`]+`\)/, "").replace(/\s*\(依赖:\s*[^)]+\)/, "").trim();
3398
+ if (cleanContent === todo) {
3399
+ targetTodoIndex = i;
3400
+ break;
3401
+ }
3185
3402
  }
3186
3403
  }
3187
3404
  }
@@ -4467,8 +4684,597 @@ Temporary solution: ${answers.solution}`
4467
4684
  }
4468
4685
  });
4469
4686
 
4470
- // src/commands/lint.ts
4687
+ // src/commands/accept.ts
4471
4688
  import { Command as Command7 } from "commander";
4689
+ import inquirer6 from "inquirer";
4690
+ import path13 from "path";
4691
+ async function selectSpec2(defaultSpec) {
4692
+ logger.step("\u6B65\u9AA4 1/4: \u9009\u62E9 spec \u6587\u4EF6...");
4693
+ logger.newLine();
4694
+ const specDir = "docs/specs";
4695
+ const exists = await FileUtils.exists(specDir);
4696
+ if (!exists) {
4697
+ throw new Error("docs/specs \u76EE\u5F55\u4E0D\u5B58\u5728");
4698
+ }
4699
+ const files = await FileUtils.findFiles("*.md", specDir);
4700
+ const specFiles = files.filter((f) => !f.includes("template"));
4701
+ if (specFiles.length === 0) {
4702
+ throw new Error("\u672A\u627E\u5230 spec \u6587\u4EF6");
4703
+ }
4704
+ if (defaultSpec) {
4705
+ const fullPath = defaultSpec.startsWith("docs/specs/") ? defaultSpec : path13.join(specDir, defaultSpec);
4706
+ const exists2 = await FileUtils.exists(fullPath);
4707
+ if (!exists2) {
4708
+ throw new Error(`Spec \u6587\u4EF6\u4E0D\u5B58\u5728: ${defaultSpec}`);
4709
+ }
4710
+ logger.success(`\u5DF2\u9009\u62E9: ${fullPath}`);
4711
+ return fullPath;
4712
+ }
4713
+ const specs = [];
4714
+ for (const file of specFiles) {
4715
+ const fullPath = path13.join(specDir, file);
4716
+ const content = await FileUtils.read(fullPath);
4717
+ const status = SpecUtils.parseSpecStatus(content);
4718
+ specs.push({ file: fullPath, name: file, status });
4719
+ }
4720
+ const activeSpecs = specs.filter(
4721
+ (s) => s.status === "\u5DF2\u62C6\u5206" || s.status === "\u8FDB\u884C\u4E2D" || s.status === "\u5DF2\u5B8C\u6210"
4722
+ );
4723
+ if (activeSpecs.length === 0) {
4724
+ logger.warn("\u6CA1\u6709\u53EF\u9A8C\u6536\u7684 spec \u6587\u4EF6");
4725
+ const { continueAnyway } = await inquirer6.prompt([
4726
+ {
4727
+ type: "confirm",
4728
+ name: "continueAnyway",
4729
+ message: "\u662F\u5426\u7EE7\u7EED\u67E5\u770B\u6240\u6709 spec?",
4730
+ default: true
4731
+ }
4732
+ ]);
4733
+ if (!continueAnyway) {
4734
+ process.exit(0);
4735
+ }
4736
+ }
4737
+ const targetSpecs = activeSpecs.length > 0 ? activeSpecs : specs;
4738
+ const choices = targetSpecs.map((spec) => ({
4739
+ name: `[${spec.status}] ${spec.name}`,
4740
+ value: spec.file,
4741
+ short: spec.name
4742
+ }));
4743
+ const { selectedFile } = await inquirer6.prompt([
4744
+ {
4745
+ type: "list",
4746
+ name: "selectedFile",
4747
+ message: "\u9009\u62E9\u8981\u9A8C\u6536\u7684 spec:",
4748
+ choices
4749
+ }
4750
+ ]);
4751
+ logger.success(`\u5DF2\u9009\u62E9: ${selectedFile}`);
4752
+ return selectedFile;
4753
+ }
4754
+ async function selectMilestone2(specFile) {
4755
+ logger.newLine();
4756
+ logger.step("\u6B65\u9AA4 2/4: \u89E3\u6790 milestones...");
4757
+ logger.newLine();
4758
+ const specContent = await FileUtils.read(specFile);
4759
+ const { enhanced } = SpecUtils.parseMilestonesEnhancedWithFallback(specContent);
4760
+ if (enhanced.length === 0) {
4761
+ throw new Error("\u8BE5 spec \u5C1A\u672A\u62C6\u5206 milestones\uFF0C\u65E0\u6CD5\u8FDB\u884C\u9A8C\u6536");
4762
+ }
4763
+ const choices = enhanced.map((m, idx) => {
4764
+ const isDone = m.completedCount === m.totalCount;
4765
+ const statusIcon = isDone ? "\u2713" : m.completedCount > 0 ? "\u27F3" : "\u25CB";
4766
+ const progress = `[${m.completedCount}/${m.totalCount}]`;
4767
+ return {
4768
+ name: `${idx + 1}. ${statusIcon} ${progress} ${m.title}`,
4769
+ value: m.title,
4770
+ short: m.title
4771
+ };
4772
+ });
4773
+ const { milestone } = await inquirer6.prompt([
4774
+ {
4775
+ type: "list",
4776
+ name: "milestone",
4777
+ message: "\u9009\u62E9\u8981\u9A8C\u6536\u7684 milestone:",
4778
+ choices
4779
+ }
4780
+ ]);
4781
+ return milestone;
4782
+ }
4783
+ async function runAcceptanceCheck(specFile, milestone) {
4784
+ logger.newLine();
4785
+ logger.step("\u6B65\u9AA4 3/4: \u6267\u884C\u9A8C\u6536\u68C0\u67E5...");
4786
+ logger.newLine();
4787
+ const specContent = await FileUtils.read(specFile);
4788
+ const { enhanced } = SpecUtils.parseMilestonesEnhancedWithFallback(specFile);
4789
+ const targetMilestone = enhanced.find((m) => m.title === milestone);
4790
+ if (!targetMilestone) {
4791
+ throw new Error(`\u672A\u627E\u5230 milestone: ${milestone}`);
4792
+ }
4793
+ const result = {
4794
+ specFile,
4795
+ milestone,
4796
+ checkTime: (/* @__PURE__ */ new Date()).toLocaleString("zh-CN"),
4797
+ frontendTasks: { total: 0, completed: 0, items: [] },
4798
+ backendTasks: { total: 0, completed: 0, items: [] },
4799
+ apiVerification: { total: 0, verified: 0, items: [] },
4800
+ integrationTasks: { total: 0, completed: 0, items: [] },
4801
+ issues: []
4802
+ };
4803
+ logger.info("\u68C0\u67E5\u524D\u7AEF\u4EFB\u52A1...");
4804
+ for (const todo of targetMilestone.frontendTodos) {
4805
+ const checkResult = await checkFrontendTask(todo);
4806
+ result.frontendTasks.items.push(checkResult);
4807
+ if (checkResult.status === "pass") {
4808
+ result.frontendTasks.completed++;
4809
+ }
4810
+ result.frontendTasks.total++;
4811
+ const icon = checkResult.status === "pass" ? "\u2713" : checkResult.status === "fail" ? "\u2717" : "\u25CB";
4812
+ logger.info(` ${icon} [F] ${todo.content}${checkResult.filePath ? ` - ${checkResult.filePath}` : ""}`);
4813
+ }
4814
+ logger.info("\u68C0\u67E5\u540E\u7AEF\u4EFB\u52A1...");
4815
+ for (const todo of targetMilestone.backendTodos) {
4816
+ const checkResult = await checkBackendTask(todo);
4817
+ result.backendTasks.items.push(checkResult);
4818
+ if (checkResult.status === "pass") {
4819
+ result.backendTasks.completed++;
4820
+ }
4821
+ result.backendTasks.total++;
4822
+ const icon = checkResult.status === "pass" ? "\u2713" : checkResult.status === "fail" ? "\u2717" : "\u25CB";
4823
+ logger.info(` ${icon} [B] ${todo.content}${checkResult.filePath ? ` - ${checkResult.filePath}` : ""}`);
4824
+ }
4825
+ logger.info("\u9A8C\u8BC1 API \u5B9E\u73B0...");
4826
+ for (const todo of targetMilestone.backendTodos) {
4827
+ if (todo.apiAssociation) {
4828
+ const checkResult = await verifyApiImplementation(todo);
4829
+ result.apiVerification.items.push(checkResult);
4830
+ if (checkResult.status === "pass") {
4831
+ result.apiVerification.verified++;
4832
+ }
4833
+ result.apiVerification.total++;
4834
+ const icon = checkResult.status === "pass" ? "\u2713" : checkResult.status === "fail" ? "\u2717" : "\u25CB";
4835
+ logger.info(` ${icon} ${todo.apiAssociation}${checkResult.filePath ? ` - ${checkResult.filePath}` : ""}`);
4836
+ }
4837
+ }
4838
+ logger.info("\u68C0\u67E5\u8054\u8C03\u4EFB\u52A1...");
4839
+ for (const todo of targetMilestone.integrationTodos) {
4840
+ const checkResult = await checkIntegrationTask(todo);
4841
+ result.integrationTasks.items.push(checkResult);
4842
+ if (checkResult.status === "pass") {
4843
+ result.integrationTasks.completed++;
4844
+ }
4845
+ result.integrationTasks.total++;
4846
+ const icon = checkResult.status === "pass" ? "\u2713" : checkResult.status === "fail" ? "\u2717" : "\u25CB";
4847
+ logger.info(` ${icon} [I] ${todo.content}`);
4848
+ }
4849
+ return result;
4850
+ }
4851
+ async function checkFrontendTask(todo) {
4852
+ const frontendPaths = [
4853
+ `frontend/src/pages/${todo.content}.tsx`,
4854
+ `frontend/src/components/${todo.content}.tsx`,
4855
+ `frontend/src/components/${todo.content.replace(/\s+/g, "")}.tsx`,
4856
+ `frontend/src/views/${todo.content}.vue`,
4857
+ `frontend/src/components/${todo.content}.vue`
4858
+ ];
4859
+ for (const fp of frontendPaths) {
4860
+ if (await FileUtils.exists(fp)) {
4861
+ return {
4862
+ description: `[F] ${todo.content}`,
4863
+ status: "pass",
4864
+ details: "\u524D\u7AEF\u4EE3\u7801\u5B58\u5728",
4865
+ filePath: fp
4866
+ };
4867
+ }
4868
+ }
4869
+ const pathMatch = todo.content.match(/\s*-\s*(.+?\.(tsx|vue|js|jsx))\s*/);
4870
+ if (pathMatch) {
4871
+ const filePath = pathMatch[1];
4872
+ if (await FileUtils.exists(filePath)) {
4873
+ return {
4874
+ description: `[F] ${todo.content}`,
4875
+ status: "pass",
4876
+ details: "\u524D\u7AEF\u4EE3\u7801\u5B58\u5728",
4877
+ filePath
4878
+ };
4879
+ }
4880
+ }
4881
+ return {
4882
+ description: `[F] ${todo.content}`,
4883
+ status: "fail",
4884
+ details: "\u524D\u7AEF\u4EE3\u7801\u4E0D\u5B58\u5728\u6216\u8DEF\u5F84\u65E0\u6CD5\u9A8C\u8BC1"
4885
+ };
4886
+ }
4887
+ async function checkBackendTask(todo) {
4888
+ const backendPaths = [
4889
+ `backend/src/main/java/${todo.content.replace(/\s+/g, "/")}.java`,
4890
+ `backend/src/${todo.content.toLowerCase().replace(/\s+/g, "/")}.java`
4891
+ ];
4892
+ for (const fp of backendPaths) {
4893
+ if (await FileUtils.exists(fp)) {
4894
+ return {
4895
+ description: `[B] ${todo.content}`,
4896
+ status: "pass",
4897
+ details: "\u540E\u7AEF\u4EE3\u7801\u5B58\u5728",
4898
+ filePath: fp
4899
+ };
4900
+ }
4901
+ }
4902
+ const pathMatch = todo.content.match(/\s*-\s*(.+?\.(java|kt|py|go))\s*/);
4903
+ if (pathMatch) {
4904
+ const filePath = pathMatch[1];
4905
+ if (await FileUtils.exists(filePath)) {
4906
+ return {
4907
+ description: `[B] ${todo.content}`,
4908
+ status: "pass",
4909
+ details: "\u540E\u7AEF\u4EE3\u7801\u5B58\u5728",
4910
+ filePath
4911
+ };
4912
+ }
4913
+ }
4914
+ return {
4915
+ description: `[B] ${todo.content}`,
4916
+ status: "fail",
4917
+ details: "\u540E\u7AEF\u4EE3\u7801\u4E0D\u5B58\u5728\u6216\u8DEF\u5F84\u65E0\u6CD5\u9A8C\u8BC1"
4918
+ };
4919
+ }
4920
+ async function verifyApiImplementation(todo) {
4921
+ if (!todo.apiAssociation) {
4922
+ return {
4923
+ description: todo.apiAssociation || "API \u9A8C\u8BC1",
4924
+ status: "pending",
4925
+ details: "\u65E0 API \u5173\u8054\u4FE1\u606F"
4926
+ };
4927
+ }
4928
+ const apiMatch = todo.apiAssociation.match(/^(GET|POST|PUT|DELETE|PATCH)\s+\/(.+)$/);
4929
+ if (!apiMatch) {
4930
+ return {
4931
+ description: todo.apiAssociation,
4932
+ status: "pending",
4933
+ details: "\u65E0\u6CD5\u89E3\u6790 API \u683C\u5F0F"
4934
+ };
4935
+ }
4936
+ const method = apiMatch[1];
4937
+ const apiPath = apiMatch[2];
4938
+ const controllerPaths = [
4939
+ `backend/src/main/java/**/*Controller.java`,
4940
+ `backend/src/**/*Controller.java`
4941
+ ];
4942
+ const controllerFiles = await FileUtils.findFiles("**/*Controller.java", "backend/src");
4943
+ for (const cf of controllerFiles) {
4944
+ const content = await FileUtils.read(cf);
4945
+ if (content.includes(apiPath) || content.includes(`"${apiPath}"`)) {
4946
+ const methodAnnotations = {
4947
+ GET: ["@GetMapping", "@RequestMapping(method = RequestMethod.GET)"],
4948
+ POST: ["@PostMapping", "@RequestMapping(method = RequestMethod.POST)"],
4949
+ PUT: ["@PutMapping", "@RequestMapping(method = RequestMethod.PUT)"],
4950
+ DELETE: ["@DeleteMapping", "@RequestMapping(method = RequestMethod.DELETE)"],
4951
+ PATCH: ["@PatchMapping", "@RequestMapping(method = RequestMethod.PATCH)"]
4952
+ };
4953
+ for (const annotation of methodAnnotations[method] || []) {
4954
+ if (content.includes(annotation)) {
4955
+ return {
4956
+ description: todo.apiAssociation,
4957
+ status: "pass",
4958
+ details: "API Controller \u5B9E\u73B0\u5B58\u5728",
4959
+ filePath: cf
4960
+ };
4961
+ }
4962
+ }
4963
+ }
4964
+ }
4965
+ return {
4966
+ description: todo.apiAssociation,
4967
+ status: "fail",
4968
+ details: "API Controller \u672A\u5B9E\u73B0"
4969
+ };
4970
+ }
4971
+ async function checkIntegrationTask(todo) {
4972
+ const integrationEvidence = [
4973
+ "**/*integration*.test.*",
4974
+ "**/*e2e*.test.*",
4975
+ "**/*IT.java",
4976
+ "docs/integration-test-results.md",
4977
+ "docs/session-logs/**"
4978
+ ];
4979
+ const sessionDir = "docs/sessions";
4980
+ if (await FileUtils.exists(sessionDir)) {
4981
+ const sessionFiles = await FileUtils.findFiles("*.md", sessionDir);
4982
+ const hasRecentSession = sessionFiles.some(
4983
+ (sf) => sf.includes("integration") || sf.includes("\u8054\u8C03")
4984
+ );
4985
+ if (hasRecentSession) {
4986
+ return {
4987
+ description: `[I] ${todo.content}`,
4988
+ status: "pass",
4989
+ details: "\u8054\u8C03\u8BC1\u636E\u5B58\u5728\uFF08session \u65E5\u5FD7\uFF09"
4990
+ };
4991
+ }
4992
+ }
4993
+ return {
4994
+ description: `[I] ${todo.content}`,
4995
+ status: "pending",
4996
+ details: "\u5EFA\u8BAE\u4EBA\u5DE5\u9A8C\u8BC1\u8054\u8C03\u7ED3\u679C"
4997
+ };
4998
+ }
4999
+ async function generateAcceptanceReport(result) {
5000
+ logger.newLine();
5001
+ logger.step("\u6B65\u9AA4 4/4: \u751F\u6210\u9A8C\u6536\u62A5\u544A...");
5002
+ logger.newLine();
5003
+ const reportDir = "docs/acceptance-reports";
5004
+ await FileUtils.ensureDir(reportDir);
5005
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5006
+ const specName = path13.basename(result.specFile, ".md");
5007
+ const milestoneSafe = result.milestone.replace(/[^a-zA-Z0-9]/g, "-");
5008
+ const reportFile = path13.join(reportDir, `${timestamp}_${specName}_${milestoneSafe}.md`);
5009
+ const report = generateMarkdownReport(result);
5010
+ await FileUtils.write(reportFile, report);
5011
+ logger.success(`\u9A8C\u6536\u62A5\u544A\u5DF2\u751F\u6210: ${reportFile}`);
5012
+ logger.newLine();
5013
+ console.log(generateConsoleReport(result));
5014
+ }
5015
+ function generateMarkdownReport(result) {
5016
+ const lines = [];
5017
+ lines.push("# \u9A8C\u6536\u62A5\u544A");
5018
+ lines.push("");
5019
+ lines.push(`**Spec \u6587\u4EF6**: ${result.specFile}`);
5020
+ lines.push(`**Milestone**: ${result.milestone}`);
5021
+ lines.push(`**\u9A8C\u6536\u65F6\u95F4**: ${result.checkTime}`);
5022
+ lines.push("");
5023
+ lines.push("## \u68C0\u67E5\u7ED3\u679C\u6C47\u603B");
5024
+ lines.push("");
5025
+ lines.push("| \u68C0\u67E5\u9879 | \u72B6\u6001 |");
5026
+ lines.push("|--------|------|");
5027
+ lines.push(
5028
+ `| \u524D\u7AEF\u4EFB\u52A1 | ${result.frontendTasks.completed}/${result.frontendTasks.total} \u5B8C\u6210 |`
5029
+ );
5030
+ lines.push(
5031
+ `| \u540E\u7AEF\u4EFB\u52A1 | ${result.backendTasks.completed}/${result.backendTasks.total} \u5B8C\u6210 |`
5032
+ );
5033
+ lines.push(`| API \u9A8C\u8BC1 | ${result.apiVerification.verified}/${result.apiVerification.total} \u5B9E\u73B0 |`);
5034
+ lines.push(
5035
+ `| \u8054\u8C03\u4EFB\u52A1 | ${result.integrationTasks.completed}/${result.integrationTasks.total} \u5B8C\u6210 |`
5036
+ );
5037
+ lines.push("");
5038
+ lines.push("## \u8BE6\u7EC6\u8BB0\u5F55");
5039
+ lines.push("");
5040
+ lines.push("### \u524D\u7AEF\u4EFB\u52A1");
5041
+ lines.push("");
5042
+ for (const item of result.frontendTasks.items) {
5043
+ const icon = item.status === "pass" ? "\u2713" : item.status === "fail" ? "\u2717" : "\u25CB";
5044
+ lines.push(`- ${icon} ${item.description} - ${item.details || ""} ${item.filePath ? `(\`${item.filePath}\`)` : ""}`);
5045
+ }
5046
+ lines.push("");
5047
+ lines.push("### \u540E\u7AEF\u4EFB\u52A1");
5048
+ lines.push("");
5049
+ for (const item of result.backendTasks.items) {
5050
+ const icon = item.status === "pass" ? "\u2713" : item.status === "fail" ? "\u2717" : "\u25CB";
5051
+ lines.push(`- ${icon} ${item.description} - ${item.details || ""} ${item.filePath ? `(\`${item.filePath}\`)` : ""}`);
5052
+ }
5053
+ lines.push("");
5054
+ lines.push("### API \u9A8C\u8BC1");
5055
+ lines.push("");
5056
+ for (const item of result.apiVerification.items) {
5057
+ const icon = item.status === "pass" ? "\u2713" : item.status === "fail" ? "\u2717" : "\u25CB";
5058
+ lines.push(`- ${icon} ${item.description} - ${item.details || ""} ${item.filePath ? `(\`${item.filePath}\`)` : ""}`);
5059
+ }
5060
+ lines.push("");
5061
+ lines.push("### \u8054\u8C03\u4EFB\u52A1");
5062
+ lines.push("");
5063
+ for (const item of result.integrationTasks.items) {
5064
+ const icon = item.status === "pass" ? "\u2713" : item.status === "fail" ? "\u2717" : "\u26A0";
5065
+ lines.push(`- ${icon} ${item.description} - ${item.details || ""}`);
5066
+ }
5067
+ lines.push("");
5068
+ if (result.issues.length > 0) {
5069
+ lines.push("## \u53D1\u73B0\u7684\u95EE\u9898");
5070
+ lines.push("");
5071
+ lines.push("| \u95EE\u9898 | \u7C7B\u578B | \u4E25\u91CD\u7A0B\u5EA6 | \u72B6\u6001 |");
5072
+ lines.push("|------|------|---------|------|");
5073
+ for (const issue of result.issues) {
5074
+ lines.push(`| ${issue.title} | ${issue.type} | ${issue.severity} | ${issue.status} |`);
5075
+ }
5076
+ lines.push("");
5077
+ lines.push("**\u64CD\u4F5C**:");
5078
+ lines.push(`- \u8FD0\u884C \`team-cli bugfix ${result.specFile}\` \u67E5\u770B\u8BE6\u60C5`);
5079
+ lines.push("- \u6216\u8FD0\u884C `team-cli hotfix` \u7ACB\u5373\u4FEE\u590D");
5080
+ lines.push("");
5081
+ }
5082
+ lines.push("## \u4E0B\u4E00\u6B65\u5EFA\u8BAE");
5083
+ lines.push("");
5084
+ if (result.issues.length > 0) {
5085
+ lines.push("- [ ] \u4FEE\u590D\u53D1\u73B0\u7684\u95EE\u9898");
5086
+ }
5087
+ lines.push("- [ ] \u8FD0\u884C `team-cli dev` \u7EE7\u7EED\u5F00\u53D1");
5088
+ lines.push("- [ ] \u8FD0\u884C `team-cli accept` \u91CD\u65B0\u9A8C\u6536");
5089
+ lines.push("");
5090
+ return lines.join("\n");
5091
+ }
5092
+ function generateConsoleReport(result) {
5093
+ const lines = [];
5094
+ lines.push("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
5095
+ lines.push("\u2502 \u9A8C \u6536 \u7ED3 \u679C \u6458 \u8981 \u2502");
5096
+ lines.push("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
5097
+ lines.push(`\u2502 Spec: ${result.specFile.padEnd(40)}\u2502`);
5098
+ lines.push(`\u2502 Milestone: ${result.milestone.padEnd(37)}\u2502`);
5099
+ lines.push("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
5100
+ lines.push(
5101
+ `\u2502 \u524D\u7AEF\u4EFB\u52A1: ${result.frontendTasks.completed}/${result.frontendTasks.total} \u5B8C\u6210`.padEnd(47) + "\u2502"
5102
+ );
5103
+ lines.push(
5104
+ `\u2502 \u540E\u7AEF\u4EFB\u52A1: ${result.backendTasks.completed}/${result.backendTasks.total} \u5B8C\u6210`.padEnd(47) + "\u2502"
5105
+ );
5106
+ lines.push(
5107
+ `\u2502 API \u9A8C\u8BC1: ${result.apiVerification.verified}/${result.apiVerification.total} \u5B9E\u73B0`.padEnd(47) + "\u2502"
5108
+ );
5109
+ lines.push(
5110
+ `\u2502 \u8054\u8C03\u4EFB\u52A1: ${result.integrationTasks.completed}/${result.integrationTasks.total} \u5B8C\u6210`.padEnd(47) + "\u2502"
5111
+ );
5112
+ lines.push("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
5113
+ const totalIssues = result.issues.length;
5114
+ if (totalIssues > 0) {
5115
+ lines.push(`\u2502 \u26A0 \u53D1\u73B0\u95EE\u9898: ${totalIssues} \u4E2A`.padEnd(47) + "\u2502");
5116
+ } else {
5117
+ lines.push(`\u2502 \u2713 \u9A8C\u6536\u901A\u8FC7`.padEnd(47) + "\u2502");
5118
+ }
5119
+ lines.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
5120
+ return lines.join("\n");
5121
+ }
5122
+ async function handleIssues(result) {
5123
+ logger.newLine();
5124
+ logger.warn(`\u53D1\u73B0 ${result.issues.length} \u4E2A\u95EE\u9898\u9700\u8981\u5904\u7406`);
5125
+ const bugfixDir = "docs/bugfixes";
5126
+ await FileUtils.ensureDir(bugfixDir);
5127
+ for (const issue of result.issues) {
5128
+ const bugfixFile = path13.join(
5129
+ bugfixDir,
5130
+ `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}_${issue.id}.md`
5131
+ );
5132
+ const bugfixContent = generateBugfixContent(result, issue);
5133
+ await FileUtils.write(bugfixFile, bugfixContent);
5134
+ logger.info(` \u5DF2\u521B\u5EFA Bugfix \u8BB0\u5F55: ${bugfixFile}`);
5135
+ }
5136
+ logger.newLine();
5137
+ const { fixNow } = await inquirer6.prompt([
5138
+ {
5139
+ type: "confirm",
5140
+ name: "fixNow",
5141
+ message: "\u662F\u5426\u7ACB\u5373\u4FEE\u590D\u53D1\u73B0\u7684\u95EE\u9898?",
5142
+ default: false
5143
+ }
5144
+ ]);
5145
+ if (fixNow) {
5146
+ logger.info("\u8BF7\u8FD0\u884C `team-cli hotfix` \u7ACB\u5373\u4FEE\u590D\u95EE\u9898");
5147
+ } else {
5148
+ logger.info(`\u95EE\u9898\u8BB0\u5F55\u5DF2\u4FDD\u5B58\u5230 ${bugfixDir} \u76EE\u5F55`);
5149
+ logger.info("\u8FD0\u884C `team-cli bugfix` \u67E5\u770B\u6240\u6709\u95EE\u9898\u8BB0\u5F55");
5150
+ }
5151
+ }
5152
+ function generateBugfixContent(result, issue) {
5153
+ const lines = [];
5154
+ lines.push("# Bugfix \u8BB0\u5F55");
5155
+ lines.push("");
5156
+ lines.push(`**ID**: ${issue.id}`);
5157
+ lines.push(`**\u521B\u5EFA\u65F6\u95F4**: ${issue.createdAt}`);
5158
+ lines.push(`**\u72B6\u6001**: ${issue.status}`);
5159
+ lines.push("");
5160
+ lines.push("## \u95EE\u9898\u63CF\u8FF0");
5161
+ lines.push("");
5162
+ lines.push(issue.description);
5163
+ lines.push("");
5164
+ lines.push("## \u6240\u5C5E\u8303\u56F4");
5165
+ lines.push("");
5166
+ lines.push(`- Spec: ${result.specFile}`);
5167
+ lines.push(`- Milestone: ${result.milestone}`);
5168
+ if (issue.todo) {
5169
+ lines.push(`- Todo: ${issue.todo}`);
5170
+ }
5171
+ lines.push("");
5172
+ lines.push("## \u4E25\u91CD\u7A0B\u5EA6");
5173
+ lines.push("");
5174
+ lines.push(`- ${issue.severity.toUpperCase()}`);
5175
+ lines.push("");
5176
+ lines.push("## \u95EE\u9898\u7C7B\u578B");
5177
+ lines.push("");
5178
+ lines.push(`- ${issue.type}`);
5179
+ lines.push("");
5180
+ lines.push("## \u89E3\u51B3\u65B9\u6848");
5181
+ lines.push("");
5182
+ lines.push("<!-- TODO: \u586B\u5199\u89E3\u51B3\u65B9\u6848 -->");
5183
+ lines.push("");
5184
+ lines.push("## \u9A8C\u8BC1\u6B65\u9AA4");
5185
+ lines.push("");
5186
+ lines.push("1. ");
5187
+ lines.push("2. ");
5188
+ lines.push("3. ");
5189
+ lines.push("");
5190
+ return lines.join("\n");
5191
+ }
5192
+ async function syncSpecStatus(specFile, result) {
5193
+ const content = await FileUtils.read(specFile);
5194
+ const lines = content.split("\n");
5195
+ let inTargetMilestone = false;
5196
+ let milestoneIndex = -1;
5197
+ for (let i = 0; i < lines.length; i++) {
5198
+ const line = lines[i];
5199
+ if (line.includes(result.milestone)) {
5200
+ inTargetMilestone = true;
5201
+ milestoneIndex = i;
5202
+ continue;
5203
+ }
5204
+ if (inTargetMilestone && line.match(/^###\s+Milestone/)) {
5205
+ break;
5206
+ }
5207
+ }
5208
+ if (milestoneIndex !== -1) {
5209
+ let completedTasks = 0;
5210
+ let totalTasks = 0;
5211
+ for (let i = milestoneIndex + 1; i < lines.length; i++) {
5212
+ const line = lines[i];
5213
+ if (line.match(/^###\s+Milestone/)) {
5214
+ break;
5215
+ }
5216
+ if (line.match(/^-\s+\[/)) {
5217
+ totalTasks++;
5218
+ if (line.match(/^-\s+\[x\]/)) {
5219
+ completedTasks++;
5220
+ }
5221
+ }
5222
+ }
5223
+ const progressLine = `${result.milestone} [${completedTasks}/${totalTasks}]`;
5224
+ const linesBefore = lines.slice(0, milestoneIndex);
5225
+ const linesAfter = lines.slice(milestoneIndex + 1);
5226
+ if (!lines[milestoneIndex].includes(`[${completedTasks}/${totalTasks}]`)) {
5227
+ const updatedMilestoneLine = lines[milestoneIndex].replace(
5228
+ /(\s*\[\d+\/\d+\])?$/,
5229
+ ` [${completedTasks}/${totalTasks}]`
5230
+ );
5231
+ lines[milestoneIndex] = updatedMilestoneLine;
5232
+ await FileUtils.write(specFile, lines.join("\n"));
5233
+ logger.info(`\u5DF2\u540C\u6B65\u91CC\u7A0B\u7891\u8FDB\u5EA6: [${completedTasks}/${totalTasks}]`);
5234
+ }
5235
+ }
5236
+ }
5237
+ var acceptCommand;
5238
+ var init_accept = __esm({
5239
+ "src/commands/accept.ts"() {
5240
+ "use strict";
5241
+ init_esm_shims();
5242
+ init_utils();
5243
+ init_logger();
5244
+ acceptCommand = new Command7("accept").argument("[spec-file]", "Spec \u6587\u4EF6\u8DEF\u5F84").description("\u9A8C\u6536\u529F\u80FD - \u8D70\u67E5\u6240\u6709\u9700\u6C42\uFF0C\u9A8C\u8BC1\u8054\u8C03\u662F\u5426\u5B8C\u6210").action(async (specFile) => {
5245
+ try {
5246
+ logger.header("\u9A8C\u6536\u6A21\u5F0F");
5247
+ logger.newLine();
5248
+ const hasTechStack = await FileUtils.exists("TECH_STACK.md");
5249
+ if (!hasTechStack) {
5250
+ logger.error("\u5F53\u524D\u76EE\u5F55\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684 team-cli \u9879\u76EE");
5251
+ logger.info("\u8BF7\u5148\u8FD0\u884C 'team-cli init <project-name>' \u6216\u5207\u6362\u5230\u9879\u76EE\u76EE\u5F55");
5252
+ process.exit(1);
5253
+ }
5254
+ logger.success("\u68C0\u6D4B\u5230\u9879\u76EE\u4E0A\u4E0B\u6587");
5255
+ const selectedSpec = await selectSpec2(specFile);
5256
+ const selectedMilestone = await selectMilestone2(selectedSpec);
5257
+ const result = await runAcceptanceCheck(selectedSpec, selectedMilestone);
5258
+ await generateAcceptanceReport(result);
5259
+ if (result.issues.length > 0) {
5260
+ await handleIssues(result);
5261
+ }
5262
+ await syncSpecStatus(selectedSpec, result);
5263
+ logger.header("\u9A8C\u6536\u5B8C\u6210!");
5264
+ logger.newLine();
5265
+ } catch (error) {
5266
+ logger.error(`\u9A8C\u6536\u5931\u8D25: ${error.message}`);
5267
+ if (process.env.DEBUG) {
5268
+ console.error(error);
5269
+ }
5270
+ process.exit(1);
5271
+ }
5272
+ });
5273
+ }
5274
+ });
5275
+
5276
+ // src/commands/lint.ts
5277
+ import { Command as Command8 } from "commander";
4472
5278
  import { execa as execa3 } from "execa";
4473
5279
  var lintCommand;
4474
5280
  var init_lint = __esm({
@@ -4477,7 +5283,7 @@ var init_lint = __esm({
4477
5283
  init_esm_shims();
4478
5284
  init_utils();
4479
5285
  init_logger();
4480
- lintCommand = new Command7("lint").option("--fix", "\u81EA\u52A8\u4FEE\u590D\u95EE\u9898").description("\u4EE3\u7801\u8D28\u91CF\u68C0\u67E5 (\u524D\u7AEF + \u540E\u7AEF)").action(async (options) => {
5286
+ lintCommand = new Command8("lint").option("--fix", "\u81EA\u52A8\u4FEE\u590D\u95EE\u9898").option("--no-type-check", "\u8DF3\u8FC7 TypeScript \u7C7B\u578B\u68C0\u67E5").description("\u4EE3\u7801\u8D28\u91CF\u68C0\u67E5 (\u524D\u7AEF + \u540E\u7AEF)").action(async (options) => {
4481
5287
  try {
4482
5288
  logger.header("\u4EE3\u7801\u8D28\u91CF\u68C0\u67E5");
4483
5289
  logger.newLine();
@@ -4507,15 +5313,26 @@ var init_lint = __esm({
4507
5313
  stdio: "inherit"
4508
5314
  });
4509
5315
  }
4510
- await execa3("npx", ["tsc", "--noEmit"], {
4511
- cwd: "frontend",
4512
- stdio: "pipe"
4513
- });
5316
+ if (options.typeCheck !== false) {
5317
+ try {
5318
+ logger.step("\u6B63\u5728\u8FDB\u884C TypeScript \u7C7B\u578B\u68C0\u67E5...");
5319
+ await execa3("npx", ["tsc", "--noEmit"], {
5320
+ cwd: "frontend",
5321
+ stdio: "pipe"
5322
+ });
5323
+ } catch (tscError) {
5324
+ logger.warn("TypeScript \u7C7B\u578B\u68C0\u67E5\u53D1\u73B0\u95EE\u9898\uFF0C\u8BF7\u68C0\u67E5\u4EE3\u7801\u7C7B\u578B\u5B89\u5168\u3002");
5325
+ if (process.env.DEBUG) {
5326
+ console.log(tscError.stdout);
5327
+ }
5328
+ results.frontend.errors.push("TypeScript \u7C7B\u578B\u68C0\u67E5\u5931\u8D25 (\u5DF2\u8DF3\u8FC7\u963B\u585E)");
5329
+ }
5330
+ }
4514
5331
  results.frontend.passed = true;
4515
5332
  logger.success("\u524D\u7AEF\u4EE3\u7801\u68C0\u67E5\u901A\u8FC7");
4516
5333
  } catch (error) {
4517
5334
  results.frontend.errors.push(error.message);
4518
- logger.error("\u524D\u7AEF\u4EE3\u7801\u68C0\u67E5\u5931\u8D25");
5335
+ logger.error(`\u524D\u7AEF\u4EE3\u7801\u68C0\u67E5\u5931\u8D25: ${error.message}`);
4519
5336
  }
4520
5337
  } else {
4521
5338
  logger.info("\u672A\u627E\u5230\u524D\u7AEF\u9879\u76EE (frontend/package.json)");
@@ -4600,8 +5417,8 @@ var init_lint = __esm({
4600
5417
  });
4601
5418
 
4602
5419
  // src/commands/status.ts
4603
- import { Command as Command8 } from "commander";
4604
- import path13 from "path";
5420
+ import { Command as Command9 } from "commander";
5421
+ import path14 from "path";
4605
5422
  async function displayProjectInfo() {
4606
5423
  logger.info("\u9879\u76EE\u4FE1\u606F:");
4607
5424
  logger.newLine();
@@ -4637,7 +5454,7 @@ async function displayFeatureInventory() {
4637
5454
  }
4638
5455
  const inventory = [];
4639
5456
  for (const file of specs) {
4640
- const filePath = path13.join(specDir, file);
5457
+ const filePath = path14.join(specDir, file);
4641
5458
  const content = await FileUtils.read(filePath);
4642
5459
  const status = SpecUtils.parseSpecStatus(content);
4643
5460
  const statusWithIcon = SpecUtils.getStatusWithIcon(status);
@@ -4697,7 +5514,7 @@ async function displayRecentActivity() {
4697
5514
  }
4698
5515
  const sorted = files.sort().reverse().slice(0, 5);
4699
5516
  for (const file of sorted) {
4700
- const filePath = path13.join(sessionDir, file);
5517
+ const filePath = path14.join(sessionDir, file);
4701
5518
  const stat = await FileUtils.read(filePath);
4702
5519
  const specMatch = stat.match(/\*\*Spec\*\*:\s*(.+)/);
4703
5520
  const spec = specMatch ? specMatch[1].trim() : "\u672A\u77E5";
@@ -4718,7 +5535,7 @@ var init_status = __esm({
4718
5535
  init_esm_shims();
4719
5536
  init_utils();
4720
5537
  init_logger();
4721
- statusCommand = new Command8("status").description("\u67E5\u770B\u9879\u76EE\u72B6\u6001").action(async () => {
5538
+ statusCommand = new Command9("status").description("\u67E5\u770B\u9879\u76EE\u72B6\u6001").action(async () => {
4722
5539
  try {
4723
5540
  logger.header("\u9879\u76EE\u72B6\u6001");
4724
5541
  logger.newLine();
@@ -4744,14 +5561,14 @@ var init_status = __esm({
4744
5561
  });
4745
5562
 
4746
5563
  // src/commands/detect-deps.ts
4747
- import { Command as Command9 } from "commander";
4748
- import path14 from "path";
4749
- import inquirer6 from "inquirer";
5564
+ import { Command as Command10 } from "commander";
5565
+ import path15 from "path";
5566
+ import inquirer7 from "inquirer";
4750
5567
  async function detectDependencies(specFile) {
4751
5568
  logger.step("\u81EA\u52A8\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB...");
4752
5569
  const projectDir = ".";
4753
5570
  const allDeps = /* @__PURE__ */ new Set();
4754
- const backendDir = path14.join(projectDir, "backend");
5571
+ const backendDir = path15.join(projectDir, "backend");
4755
5572
  const backendExists = await FileUtils.exists(backendDir);
4756
5573
  if (backendExists) {
4757
5574
  const apiDeps = await scanBackendApiCalls(backendDir);
@@ -4761,7 +5578,7 @@ async function detectDependencies(specFile) {
4761
5578
  const serviceDeps = await scanBackendServiceRefs(backendDir);
4762
5579
  serviceDeps.forEach((d) => allDeps.add(d));
4763
5580
  }
4764
- const frontendDir = path14.join(projectDir, "frontend");
5581
+ const frontendDir = path15.join(projectDir, "frontend");
4765
5582
  const frontendExists = await FileUtils.exists(frontendDir);
4766
5583
  if (frontendExists) {
4767
5584
  const frontendDeps = await scanFrontendApiCalls(frontendDir);
@@ -4787,7 +5604,7 @@ async function detectDependencies(specFile) {
4787
5604
  logger.step(`- ${spec}`);
4788
5605
  }
4789
5606
  logger.newLine();
4790
- const answers = await inquirer6.prompt([
5607
+ const answers = await inquirer7.prompt([
4791
5608
  {
4792
5609
  type: "confirm",
4793
5610
  name: "autoUpdate",
@@ -4802,11 +5619,11 @@ async function detectDependencies(specFile) {
4802
5619
  }
4803
5620
  async function scanBackendApiCalls(backendDir) {
4804
5621
  const deps = [];
4805
- const srcDir = path14.join(backendDir, "src");
5622
+ const srcDir = path15.join(backendDir, "src");
4806
5623
  try {
4807
5624
  const javaFiles = await FileUtils.findFiles("*.java", srcDir);
4808
5625
  for (const file of javaFiles) {
4809
- const filePath = path14.join(srcDir, file);
5626
+ const filePath = path15.join(srcDir, file);
4810
5627
  const content = await FileUtils.read(filePath);
4811
5628
  const pathRegex = /"(\/api\/[^"]+)"/g;
4812
5629
  let match;
@@ -4824,11 +5641,11 @@ async function scanBackendApiCalls(backendDir) {
4824
5641
  }
4825
5642
  async function scanBackendEntityRelations(backendDir) {
4826
5643
  const deps = [];
4827
- const srcDir = path14.join(backendDir, "src");
5644
+ const srcDir = path15.join(backendDir, "src");
4828
5645
  try {
4829
5646
  const javaFiles = await FileUtils.findFiles("*.java", srcDir);
4830
5647
  for (const file of javaFiles) {
4831
- const filePath = path14.join(srcDir, file);
5648
+ const filePath = path15.join(srcDir, file);
4832
5649
  const content = await FileUtils.read(filePath);
4833
5650
  if (content.includes("@JoinColumn") || content.includes("@ManyToOne") || content.includes("@OneToMany")) {
4834
5651
  const typeRegex = /type\s*=\s*(\w+)/g;
@@ -4844,11 +5661,11 @@ async function scanBackendEntityRelations(backendDir) {
4844
5661
  }
4845
5662
  async function scanBackendServiceRefs(backendDir) {
4846
5663
  const deps = [];
4847
- const srcDir = path14.join(backendDir, "src");
5664
+ const srcDir = path15.join(backendDir, "src");
4848
5665
  try {
4849
5666
  const javaFiles = await FileUtils.findFiles("*.java", srcDir);
4850
5667
  for (const file of javaFiles) {
4851
- const filePath = path14.join(srcDir, file);
5668
+ const filePath = path15.join(srcDir, file);
4852
5669
  const content = await FileUtils.read(filePath);
4853
5670
  const serviceRegex = /private\s+(\w+)Service/g;
4854
5671
  let match;
@@ -4864,11 +5681,11 @@ async function scanBackendServiceRefs(backendDir) {
4864
5681
  }
4865
5682
  async function scanFrontendApiCalls(frontendDir) {
4866
5683
  const deps = [];
4867
- const srcDir = path14.join(frontendDir, "src");
5684
+ const srcDir = path15.join(frontendDir, "src");
4868
5685
  try {
4869
5686
  const tsFiles = await FileUtils.findFiles("*.{ts,tsx,js,jsx}", srcDir);
4870
5687
  for (const file of tsFiles) {
4871
- const filePath = path14.join(srcDir, file);
5688
+ const filePath = path15.join(srcDir, file);
4872
5689
  const content = await FileUtils.read(filePath);
4873
5690
  const pathRegex = /"(\/api\/[^"]+)"/g;
4874
5691
  let match;
@@ -4959,7 +5776,7 @@ var init_detect_deps = __esm({
4959
5776
  init_esm_shims();
4960
5777
  init_utils();
4961
5778
  init_logger();
4962
- detectDepsCommand = new Command9("detect-deps").argument("[spec-file]", "Spec \u6587\u4EF6\u8DEF\u5F84").description("\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB").action(async (specFile) => {
5779
+ detectDepsCommand = new Command10("detect-deps").argument("[spec-file]", "Spec \u6587\u4EF6\u8DEF\u5F84").description("\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB").action(async (specFile) => {
4963
5780
  try {
4964
5781
  logger.header("\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB");
4965
5782
  logger.newLine();
@@ -4985,7 +5802,7 @@ var init_detect_deps = __esm({
4985
5802
  process.exit(1);
4986
5803
  }
4987
5804
  for (const spec of specs) {
4988
- const specPath = path14.join(specsDir, spec);
5805
+ const specPath = path15.join(specsDir, spec);
4989
5806
  logger.step(`\u5904\u7406: ${spec}`);
4990
5807
  await detectDependencies(specPath);
4991
5808
  logger.newLine();
@@ -5011,11 +5828,11 @@ var init_detect_deps = __esm({
5011
5828
  });
5012
5829
 
5013
5830
  // src/commands/sync-memory.ts
5014
- import { Command as Command10 } from "commander";
5015
- import path15 from "path";
5831
+ import { Command as Command11 } from "commander";
5832
+ import path16 from "path";
5016
5833
  async function syncFeatureInventory(aiMemoryFile, projectDir) {
5017
5834
  logger.step("\u540C\u6B65\u529F\u80FD\u6E05\u5355...");
5018
- const specsDir = path15.join(projectDir, "docs/specs");
5835
+ const specsDir = path16.join(projectDir, "docs/specs");
5019
5836
  const exists = await FileUtils.exists(specsDir);
5020
5837
  if (!exists) {
5021
5838
  return;
@@ -5030,7 +5847,7 @@ async function syncFeatureInventory(aiMemoryFile, projectDir) {
5030
5847
  for (const specFile of specs) {
5031
5848
  const name = specFile.replace(".md", "");
5032
5849
  const displayName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
5033
- const specPath = path15.join(specsDir, specFile);
5850
+ const specPath = path16.join(specsDir, specFile);
5034
5851
  const content = await FileUtils.read(specPath);
5035
5852
  const status = SpecUtils.parseSpecStatus(content);
5036
5853
  const statusWithIcon = SpecUtils.getStatusWithIcon(status);
@@ -5049,7 +5866,7 @@ async function syncFeatureInventory(aiMemoryFile, projectDir) {
5049
5866
  }
5050
5867
  async function syncApiInventory(aiMemoryFile, projectDir) {
5051
5868
  logger.step("\u540C\u6B65 API \u5217\u8868...");
5052
- const backendDir = path15.join(projectDir, "backend");
5869
+ const backendDir = path16.join(projectDir, "backend");
5053
5870
  const exists = await FileUtils.exists(backendDir);
5054
5871
  if (!exists) {
5055
5872
  return;
@@ -5059,13 +5876,13 @@ async function syncApiInventory(aiMemoryFile, projectDir) {
5059
5876
  lines.push("");
5060
5877
  lines.push("> \u672C\u90E8\u5206\u7531 team-cli \u81EA\u52A8\u626B\u63CF\u540E\u7AEF Controller \u751F\u6210");
5061
5878
  lines.push("");
5062
- const srcDir = path15.join(backendDir, "src");
5879
+ const srcDir = path16.join(backendDir, "src");
5063
5880
  const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
5064
5881
  if (controllers.length === 0) {
5065
5882
  lines.push("\u6682\u65E0 API");
5066
5883
  } else {
5067
5884
  for (const controllerFile of controllers) {
5068
- const controllerPath = path15.join(srcDir, controllerFile);
5885
+ const controllerPath = path16.join(srcDir, controllerFile);
5069
5886
  const controllerName = controllerFile.replace(".java", "");
5070
5887
  const module = controllerName.replace(/Controller$/, "").toLowerCase();
5071
5888
  lines.push(`### ${module} \u6A21\u5757`);
@@ -5142,7 +5959,7 @@ function extractMethodComment(content, methodName) {
5142
5959
  }
5143
5960
  async function syncDataModels(aiMemoryFile, projectDir) {
5144
5961
  logger.step("\u540C\u6B65\u6570\u636E\u6A21\u578B...");
5145
- const backendDir = path15.join(projectDir, "backend");
5962
+ const backendDir = path16.join(projectDir, "backend");
5146
5963
  const exists = await FileUtils.exists(backendDir);
5147
5964
  if (!exists) {
5148
5965
  return;
@@ -5152,7 +5969,7 @@ async function syncDataModels(aiMemoryFile, projectDir) {
5152
5969
  lines.push("");
5153
5970
  lines.push("> \u672C\u90E8\u5206\u7531 team-cli \u81EA\u52A8\u626B\u63CF\u540E\u7AEF Entity \u751F\u6210");
5154
5971
  lines.push("");
5155
- const srcDir = path15.join(backendDir, "src");
5972
+ const srcDir = path16.join(backendDir, "src");
5156
5973
  const entities = await FileUtils.findFiles("*Entity.java", srcDir);
5157
5974
  if (entities.length === 0) {
5158
5975
  lines.push("\u6682\u65E0\u6570\u636E\u6A21\u578B");
@@ -5160,7 +5977,7 @@ async function syncDataModels(aiMemoryFile, projectDir) {
5160
5977
  lines.push("| \u6A21\u578B | \u8BF4\u660E | \u5B57\u6BB5 | \u5173\u8054 |");
5161
5978
  lines.push("|------|------|------|------|");
5162
5979
  for (const entityFile of entities) {
5163
- const entityPath = path15.join(srcDir, entityFile);
5980
+ const entityPath = path16.join(srcDir, entityFile);
5164
5981
  const entityName = entityFile.replace(".java", "").replace(/Entity$/, "");
5165
5982
  const displayName = entityName.split(/(?=[A-Z])/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
5166
5983
  const content = await FileUtils.read(entityPath);
@@ -5262,15 +6079,15 @@ async function syncTemplateVersions(aiMemoryFile, projectDir) {
5262
6079
  await replaceOrInsertSection(aiMemoryFile, "## \u6A21\u677F\u7248\u672C\u4FE1\u606F", newContent);
5263
6080
  }
5264
6081
  function extractRepoName(repository) {
5265
- let path20 = repository;
5266
- path20 = path20.replace(/^https?:\/\//, "");
5267
- path20 = path20.replace(/^git@/, "");
5268
- const parts = path20.split("/");
6082
+ let path21 = repository;
6083
+ path21 = path21.replace(/^https?:\/\//, "");
6084
+ path21 = path21.replace(/^git@/, "");
6085
+ const parts = path21.split("/");
5269
6086
  if (parts.length > 1) {
5270
- path20 = parts.slice(1).join("/");
6087
+ path21 = parts.slice(1).join("/");
5271
6088
  }
5272
- path20 = path20.replace(/\.git$/, "");
5273
- return path20;
6089
+ path21 = path21.replace(/\.git$/, "");
6090
+ return path21;
5274
6091
  }
5275
6092
  var syncMemoryCommand;
5276
6093
  var init_sync_memory = __esm({
@@ -5280,7 +6097,7 @@ var init_sync_memory = __esm({
5280
6097
  init_utils();
5281
6098
  init_logger();
5282
6099
  init_template_version();
5283
- syncMemoryCommand = new Command10("sync-memory").description("\u540C\u6B65 AI_MEMORY.md").action(async () => {
6100
+ syncMemoryCommand = new Command11("sync-memory").description("\u540C\u6B65 AI_MEMORY.md").action(async () => {
5284
6101
  try {
5285
6102
  logger.header("\u540C\u6B65 AI_MEMORY.md");
5286
6103
  logger.newLine();
@@ -5314,12 +6131,12 @@ var init_sync_memory = __esm({
5314
6131
  });
5315
6132
 
5316
6133
  // src/commands/check-api.ts
5317
- import { Command as Command11 } from "commander";
5318
- import path16 from "path";
5319
- import inquirer7 from "inquirer";
6134
+ import { Command as Command12 } from "commander";
6135
+ import path17 from "path";
6136
+ import inquirer8 from "inquirer";
5320
6137
  import { Listr as Listr6 } from "listr2";
5321
6138
  async function checkApiConflicts(projectDir) {
5322
- const backendDir = path16.join(projectDir, "backend");
6139
+ const backendDir = path17.join(projectDir, "backend");
5323
6140
  const exists = await FileUtils.exists(backendDir);
5324
6141
  if (!exists) {
5325
6142
  logger.info("\u672A\u627E\u5230\u540E\u7AEF\u9879\u76EE");
@@ -5328,10 +6145,10 @@ async function checkApiConflicts(projectDir) {
5328
6145
  logger.step("\u626B\u63CF\u540E\u7AEF API...");
5329
6146
  logger.newLine();
5330
6147
  const apiMap = /* @__PURE__ */ new Map();
5331
- const srcDir = path16.join(backendDir, "src");
6148
+ const srcDir = path17.join(backendDir, "src");
5332
6149
  const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
5333
6150
  for (const controllerFile of controllers) {
5334
- const controllerPath = path16.join(srcDir, controllerFile);
6151
+ const controllerPath = path17.join(srcDir, controllerFile);
5335
6152
  const apis = await extractApisFromController(controllerPath);
5336
6153
  for (const api of apis) {
5337
6154
  const key = `${api.method}:${api.path}`;
@@ -5362,8 +6179,8 @@ async function checkApiConflicts(projectDir) {
5362
6179
  }
5363
6180
  }
5364
6181
  async function detectApiChanges(projectDir) {
5365
- const backendDir = path16.join(projectDir, "backend");
5366
- const registryFile = path16.join(projectDir, "docs/api-registry.md");
6182
+ const backendDir = path17.join(projectDir, "backend");
6183
+ const registryFile = path17.join(projectDir, "docs/api-registry.md");
5367
6184
  const registryExists = await FileUtils.exists(registryFile);
5368
6185
  if (!registryExists) {
5369
6186
  logger.info("API Registry \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u53D8\u66F4\u68C0\u6D4B");
@@ -5375,10 +6192,10 @@ async function detectApiChanges(projectDir) {
5375
6192
  const registryContent = await FileUtils.read(registryFile);
5376
6193
  const existingApis = extractApisFromRegistry(registryContent);
5377
6194
  const currentApis = /* @__PURE__ */ new Map();
5378
- const srcDir = path16.join(backendDir, "src");
6195
+ const srcDir = path17.join(backendDir, "src");
5379
6196
  const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
5380
6197
  for (const controllerFile of controllers) {
5381
- const controllerPath = path16.join(srcDir, controllerFile);
6198
+ const controllerPath = path17.join(srcDir, controllerFile);
5382
6199
  const apis = await extractApisFromController(controllerPath);
5383
6200
  for (const api of apis) {
5384
6201
  const key = `${api.method}:${api.path}`;
@@ -5440,9 +6257,9 @@ async function detectApiChanges(projectDir) {
5440
6257
  }
5441
6258
  }
5442
6259
  async function generateApiRegistry(projectDir) {
5443
- const registryFile = path16.join(projectDir, "docs/api-registry.md");
6260
+ const registryFile = path17.join(projectDir, "docs/api-registry.md");
5444
6261
  logger.step("\u626B\u63CF\u5E76\u751F\u6210 API Registry...");
5445
- await FileUtils.ensureDir(path16.dirname(registryFile));
6262
+ await FileUtils.ensureDir(path17.dirname(registryFile));
5446
6263
  const header = `# API Registry
5447
6264
 
5448
6265
  > \u672C\u6587\u4EF6\u8BB0\u5F55\u6240\u6709 API \u7684\u5B9A\u4E49\u3001\u7248\u672C\u548C\u53D8\u66F4\u5386\u53F2
@@ -5471,14 +6288,14 @@ async function generateApiRegistry(projectDir) {
5471
6288
  *\u6700\u540E\u66F4\u65B0: ${DateUtils.format(/* @__PURE__ */ new Date(), "YYYY-MM-DD HH:mm:ss")}*
5472
6289
  `;
5473
6290
  let content = header;
5474
- const backendDir = path16.join(projectDir, "backend");
6291
+ const backendDir = path17.join(projectDir, "backend");
5475
6292
  const exists = await FileUtils.exists(backendDir);
5476
6293
  if (exists) {
5477
- const srcDir = path16.join(backendDir, "src");
6294
+ const srcDir = path17.join(backendDir, "src");
5478
6295
  const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
5479
6296
  const moduleMap = /* @__PURE__ */ new Map();
5480
6297
  for (const controllerFile of controllers) {
5481
- const controllerPath = path16.join(srcDir, controllerFile);
6298
+ const controllerPath = path17.join(srcDir, controllerFile);
5482
6299
  const controllerName = controllerFile.replace(".java", "");
5483
6300
  const module = controllerName.replace(/Controller$/, "").toLowerCase();
5484
6301
  if (!moduleMap.has(module)) {
@@ -5562,10 +6379,10 @@ function extractApisFromRegistry(registryContent) {
5562
6379
  let match;
5563
6380
  while ((match = apiRegex.exec(registryContent)) !== null) {
5564
6381
  const method = match[1];
5565
- const path20 = match[2].trim();
6382
+ const path21 = match[2].trim();
5566
6383
  const description = match[3].trim();
5567
- const key = `${method}:${path20}`;
5568
- apis.set(key, { method, path: path20, description });
6384
+ const key = `${method}:${path21}`;
6385
+ apis.set(key, { method, path: path21, description });
5569
6386
  }
5570
6387
  return apis;
5571
6388
  }
@@ -5588,7 +6405,7 @@ var init_check_api = __esm({
5588
6405
  init_esm_shims();
5589
6406
  init_utils();
5590
6407
  init_logger();
5591
- checkApiCommand = new Command11("check-api").description("API \u68C0\u67E5\uFF08\u51B2\u7A81/\u53D8\u66F4/Registry\uFF09").action(async () => {
6408
+ checkApiCommand = new Command12("check-api").description("API \u68C0\u67E5\uFF08\u51B2\u7A81/\u53D8\u66F4/Registry\uFF09").action(async () => {
5592
6409
  try {
5593
6410
  logger.header("API \u68C0\u67E5");
5594
6411
  logger.newLine();
@@ -5598,7 +6415,7 @@ var init_check_api = __esm({
5598
6415
  logger.info("\u8BF7\u5148\u8FD0\u884C 'team-cli init <project-name>' \u6216\u5207\u6362\u5230\u9879\u76EE\u76EE\u5F55");
5599
6416
  process.exit(1);
5600
6417
  }
5601
- const answers = await inquirer7.prompt([
6418
+ const answers = await inquirer8.prompt([
5602
6419
  {
5603
6420
  type: "list",
5604
6421
  name: "checkType",
@@ -5652,16 +6469,16 @@ var init_check_api = __esm({
5652
6469
  });
5653
6470
 
5654
6471
  // src/commands/logs.ts
5655
- import { Command as Command12 } from "commander";
5656
- import path17 from "path";
5657
- import inquirer8 from "inquirer";
6472
+ import { Command as Command13 } from "commander";
6473
+ import path18 from "path";
6474
+ import inquirer9 from "inquirer";
5658
6475
  async function collectLogFiles(targetDir) {
5659
6476
  const logs = [];
5660
6477
  try {
5661
6478
  const allFiles = await FileUtils.findFiles("*.md", targetDir);
5662
6479
  const filtered = allFiles.filter((f) => f !== "index.md");
5663
6480
  for (const file of filtered) {
5664
- const filePath = path17.join(targetDir, file);
6481
+ const filePath = path18.join(targetDir, file);
5665
6482
  const stat = await FileUtils.exists(filePath);
5666
6483
  if (stat) {
5667
6484
  logs.push(filePath);
@@ -5678,7 +6495,7 @@ var init_logs = __esm({
5678
6495
  init_esm_shims();
5679
6496
  init_utils();
5680
6497
  init_logger();
5681
- logsCommand = new Command12("logs").argument("[filter]", "\u8FC7\u6EE4\u5668 (today, --all, \u6216\u65E5\u671F YYYY-MM-DD)").description("\u67E5\u770B\u4F1A\u8BDD\u65E5\u5FD7").action(async (filter = "today") => {
6498
+ logsCommand = new Command13("logs").argument("[filter]", "\u8FC7\u6EE4\u5668 (today, --all, \u6216\u65E5\u671F YYYY-MM-DD)").description("\u67E5\u770B\u4F1A\u8BDD\u65E5\u5FD7").action(async (filter = "today") => {
5682
6499
  try {
5683
6500
  logger.header("\u4F1A\u8BDD\u65E5\u5FD7");
5684
6501
  logger.newLine();
@@ -5701,7 +6518,7 @@ var init_logs = __esm({
5701
6518
  case "":
5702
6519
  case "today": {
5703
6520
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
5704
- targetDir = path17.join(sessionsDir, today);
6521
+ targetDir = path18.join(sessionsDir, today);
5705
6522
  const todayExists = await FileUtils.exists(targetDir);
5706
6523
  if (!todayExists) {
5707
6524
  logger.info("\u4ECA\u65E5\u6682\u65E0\u4F1A\u8BDD\u65E5\u5FD7");
@@ -5717,7 +6534,7 @@ var init_logs = __esm({
5717
6534
  break;
5718
6535
  }
5719
6536
  default: {
5720
- targetDir = path17.join(sessionsDir, filter);
6537
+ targetDir = path18.join(sessionsDir, filter);
5721
6538
  const dateExists = await FileUtils.exists(targetDir);
5722
6539
  if (!dateExists) {
5723
6540
  logger.error(`\u672A\u627E\u5230\u65E5\u671F '${filter}' \u7684\u65E5\u5FD7`);
@@ -5741,11 +6558,11 @@ var init_logs = __esm({
5741
6558
  process.exit(0);
5742
6559
  }
5743
6560
  for (let i = 0; i < logs.length; i++) {
5744
- const relPath = path17.relative(sessionsDir, logs[i]);
6561
+ const relPath = path18.relative(sessionsDir, logs[i]);
5745
6562
  logger.step(`${i + 1}) ${relPath}`);
5746
6563
  }
5747
6564
  logger.newLine();
5748
- const answers = await inquirer8.prompt([
6565
+ const answers = await inquirer9.prompt([
5749
6566
  {
5750
6567
  type: "input",
5751
6568
  name: "selection",
@@ -5780,10 +6597,10 @@ var init_logs = __esm({
5780
6597
  });
5781
6598
 
5782
6599
  // src/commands/update.ts
5783
- import { Command as Command13 } from "commander";
5784
- import path18 from "path";
6600
+ import { Command as Command14 } from "commander";
6601
+ import path19 from "path";
5785
6602
  import { execa as execa4 } from "execa";
5786
- import inquirer9 from "inquirer";
6603
+ import inquirer10 from "inquirer";
5787
6604
  import fs4 from "fs-extra";
5788
6605
  async function performUpdate(projectPath, updates) {
5789
6606
  logger.newLine();
@@ -5791,7 +6608,7 @@ async function performUpdate(projectPath, updates) {
5791
6608
  for (const update of updates) {
5792
6609
  const { type, info, updateOptions } = update;
5793
6610
  const targetDir = type === "frontend" ? "frontend" : "backend";
5794
- const targetPath = path18.join(projectPath, targetDir);
6611
+ const targetPath = path19.join(projectPath, targetDir);
5795
6612
  logger.newLine();
5796
6613
  logger.step(`\u66F4\u65B0 ${type === "frontend" ? "\u524D\u7AEF" : "\u540E\u7AEF"}\u6A21\u677F...`);
5797
6614
  if (updateOptions?.tag || updateOptions?.branch) {
@@ -5822,8 +6639,8 @@ async function performUpdate(projectPath, updates) {
5822
6639
  }
5823
6640
  }
5824
6641
  const ref = updateOptions?.tag || updateOptions?.branch || "HEAD";
5825
- const backupDir = path18.join(projectPath, `.backup-${Date.now()}`);
5826
- await fs4.copy(targetPath, path18.join(backupDir, targetDir));
6642
+ const backupDir = path19.join(projectPath, `.backup-${Date.now()}`);
6643
+ await fs4.copy(targetPath, path19.join(backupDir, targetDir));
5827
6644
  logger.info(`\u5DF2\u521B\u5EFA\u5907\u4EFD: ${backupDir}`);
5828
6645
  if (updateOptions?.dryRun) {
5829
6646
  logger.info("[Dry Run] \u5C06\u4F1A\u66F4\u65B0\u5230\u4EE5\u4E0B\u7248\u672C:");
@@ -5833,7 +6650,7 @@ async function performUpdate(projectPath, updates) {
5833
6650
  continue;
5834
6651
  }
5835
6652
  try {
5836
- const tempDir = path18.join(projectPath, `.template-update-${Date.now()}`);
6653
+ const tempDir = path19.join(projectPath, `.template-update-${Date.now()}`);
5837
6654
  await execa4("git", ["clone", "--depth=1", "--branch", ref, info.repository, tempDir], {
5838
6655
  stdio: "pipe"
5839
6656
  });
@@ -5850,7 +6667,7 @@ async function performUpdate(projectPath, updates) {
5850
6667
  const currentFiles = await FileUtils.findFiles("*", targetPath);
5851
6668
  for (const file of currentFiles) {
5852
6669
  if (!keepFiles.includes(file)) {
5853
- const filePath = path18.join(targetPath, file);
6670
+ const filePath = path19.join(targetPath, file);
5854
6671
  try {
5855
6672
  await fs4.remove(filePath);
5856
6673
  } catch {
@@ -5872,7 +6689,7 @@ async function performUpdate(projectPath, updates) {
5872
6689
  logger.error(`\u66F4\u65B0\u5931\u8D25: ${error.message}`);
5873
6690
  logger.info("\u6B63\u5728\u6062\u590D\u5907\u4EFD...");
5874
6691
  await fs4.remove(targetPath);
5875
- await fs4.copy(path18.join(backupDir, targetDir), targetPath);
6692
+ await fs4.copy(path19.join(backupDir, targetDir), targetPath);
5876
6693
  await fs4.remove(backupDir);
5877
6694
  logger.info("\u5DF2\u6062\u590D\u5230\u66F4\u65B0\u524D\u7684\u72B6\u6001");
5878
6695
  }
@@ -5895,7 +6712,7 @@ var init_update = __esm({
5895
6712
  init_template_version();
5896
6713
  init_logger();
5897
6714
  init_utils();
5898
- updateCommand = new Command13("update").description("\u68C0\u67E5\u5E76\u66F4\u65B0\u6A21\u677F\u7248\u672C").option("-f, --frontend", "\u68C0\u67E5\u524D\u7AEF\u6A21\u677F\u66F4\u65B0").option("-b, --backend", "\u68C0\u67E5\u540E\u7AEF\u6A21\u677F\u66F4\u65B0").option("-a, --all", "\u68C0\u67E5\u6240\u6709\u6A21\u677F (\u9ED8\u8BA4)").option("-t, --tag <tag>", "\u66F4\u65B0\u5230\u6307\u5B9A\u6807\u7B7E").option("-B, --branch <branch>", "\u66F4\u65B0\u5230\u6307\u5B9A\u5206\u652F").option("--dry-run", "\u9884\u89C8\u66F4\u65B0\uFF0C\u4E0D\u5B9E\u9645\u6267\u884C").action(async (options) => {
6715
+ updateCommand = new Command14("update").description("\u68C0\u67E5\u5E76\u66F4\u65B0\u6A21\u677F\u7248\u672C").option("-f, --frontend", "\u68C0\u67E5\u524D\u7AEF\u6A21\u677F\u66F4\u65B0").option("-b, --backend", "\u68C0\u67E5\u540E\u7AEF\u6A21\u677F\u66F4\u65B0").option("-a, --all", "\u68C0\u67E5\u6240\u6709\u6A21\u677F (\u9ED8\u8BA4)").option("-t, --tag <tag>", "\u66F4\u65B0\u5230\u6307\u5B9A\u6807\u7B7E").option("-B, --branch <branch>", "\u66F4\u65B0\u5230\u6307\u5B9A\u5206\u652F").option("--dry-run", "\u9884\u89C8\u66F4\u65B0\uFF0C\u4E0D\u5B9E\u9645\u6267\u884C").action(async (options) => {
5899
6716
  try {
5900
6717
  logger.header("\u6A21\u677F\u7248\u672C\u68C0\u67E5");
5901
6718
  logger.newLine();
@@ -5967,7 +6784,7 @@ var init_update = __esm({
5967
6784
  logger.info("Dry run \u6A21\u5F0F\uFF0C\u4E0D\u6267\u884C\u5B9E\u9645\u66F4\u65B0");
5968
6785
  return;
5969
6786
  }
5970
- const answers = await inquirer9.prompt([
6787
+ const answers = await inquirer10.prompt([
5971
6788
  {
5972
6789
  type: "confirm",
5973
6790
  name: "shouldUpdate",
@@ -5992,8 +6809,8 @@ var init_update = __esm({
5992
6809
  });
5993
6810
 
5994
6811
  // src/commands/config.ts
5995
- import { Command as Command14 } from "commander";
5996
- import inquirer10 from "inquirer";
6812
+ import { Command as Command15 } from "commander";
6813
+ import inquirer11 from "inquirer";
5997
6814
  import chalk2 from "chalk";
5998
6815
  var setTokenCommand, showConfigCommand, removeConfigCommand, validateTokenCommand, configCommand;
5999
6816
  var init_config = __esm({
@@ -6003,13 +6820,13 @@ var init_config = __esm({
6003
6820
  init_user_config();
6004
6821
  init_gitlab_api();
6005
6822
  init_logger();
6006
- setTokenCommand = new Command14("set-token").description("\u8BBE\u7F6E GitLab Access Token").option("-t, --token <token>", "Access Token").option("-u, --url <url>", "GitLab Base URL", "https://gitlab.com").action(async (options) => {
6823
+ setTokenCommand = new Command15("set-token").description("\u8BBE\u7F6E GitLab Access Token").option("-t, --token <token>", "Access Token").option("-u, --url <url>", "GitLab Base URL", "https://gitlab.com").action(async (options) => {
6007
6824
  try {
6008
6825
  logger.header("GitLab Access Token \u914D\u7F6E");
6009
6826
  logger.newLine();
6010
6827
  let { token, url } = options;
6011
6828
  if (!token) {
6012
- const answers = await inquirer10.prompt([
6829
+ const answers = await inquirer11.prompt([
6013
6830
  {
6014
6831
  type: "password",
6015
6832
  name: "token",
@@ -6071,7 +6888,7 @@ var init_config = __esm({
6071
6888
  process.exit(1);
6072
6889
  }
6073
6890
  });
6074
- showConfigCommand = new Command14("show").description("\u663E\u793A\u5F53\u524D\u914D\u7F6E").action(async () => {
6891
+ showConfigCommand = new Command15("show").description("\u663E\u793A\u5F53\u524D\u914D\u7F6E").action(async () => {
6075
6892
  try {
6076
6893
  logger.header("GitLab \u914D\u7F6E");
6077
6894
  logger.newLine();
@@ -6110,14 +6927,14 @@ var init_config = __esm({
6110
6927
  process.exit(1);
6111
6928
  }
6112
6929
  });
6113
- removeConfigCommand = new Command14("remove").alias("rm").description("\u5220\u9664 GitLab \u914D\u7F6E").action(async () => {
6930
+ removeConfigCommand = new Command15("remove").alias("rm").description("\u5220\u9664 GitLab \u914D\u7F6E").action(async () => {
6114
6931
  try {
6115
6932
  const hasConfig = await userConfigManager.hasConfig();
6116
6933
  if (!hasConfig) {
6117
6934
  logger.warn("\u672A\u914D\u7F6E GitLab Access Token");
6118
6935
  return;
6119
6936
  }
6120
- const answers = await inquirer10.prompt([
6937
+ const answers = await inquirer11.prompt([
6121
6938
  {
6122
6939
  type: "confirm",
6123
6940
  name: "confirm",
@@ -6139,7 +6956,7 @@ var init_config = __esm({
6139
6956
  process.exit(1);
6140
6957
  }
6141
6958
  });
6142
- validateTokenCommand = new Command14("validate").alias("test").description("\u9A8C\u8BC1\u5F53\u524D Token \u662F\u5426\u6709\u6548").action(async () => {
6959
+ validateTokenCommand = new Command15("validate").alias("test").description("\u9A8C\u8BC1\u5F53\u524D Token \u662F\u5426\u6709\u6548").action(async () => {
6143
6960
  try {
6144
6961
  logger.header("\u9A8C\u8BC1 GitLab Token");
6145
6962
  logger.newLine();
@@ -6169,12 +6986,12 @@ var init_config = __esm({
6169
6986
  process.exit(1);
6170
6987
  }
6171
6988
  });
6172
- configCommand = new Command14("config").description("\u7BA1\u7406 GitLab \u914D\u7F6E").addCommand(setTokenCommand).addCommand(showConfigCommand).addCommand(removeConfigCommand).addCommand(validateTokenCommand);
6989
+ configCommand = new Command15("config").description("\u7BA1\u7406 GitLab \u914D\u7F6E").addCommand(setTokenCommand).addCommand(showConfigCommand).addCommand(removeConfigCommand).addCommand(validateTokenCommand);
6173
6990
  }
6174
6991
  });
6175
6992
 
6176
6993
  // src/commands/diff.ts
6177
- import { Command as Command15 } from "commander";
6994
+ import { Command as Command16 } from "commander";
6178
6995
  import chalk3 from "chalk";
6179
6996
  async function compareTemplate(projectPath, type, localConfig, remoteTag, remoteBranch, gitlabConfig) {
6180
6997
  try {
@@ -6353,7 +7170,7 @@ var init_diff = __esm({
6353
7170
  init_utils();
6354
7171
  init_user_config();
6355
7172
  init_gitlab_api();
6356
- diffCommand = new Command15("diff").description("\u5BF9\u6BD4\u672C\u5730\u4E0E\u8FDC\u7A0B\u6A21\u677F\u5DEE\u5F02").option("-f, --frontend", "\u5BF9\u6BD4\u524D\u7AEF\u6A21\u677F").option("-b, --backend", "\u5BF9\u6BD4\u540E\u7AEF\u6A21\u677F").option("-t, --tag <tag>", "\u6307\u5B9A\u8FDC\u7A0B\u6807\u7B7E").option("-B, --branch <branch>", "\u6307\u5B9A\u8FDC\u7A0B\u5206\u652F").option("-o, --output <format>", "\u8F93\u51FA\u683C\u5F0F (table|json|diff)", "table").action(async (options) => {
7173
+ diffCommand = new Command16("diff").description("\u5BF9\u6BD4\u672C\u5730\u4E0E\u8FDC\u7A0B\u6A21\u677F\u5DEE\u5F02").option("-f, --frontend", "\u5BF9\u6BD4\u524D\u7AEF\u6A21\u677F").option("-b, --backend", "\u5BF9\u6BD4\u540E\u7AEF\u6A21\u677F").option("-t, --tag <tag>", "\u6307\u5B9A\u8FDC\u7A0B\u6807\u7B7E").option("-B, --branch <branch>", "\u6307\u5B9A\u8FDC\u7A0B\u5206\u652F").option("-o, --output <format>", "\u8F93\u51FA\u683C\u5F0F (table|json|diff)", "table").action(async (options) => {
6357
7174
  try {
6358
7175
  logger.header("\u6A21\u677F\u7248\u672C\u5BF9\u6BD4");
6359
7176
  logger.newLine();
@@ -6475,10 +7292,10 @@ var init_diff = __esm({
6475
7292
 
6476
7293
  // src/index.ts
6477
7294
  var index_exports = {};
6478
- import { Command as Command16 } from "commander";
7295
+ import { Command as Command17 } from "commander";
6479
7296
  import chalk4 from "chalk";
6480
7297
  import fs5 from "fs-extra";
6481
- import path19 from "path";
7298
+ import path20 from "path";
6482
7299
  import { fileURLToPath as fileURLToPath2 } from "url";
6483
7300
  function showHelp() {
6484
7301
  console.log("");
@@ -6489,7 +7306,8 @@ function showHelp() {
6489
7306
  console.log(" team-cli split-prd <prd-folder> \u5C06 PRD \u62C6\u5206\u6210\u591A\u4E2A specs");
6490
7307
  console.log(" team-cli breakdown [spec-file] \u5C06 spec \u62C6\u5206\u4E3A milestones \u548C todos");
6491
7308
  console.log(" team-cli dev \u5F00\u53D1\u6A21\u5F0F\uFF0C\u6267\u884C\u5177\u4F53\u4EFB\u52A1");
6492
- console.log(" team-cli add-feature <name> \u6DFB\u52A0\u65B0\u529F\u80FD");
7309
+ console.log(" team-cli accept [spec-file] \u9A8C\u6536\u529F\u80FD\uFF0C\u8D70\u67E5\u6240\u6709\u9700\u6C42");
7310
+ console.log(" team-cli add-feature <name> \u6DFB\u52A0\u65B0\u529F\u80FD");
6493
7311
  console.log(" team-cli bugfix \u521B\u5EFA Bugfix \u8BB0\u5F55");
6494
7312
  console.log(" team-cli hotfix \u521B\u5EFA Hotfix");
6495
7313
  console.log(" team-cli detect-deps [spec] \u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB");
@@ -6514,6 +7332,7 @@ function showHelp() {
6514
7332
  console.log(" 1. PRD \u2192 specs (split-prd)");
6515
7333
  console.log(" 2. spec \u2192 milestones + todos (breakdown)");
6516
7334
  console.log(" 3. \u9009\u62E9 milestone/todo \u2192 \u5B9E\u73B0 (dev)");
7335
+ console.log(" 4. \u9A8C\u6536 (accept) \u2192 \u9A8C\u8BC1\u8054\u8C03\u662F\u5426\u5B8C\u6210");
6517
7336
  console.log("");
6518
7337
  console.log(chalk4.bold("\u8FED\u4EE3\u6D41\u7A0B:"));
6519
7338
  console.log(" team-cli add-feature <name> # \u6DFB\u52A0\u65B0\u529F\u80FD");
@@ -6547,6 +7366,7 @@ var init_index = __esm({
6547
7366
  init_split_prd();
6548
7367
  init_bugfix();
6549
7368
  init_bugfix();
7369
+ init_accept();
6550
7370
  init_lint();
6551
7371
  init_status();
6552
7372
  init_detect_deps();
@@ -6556,9 +7376,9 @@ var init_index = __esm({
6556
7376
  init_update();
6557
7377
  init_config();
6558
7378
  init_diff();
6559
- __dirname2 = path19.dirname(fileURLToPath2(import.meta.url));
6560
- pkg = fs5.readJsonSync(path19.join(__dirname2, "../package.json"));
6561
- program = new Command16();
7379
+ __dirname2 = path20.dirname(fileURLToPath2(import.meta.url));
7380
+ pkg = fs5.readJsonSync(path20.join(__dirname2, "../package.json"));
7381
+ program = new Command17();
6562
7382
  program.name("team-cli").description("AI-Native \u56E2\u961F\u7814\u53D1\u811A\u624B\u67B6").version(pkg.version);
6563
7383
  program.option("-v, --verbose", "\u8BE6\u7EC6\u8F93\u51FA\u6A21\u5F0F").option("--debug", "\u8C03\u8BD5\u6A21\u5F0F");
6564
7384
  program.addCommand(initCommand);
@@ -6568,6 +7388,7 @@ var init_index = __esm({
6568
7388
  program.addCommand(addFeatureCommand);
6569
7389
  program.addCommand(bugfixCommand);
6570
7390
  program.addCommand(hotfixCommand);
7391
+ program.addCommand(acceptCommand);
6571
7392
  program.addCommand(lintCommand);
6572
7393
  program.addCommand(statusCommand);
6573
7394
  program.addCommand(detectDepsCommand);