@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 +15 -6
- package/dist/cli/index.js +276 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +274 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +274 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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` 架构 -
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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` -
|
|
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` - 新增 `
|
|
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 === "
|
|
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/
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
1961
|
-
|
|
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.
|
|
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}
|
|
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 (
|
|
2301
|
+
if (interactionAnswer) {
|
|
2091
2302
|
scenario.scenarios.push({
|
|
2092
|
-
name: `\
|
|
2093
|
-
given: [`\u7528\u6237\u8FDB\u5165\
|
|
2094
|
-
when: [`\u7528\u6237\
|
|
2095
|
-
then: [`\u7CFB\u7EDF\u5E94\
|
|
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,
|