@nick848/sf-cli 1.0.10 → 1.0.11

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/CHANGELOG.md CHANGED
@@ -9,19 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  **重大重构 - 工作流系统重写**
11
11
 
12
- - ✨ 全新的 `WorkflowSession` 架构 - 7 阶段自动流转
13
- - 🔄 自动执行流程:context analysis → bdd → spec → tdd → develop → review
14
- - ⏸️ 唯一暂停点:spec 阶段等待 y/n 确认
15
- - 🎯 简化交互:y/n/c 三键操作(确认/重新生成/取消)
12
+ - ✨ 全新的 `WorkflowSession` 架构 - 8 阶段自动流转
13
+ - 🆕 **需求澄清阶段** - 需求不明确时主动引导开发者补充信息
14
+ - 📊 需求清晰度评估 - 自动计算需求清晰度分数
15
+ - 智能问题生成 - 根据需求内容自动生成澄清问题
16
+ - 🔄 自动执行流程:context → clarify → analysis → bdd → spec → tdd → develop → review
17
+ - ⏸️ 两个暂停点:clarify(需求澄清)、spec(规格确认)
18
+
19
+ **需求澄清功能**
20
+
21
+ - 自动检测需求清晰度(长度、动作、UI、数据、交互、边界)
22
+ - 生成针对性澄清问题(范围、界面、数据、交互、边界条件)
23
+ - 支持逐个回答或 `done` 跳过
24
+ - 回答后自动更新精炼需求
16
25
 
17
26
  **架构改进**
18
27
 
19
- - 📦 `new.ts` - 完全重写,移除旧 WorkflowEngine 依赖
28
+ - 📦 `new.ts` - 完全重写,新增 ClarificationQuestion 接口
20
29
  - 📦 `natural.ts` - 简化为工作流输入处理
21
30
  - 📦 `executor.ts` - 简化权限控制逻辑
22
31
  - 📦 `repl.ts` - 使用 `getActiveSession()` 获取状态
23
32
  - 📦 `status.ts` - 支持新 WorkflowPhase 类型显示
24
- - 📦 `types/index.ts` - 新增 `WorkflowPhase` 类型定义
33
+ - 📦 `types/index.ts` - 新增 `clarify` 阶段
25
34
 
26
35
  **修复问题**
27
36
 
package/dist/cli/index.js CHANGED
@@ -1794,14 +1794,17 @@ async function handleNew(args, ctx) {
1794
1794
  const requirement = args.join(" ").trim();
1795
1795
  if (!requirement) {
1796
1796
  return {
1797
- output: chalk9__default.default.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9__default.default.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>")
1797
+ output: chalk9__default.default.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9__default.default.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray("\n\n\u793A\u4F8B:") + chalk9__default.default.gray("\n /new \u5B9E\u73B0\u7528\u6237\u767B\u5F55\u529F\u80FD") + chalk9__default.default.gray("\n /new \u6DFB\u52A0\u6570\u636E\u5BFC\u51FA\u4E3AExcel\u7684\u529F\u80FD")
1798
1798
  };
1799
1799
  }
1800
1800
  activeSession = {
1801
1801
  id: generateSessionId(),
1802
1802
  requirement,
1803
+ refinedRequirement: requirement,
1803
1804
  phase: "context",
1804
1805
  context: null,
1806
+ clarityScore: 0,
1807
+ clarificationQuestions: [],
1805
1808
  complexity: 0,
1806
1809
  bddScenarios: [],
1807
1810
  specItems: [],
@@ -1819,10 +1822,13 @@ function handleActiveSession(ctx) {
1819
1822
  const lines = [];
1820
1823
  lines.push(chalk9__default.default.cyan("\u{1F4CB} \u5F53\u524D\u5DE5\u4F5C\u6D41\u72B6\u6001"));
1821
1824
  lines.push("");
1822
- lines.push(chalk9__default.default.white(`\u9700\u6C42: ${activeSession.requirement}`));
1825
+ lines.push(chalk9__default.default.white(`\u9700\u6C42: ${activeSession.requirement.slice(0, 60)}${activeSession.requirement.length > 60 ? "..." : ""}`));
1823
1826
  lines.push(chalk9__default.default.gray(`\u9636\u6BB5: ${getPhaseLabel(activeSession.phase)}`));
1824
1827
  lines.push("");
1825
- if (activeSession.phase === "spec") {
1828
+ if (activeSession.phase === "clarify") {
1829
+ lines.push(chalk9__default.default.yellow("\u23F8\uFE0F \u7B49\u5F85\u9700\u6C42\u6F84\u6E05"));
1830
+ lines.push(chalk9__default.default.gray('\u8BF7\u56DE\u7B54\u4E0A\u8FF0\u95EE\u9898\uFF0C\u6216\u8F93\u5165 "done" \u8868\u793A\u56DE\u7B54\u5B8C\u6210'));
1831
+ } else if (activeSession.phase === "spec") {
1826
1832
  lines.push(chalk9__default.default.yellow("\u23F8\uFE0F \u7B49\u5F85\u89C4\u683C\u786E\u8BA4"));
1827
1833
  lines.push("");
1828
1834
  lines.push(chalk9__default.default.green(" y - \u786E\u8BA4\u89C4\u683C\uFF0C\u7EE7\u7EED\u5DE5\u4F5C\u6D41"));
@@ -1841,7 +1847,7 @@ async function executeWorkflow(ctx) {
1841
1847
  const lines = [];
1842
1848
  try {
1843
1849
  if (activeSession.phase === "context") {
1844
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/7: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
1850
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/8: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
1845
1851
  lines.push("");
1846
1852
  activeSession.context = await readProjectContext(ctx.options.workingDirectory);
1847
1853
  lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${activeSession.context.name}`));
@@ -1851,13 +1857,46 @@ async function executeWorkflow(ctx) {
1851
1857
  if (activeSession.context.devStandards) {
1852
1858
  lines.push(chalk9__default.default.green(" \u2713 \u5DF2\u8BFB\u53D6\u5F00\u53D1\u89C4\u8303"));
1853
1859
  }
1860
+ activeSession.phase = "clarify";
1861
+ }
1862
+ if (activeSession.phase === "clarify") {
1863
+ lines.push("");
1864
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/8: \u9700\u6C42\u6F84\u6E05 \u2501\u2501\u2501"));
1865
+ lines.push("");
1866
+ const clarityResult = analyzeRequirementClarity(
1867
+ activeSession.requirement,
1868
+ activeSession.context
1869
+ );
1870
+ activeSession.clarityScore = clarityResult.score;
1871
+ activeSession.clarificationQuestions = clarityResult.questions;
1872
+ lines.push(chalk9__default.default.gray(` \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(clarityResult.score * 100)}%`));
1873
+ lines.push("");
1874
+ if (clarityResult.score < CLARITY_THRESHOLD && clarityResult.questions.length > 0) {
1875
+ lines.push(chalk9__default.default.yellow(" \u9700\u6C42\u4E0D\u591F\u660E\u786E\uFF0C\u8BF7\u8865\u5145\u4EE5\u4E0B\u4FE1\u606F\uFF1A"));
1876
+ lines.push("");
1877
+ const unansweredQuestions = clarityResult.questions.filter((q) => !q.answered);
1878
+ for (let i = 0; i < Math.min(unansweredQuestions.length, 3); i++) {
1879
+ const q = unansweredQuestions[i];
1880
+ lines.push(chalk9__default.default.white(` ${i + 1}. ${q.question}`));
1881
+ }
1882
+ if (unansweredQuestions.length > 3) {
1883
+ lines.push(chalk9__default.default.gray(` ... \u8FD8\u6709 ${unansweredQuestions.length - 3} \u4E2A\u95EE\u9898`));
1884
+ }
1885
+ lines.push("");
1886
+ lines.push(chalk9__default.default.gray(' \u8BF7\u8F93\u5165\u56DE\u7B54\uFF0C\u6216\u8F93\u5165 "done" \u8DF3\u8FC7\u6F84\u6E05'));
1887
+ return { output: lines.join("\n") };
1888
+ }
1889
+ lines.push(chalk9__default.default.green(" \u2713 \u9700\u6C42\u6E05\u6670\uFF0C\u7EE7\u7EED\u4E0B\u4E00\u6B65"));
1854
1890
  activeSession.phase = "analysis";
1855
1891
  }
1856
1892
  if (activeSession.phase === "analysis") {
1857
1893
  lines.push("");
1858
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/7: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
1894
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 3/8: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
1859
1895
  lines.push("");
1860
- activeSession.complexity = analyzeComplexity(activeSession.requirement, activeSession.context);
1896
+ activeSession.complexity = analyzeComplexity(
1897
+ activeSession.refinedRequirement,
1898
+ activeSession.context
1899
+ );
1861
1900
  const complexityBar = generateComplexityBar(activeSession.complexity);
1862
1901
  lines.push(chalk9__default.default.gray(` \u590D\u6742\u5EA6: ${complexityBar} ${activeSession.complexity}/10`));
1863
1902
  if (activeSession.complexity >= COMPLEXITY_THRESHOLD) {
@@ -1869,9 +1908,13 @@ async function executeWorkflow(ctx) {
1869
1908
  }
1870
1909
  if (activeSession.phase === "bdd") {
1871
1910
  lines.push("");
1872
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 3/7: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
1911
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 4/8: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
1873
1912
  lines.push("");
1874
- activeSession.bddScenarios = generateBDDScenarios(activeSession.requirement, activeSession.context);
1913
+ activeSession.bddScenarios = generateBDDScenarios(
1914
+ activeSession.refinedRequirement,
1915
+ activeSession.context,
1916
+ activeSession.clarificationQuestions
1917
+ );
1875
1918
  for (const scenario of activeSession.bddScenarios) {
1876
1919
  lines.push(chalk9__default.default.white(` Feature: ${scenario.feature}`));
1877
1920
  for (const s of scenario.scenarios.slice(0, 3)) {
@@ -1885,9 +1928,14 @@ async function executeWorkflow(ctx) {
1885
1928
  }
1886
1929
  if (activeSession.phase === "spec") {
1887
1930
  lines.push("");
1888
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 4/7: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
1931
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/8: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
1889
1932
  lines.push("");
1890
- activeSession.specItems = generateSpecItems(activeSession.requirement, activeSession.context, activeSession.bddScenarios);
1933
+ activeSession.specItems = generateSpecItems(
1934
+ activeSession.refinedRequirement,
1935
+ activeSession.context,
1936
+ activeSession.bddScenarios,
1937
+ activeSession.clarificationQuestions
1938
+ );
1891
1939
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
1892
1940
  lines.push(chalk9__default.default.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
1893
1941
  lines.push(chalk9__default.default.gray(` \u8DEF\u5F84: ${specPath}`));
@@ -1910,7 +1958,7 @@ async function executeWorkflow(ctx) {
1910
1958
  }
1911
1959
  if (activeSession.phase === "tdd") {
1912
1960
  lines.push("");
1913
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/7: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
1961
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/8: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
1914
1962
  lines.push("");
1915
1963
  activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
1916
1964
  lines.push(chalk9__default.default.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
@@ -1921,7 +1969,7 @@ async function executeWorkflow(ctx) {
1921
1969
  }
1922
1970
  if (activeSession.phase === "develop") {
1923
1971
  lines.push("");
1924
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/7: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
1972
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/8: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
1925
1973
  lines.push("");
1926
1974
  lines.push(chalk9__default.default.yellow(" \u{1F4DD} \u5F00\u53D1\u9636\u6BB5"));
1927
1975
  lines.push(chalk9__default.default.gray(" \u8BF7\u8C03\u7528 $frontend-dev \u6267\u884C\u5F00\u53D1\u4EFB\u52A1"));
@@ -1930,7 +1978,7 @@ async function executeWorkflow(ctx) {
1930
1978
  }
1931
1979
  if (activeSession.phase === "review") {
1932
1980
  lines.push("");
1933
- lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/7: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
1981
+ lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 8/8: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
1934
1982
  lines.push("");
1935
1983
  lines.push(chalk9__default.default.yellow(" \u{1F50D} \u4EE3\u7801\u5BA1\u6838\u9636\u6BB5"));
1936
1984
  lines.push(chalk9__default.default.gray(" \u8BF7\u8C03\u7528 $code-reviewer \u6267\u884C\u4EE3\u7801\u5BA1\u6838"));
@@ -1951,14 +1999,58 @@ async function handleWorkflowInput(input, ctx) {
1951
1999
  output: chalk9__default.default.yellow("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u53D6\u6D88")
1952
2000
  };
1953
2001
  }
2002
+ if (activeSession.phase === "clarify") {
2003
+ if (trimmed === "done" || trimmed === "\u5B8C\u6210" || trimmed === "\u8DF3\u8FC7" || trimmed === "skip") {
2004
+ activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
2005
+ activeSession.phase = "analysis";
2006
+ return executeWorkflow(ctx);
2007
+ }
2008
+ activeSession.clarificationQuestions.filter((q) => q.answered).length;
2009
+ const unansweredQuestions = activeSession.clarificationQuestions.filter((q) => !q.answered);
2010
+ if (unansweredQuestions.length > 0) {
2011
+ const question = unansweredQuestions[0];
2012
+ question.answer = input.trim();
2013
+ question.answered = true;
2014
+ activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
2015
+ const remaining = activeSession.clarificationQuestions.filter((q) => !q.answered);
2016
+ if (remaining.length > 0) {
2017
+ activeSession.clarityScore = calculateClarityScore(activeSession.clarificationQuestions);
2018
+ const lines = [];
2019
+ lines.push(chalk9__default.default.green(" \u2713 \u5DF2\u8BB0\u5F55"));
2020
+ lines.push("");
2021
+ lines.push(chalk9__default.default.yellow(" \u7EE7\u7EED\u56DE\u7B54\uFF1A"));
2022
+ for (let i = 0; i < Math.min(remaining.length, 3); i++) {
2023
+ const q = remaining[i];
2024
+ lines.push(chalk9__default.default.white(` ${i + 1}. ${q.question}`));
2025
+ }
2026
+ lines.push("");
2027
+ lines.push(chalk9__default.default.gray(' \u8F93\u5165\u56DE\u7B54\uFF0C\u6216 "done" \u8DF3\u8FC7'));
2028
+ return { output: lines.join("\n") };
2029
+ }
2030
+ activeSession.clarityScore = 1;
2031
+ activeSession.phase = "analysis";
2032
+ return executeWorkflow(ctx);
2033
+ }
2034
+ activeSession.phase = "analysis";
2035
+ return executeWorkflow(ctx);
2036
+ }
1954
2037
  if (activeSession.phase === "spec") {
1955
2038
  if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
1956
2039
  activeSession.phase = "tdd";
1957
2040
  return executeWorkflow(ctx);
1958
2041
  }
1959
2042
  if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
1960
- activeSession.bddScenarios = generateBDDScenarios(activeSession.requirement, activeSession.context);
1961
- activeSession.specItems = generateSpecItems(activeSession.requirement, activeSession.context, activeSession.bddScenarios);
2043
+ activeSession.bddScenarios = generateBDDScenarios(
2044
+ activeSession.refinedRequirement,
2045
+ activeSession.context,
2046
+ activeSession.clarificationQuestions
2047
+ );
2048
+ activeSession.specItems = generateSpecItems(
2049
+ activeSession.refinedRequirement,
2050
+ activeSession.context,
2051
+ activeSession.bddScenarios,
2052
+ activeSession.clarificationQuestions
2053
+ );
1962
2054
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
1963
2055
  return {
1964
2056
  output: chalk9__default.default.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9__default.default.gray(`
@@ -1975,11 +2067,11 @@ async function handleWorkflowInput(input, ctx) {
1975
2067
  if (activeSession.phase === "review") {
1976
2068
  if (trimmed === "review" || trimmed === "\u5BA1\u6838" || trimmed === "pass" || trimmed === "\u901A\u8FC7") {
1977
2069
  await archiveWorkflow(ctx.options.workingDirectory);
1978
- const summary = activeSession.requirement;
2070
+ const summary = activeSession.refinedRequirement;
1979
2071
  activeSession = null;
1980
2072
  return {
1981
2073
  output: chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5B8C\u6210") + chalk9__default.default.gray(`
1982
- \u9700\u6C42: ${summary}`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
2074
+ \u9700\u6C42: ${summary.slice(0, 60)}...`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
1983
2075
  };
1984
2076
  }
1985
2077
  if (trimmed === "fail" || trimmed === "\u5931\u8D25" || trimmed === "reject" || trimmed === "\u62D2\u7EDD") {
@@ -1991,6 +2083,122 @@ async function handleWorkflowInput(input, ctx) {
1991
2083
  }
1992
2084
  return null;
1993
2085
  }
2086
+ function analyzeRequirementClarity(requirement, context) {
2087
+ const questions = [];
2088
+ let score = 0.5;
2089
+ if (requirement.length < 10) {
2090
+ score -= 0.2;
2091
+ questions.push({
2092
+ id: "q-length",
2093
+ question: "\u9700\u6C42\u63CF\u8FF0\u8F83\u77ED\uFF0C\u80FD\u5426\u8BE6\u7EC6\u8BF4\u660E\u5177\u4F53\u8981\u5B9E\u73B0\u4EC0\u4E48\u529F\u80FD\uFF1F",
2094
+ category: "scope",
2095
+ answered: false
2096
+ });
2097
+ } else if (requirement.length >= 50) {
2098
+ score += 0.1;
2099
+ }
2100
+ const actionKeywords = ["\u5B9E\u73B0", "\u6DFB\u52A0", "\u4FEE\u6539", "\u5220\u9664", "\u4F18\u5316", "\u4FEE\u590D", "\u91CD\u6784", "\u5F00\u53D1", "\u521B\u5EFA", "\u8BBE\u8BA1"];
2101
+ const hasAction = actionKeywords.some((kw) => requirement.includes(kw));
2102
+ if (!hasAction) {
2103
+ score -= 0.15;
2104
+ questions.push({
2105
+ id: "q-action",
2106
+ question: "\u8FD9\u662F\u4E00\u4E2A\u65B0\u529F\u80FD\u3001\u4FEE\u6539\u8FD8\u662F\u4FEE\u590D\uFF1F\u8BF7\u8BF4\u660E\u5177\u4F53\u8981\u505A\u4EC0\u4E48\u3002",
2107
+ category: "scope",
2108
+ answered: false
2109
+ });
2110
+ } else {
2111
+ score += 0.1;
2112
+ }
2113
+ if (requirement.match(/界面|页面|组件|按钮|表单|弹窗|布局|样式|UI/)) {
2114
+ score += 0.1;
2115
+ if (!requirement.match(/在.*页面|在.*位置|显示在|位于/)) {
2116
+ questions.push({
2117
+ id: "q-ui-position",
2118
+ question: "\u8FD9\u4E2A\u529F\u80FD\u5E94\u8BE5\u653E\u5728\u54EA\u4E2A\u9875\u9762\u6216\u4F4D\u7F6E\uFF1F",
2119
+ category: "ui",
2120
+ answered: false
2121
+ });
2122
+ }
2123
+ } else {
2124
+ questions.push({
2125
+ id: "q-ui-need",
2126
+ question: "\u8FD9\u4E2A\u529F\u80FD\u9700\u8981\u7528\u6237\u754C\u9762\u5417\uFF1F\u5982\u679C\u9700\u8981\uFF0C\u5927\u6982\u957F\u4EC0\u4E48\u6837\uFF1F",
2127
+ category: "ui",
2128
+ answered: false
2129
+ });
2130
+ }
2131
+ if (requirement.match(/数据|存储|保存|读取|API|接口|数据库|缓存/)) {
2132
+ score += 0.1;
2133
+ if (!requirement.match(/从.*获取|调用.*接口|读取.*数据|来源/)) {
2134
+ questions.push({
2135
+ id: "q-data-source",
2136
+ question: "\u6570\u636E\u4ECE\u54EA\u91CC\u6765\uFF1F\u662F\u8C03\u7528API\u3001\u672C\u5730\u5B58\u50A8\u8FD8\u662F\u5176\u4ED6\u6765\u6E90\uFF1F",
2137
+ category: "data",
2138
+ answered: false
2139
+ });
2140
+ }
2141
+ }
2142
+ if (requirement.match(/点击|输入|选择|拖动|滑动|交互|操作/)) {
2143
+ score += 0.1;
2144
+ } else {
2145
+ if (hasAction && requirement.match(/功能|特性|模块/)) {
2146
+ questions.push({
2147
+ id: "q-interaction",
2148
+ question: "\u7528\u6237\u5982\u4F55\u64CD\u4F5C\u8FD9\u4E2A\u529F\u80FD\uFF1F\u6709\u4EC0\u4E48\u4EA4\u4E92\u6D41\u7A0B\uFF1F",
2149
+ category: "interaction",
2150
+ answered: false
2151
+ });
2152
+ }
2153
+ }
2154
+ if (requirement.match(/异常|错误|失败|边界|特殊情况|空值|验证/)) {
2155
+ score += 0.15;
2156
+ } else {
2157
+ if (requirement.match(/功能|输入|表单|数据/)) {
2158
+ questions.push({
2159
+ id: "q-edge",
2160
+ question: "\u6709\u4EC0\u4E48\u7279\u6B8A\u60C5\u51B5\u6216\u8FB9\u754C\u6761\u4EF6\u9700\u8981\u5904\u7406\uFF1F\u6BD4\u5982\u8F93\u5165\u4E3A\u7A7A\u3001\u6570\u636E\u52A0\u8F7D\u5931\u8D25\u7B49\u3002",
2161
+ category: "edge",
2162
+ answered: false
2163
+ });
2164
+ }
2165
+ }
2166
+ if (requirement.match(/https?:\/\/|参考|参照|类似/)) {
2167
+ score += 0.15;
2168
+ }
2169
+ if (context.framework) {
2170
+ score += 0.05;
2171
+ }
2172
+ const limitedQuestions = questions.slice(0, 5);
2173
+ score = Math.max(0, Math.min(1, score));
2174
+ return { score, questions: limitedQuestions };
2175
+ }
2176
+ function calculateClarityScore(questions) {
2177
+ const answered = questions.filter((q) => q.answered).length;
2178
+ if (questions.length === 0) return 1;
2179
+ return 0.5 + answered / questions.length * 0.5;
2180
+ }
2181
+ function buildRefinedRequirement(session) {
2182
+ const parts = [session.requirement];
2183
+ for (const q of session.clarificationQuestions) {
2184
+ if (q.answered && q.answer) {
2185
+ parts.push(`
2186
+ \u3010${getCategoryLabel(q.category)}\u3011${q.answer}`);
2187
+ }
2188
+ }
2189
+ return parts.join("");
2190
+ }
2191
+ function getCategoryLabel(category) {
2192
+ const labels = {
2193
+ scope: "\u8303\u56F4",
2194
+ ui: "\u754C\u9762",
2195
+ data: "\u6570\u636E",
2196
+ interaction: "\u4EA4\u4E92",
2197
+ edge: "\u8FB9\u754C",
2198
+ tech: "\u6280\u672F"
2199
+ };
2200
+ return labels[category] || category;
2201
+ }
1994
2202
  async function readProjectContext(workingDir) {
1995
2203
  const context = {
1996
2204
  name: path7__namespace.basename(workingDir),
@@ -2072,8 +2280,11 @@ function analyzeComplexity(requirement, context) {
2072
2280
  if (!context.framework) score += 0.5;
2073
2281
  return Math.max(1, Math.min(10, Math.round(score)));
2074
2282
  }
2075
- function generateBDDScenarios(requirement, context) {
2283
+ function generateBDDScenarios(requirement, context, questions) {
2076
2284
  const scenarios = [];
2285
+ questions.find((q) => q.category === "ui" && q.answered)?.answer;
2286
+ const interactionAnswer = questions.find((q) => q.category === "interaction" && q.answered)?.answer;
2287
+ const edgeAnswer = questions.find((q) => q.category === "edge" && q.answered)?.answer;
2077
2288
  const features = extractFeatures(requirement);
2078
2289
  for (const feature of features) {
2079
2290
  const scenario = {
@@ -2087,12 +2298,20 @@ function generateBDDScenarios(requirement, context) {
2087
2298
  when: [`\u7528\u6237\u6267\u884C "${feature.title}" \u64CD\u4F5C`],
2088
2299
  then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5E76\u8FD4\u56DE\u9884\u671F\u7ED3\u679C`]
2089
2300
  });
2090
- if (feature.hasInput) {
2301
+ if (interactionAnswer) {
2091
2302
  scenario.scenarios.push({
2092
- name: `\u8FB9\u754C\u60C5\u51B5: \u8F93\u5165\u9A8C\u8BC1`,
2093
- given: [`\u7528\u6237\u8FDB\u5165\u8F93\u5165\u754C\u9762`],
2094
- when: [`\u7528\u6237\u8F93\u5165\u8FB9\u754C\u503C\u6216\u7A7A\u503C`],
2095
- then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u8FB9\u754C\u60C5\u51B5`]
2303
+ name: `\u4EA4\u4E92\u6D41\u7A0B: \u7528\u6237\u64CD\u4F5C`,
2304
+ given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
2305
+ when: [`\u7528\u6237\u6309\u7167\u4EE5\u4E0B\u6D41\u7A0B\u64CD\u4F5C: ${interactionAnswer}`],
2306
+ then: [`\u7CFB\u7EDF\u54CD\u5E94\u5E76\u5B8C\u6210\u529F\u80FD`]
2307
+ });
2308
+ }
2309
+ if (feature.hasInput || edgeAnswer) {
2310
+ scenario.scenarios.push({
2311
+ name: `\u8FB9\u754C\u60C5\u51B5: \u5F02\u5E38\u5904\u7406`,
2312
+ given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
2313
+ when: [`\u53D1\u751F\u5F02\u5E38\u60C5\u51B5${edgeAnswer ? `: ${edgeAnswer}` : ""}`],
2314
+ then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5F02\u5E38\u5E76\u7ED9\u51FA\u63D0\u793A`]
2096
2315
  });
2097
2316
  }
2098
2317
  scenarios.push(scenario);
@@ -2139,7 +2358,7 @@ function extractFeatures(requirement) {
2139
2358
  }
2140
2359
  return features;
2141
2360
  }
2142
- function generateSpecItems(requirement, context, bddScenarios) {
2361
+ function generateSpecItems(requirement, context, bddScenarios, questions) {
2143
2362
  const items = [];
2144
2363
  let id = 1;
2145
2364
  for (const scenario of bddScenarios) {
@@ -2176,11 +2395,33 @@ function formatSpecFile(session) {
2176
2395
  lines.push(`# \u9700\u6C42\u89C4\u683C: ${session.requirement.slice(0, 50)}`);
2177
2396
  lines.push("");
2178
2397
  lines.push(`> \u53D8\u66F4ID: ${session.id}`);
2398
+ lines.push(`> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(session.clarityScore * 100)}%`);
2179
2399
  lines.push(`> \u590D\u6742\u5EA6: ${session.complexity}/10`);
2180
2400
  lines.push(`> \u751F\u6210\u65F6\u95F4: ${session.createdAt.toISOString()}`);
2181
2401
  lines.push("");
2182
2402
  lines.push("---");
2183
2403
  lines.push("");
2404
+ if (session.refinedRequirement !== session.requirement) {
2405
+ lines.push("## \u9700\u6C42\u8BE6\u60C5");
2406
+ lines.push("");
2407
+ lines.push(session.refinedRequirement);
2408
+ lines.push("");
2409
+ lines.push("---");
2410
+ lines.push("");
2411
+ }
2412
+ if (session.clarificationQuestions.some((q) => q.answered)) {
2413
+ lines.push("## \u9700\u6C42\u6F84\u6E05");
2414
+ lines.push("");
2415
+ for (const q of session.clarificationQuestions) {
2416
+ if (q.answered) {
2417
+ lines.push(`**Q: ${q.question}**`);
2418
+ lines.push(`A: ${q.answer}`);
2419
+ lines.push("");
2420
+ }
2421
+ }
2422
+ lines.push("---");
2423
+ lines.push("");
2424
+ }
2184
2425
  lines.push("## BDD \u573A\u666F");
2185
2426
  lines.push("");
2186
2427
  for (const scenario of session.bddScenarios) {
@@ -2244,11 +2485,17 @@ async function archiveWorkflow(workingDir) {
2244
2485
  const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
2245
2486
 
2246
2487
  > \u5F52\u6863\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}
2488
+ > \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(activeSession.clarityScore * 100)}%
2247
2489
  > \u590D\u6742\u5EA6: ${activeSession.complexity}/10
2248
2490
 
2491
+ ## \u9700\u6C42\u8BE6\u60C5
2492
+
2493
+ ${activeSession.refinedRequirement}
2494
+
2249
2495
  ## \u5B8C\u6210\u60C5\u51B5
2250
2496
 
2251
2497
  - [x] \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6
2498
+ - [x] \u9700\u6C42\u6F84\u6E05
2252
2499
  - [x] \u590D\u6742\u5EA6\u8BC4\u4F30
2253
2500
  - [x] BDD \u573A\u666F\u62C6\u89E3
2254
2501
  - [x] OpenSpec \u89C4\u683C
@@ -2275,6 +2522,7 @@ function generateComplexityBar(score) {
2275
2522
  function getPhaseLabel(phase) {
2276
2523
  const labels = {
2277
2524
  context: "\u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6",
2525
+ clarify: "\u9700\u6C42\u6F84\u6E05",
2278
2526
  analysis: "\u590D\u6742\u5EA6\u8BC4\u4F30",
2279
2527
  bdd: "BDD \u573A\u666F\u62C6\u89E3",
2280
2528
  spec: "OpenSpec \u89C4\u683C",
@@ -2290,12 +2538,13 @@ function getActiveSession() {
2290
2538
  function clearActiveSession() {
2291
2539
  activeSession = null;
2292
2540
  }
2293
- var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, activeSession, new_default;
2541
+ var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
2294
2542
  var init_new = __esm({
2295
2543
  "src/commands/new.ts"() {
2296
2544
  init_cjs_shims();
2297
2545
  MAX_FILE_SIZE2 = 1024 * 1024;
2298
2546
  COMPLEXITY_THRESHOLD = 6;
2547
+ CLARITY_THRESHOLD = 0.6;
2299
2548
  activeSession = null;
2300
2549
  new_default = handleNew;
2301
2550
  }
@@ -6879,6 +7128,7 @@ var STEP_DISPLAY_NAMES = {
6879
7128
  "apply": "\u5BA1\u67E5",
6880
7129
  "archive": "\u5F52\u6863",
6881
7130
  "context": "\u4E0A\u4E0B\u6587",
7131
+ "clarify": "\u6F84\u6E05",
6882
7132
  "analysis": "\u5206\u6790",
6883
7133
  "bdd": "BDD",
6884
7134
  "spec": "\u89C4\u683C",
@@ -6894,6 +7144,7 @@ var STEP_COLORS = {
6894
7144
  "apply": chalk9__default.default.yellow,
6895
7145
  "archive": chalk9__default.default.gray,
6896
7146
  "context": chalk9__default.default.magenta,
7147
+ "clarify": chalk9__default.default.yellow,
6897
7148
  "analysis": chalk9__default.default.blue,
6898
7149
  "bdd": chalk9__default.default.cyan,
6899
7150
  "spec": chalk9__default.default.green,