@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/dist/index.mjs
CHANGED
|
@@ -48,14 +48,17 @@ async function handleNew(args, ctx) {
|
|
|
48
48
|
const requirement = args.join(" ").trim();
|
|
49
49
|
if (!requirement) {
|
|
50
50
|
return {
|
|
51
|
-
output: chalk9.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>")
|
|
51
|
+
output: chalk9.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>") + chalk9.gray("\n\n\u793A\u4F8B:") + chalk9.gray("\n /new \u5B9E\u73B0\u7528\u6237\u767B\u5F55\u529F\u80FD") + chalk9.gray("\n /new \u6DFB\u52A0\u6570\u636E\u5BFC\u51FA\u4E3AExcel\u7684\u529F\u80FD")
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
activeSession = {
|
|
55
55
|
id: generateSessionId(),
|
|
56
56
|
requirement,
|
|
57
|
+
refinedRequirement: requirement,
|
|
57
58
|
phase: "context",
|
|
58
59
|
context: null,
|
|
60
|
+
clarityScore: 0,
|
|
61
|
+
clarificationQuestions: [],
|
|
59
62
|
complexity: 0,
|
|
60
63
|
bddScenarios: [],
|
|
61
64
|
specItems: [],
|
|
@@ -73,10 +76,13 @@ function handleActiveSession(ctx) {
|
|
|
73
76
|
const lines = [];
|
|
74
77
|
lines.push(chalk9.cyan("\u{1F4CB} \u5F53\u524D\u5DE5\u4F5C\u6D41\u72B6\u6001"));
|
|
75
78
|
lines.push("");
|
|
76
|
-
lines.push(chalk9.white(`\u9700\u6C42: ${activeSession.requirement}`));
|
|
79
|
+
lines.push(chalk9.white(`\u9700\u6C42: ${activeSession.requirement.slice(0, 60)}${activeSession.requirement.length > 60 ? "..." : ""}`));
|
|
77
80
|
lines.push(chalk9.gray(`\u9636\u6BB5: ${getPhaseLabel(activeSession.phase)}`));
|
|
78
81
|
lines.push("");
|
|
79
|
-
if (activeSession.phase === "
|
|
82
|
+
if (activeSession.phase === "clarify") {
|
|
83
|
+
lines.push(chalk9.yellow("\u23F8\uFE0F \u7B49\u5F85\u9700\u6C42\u6F84\u6E05"));
|
|
84
|
+
lines.push(chalk9.gray('\u8BF7\u56DE\u7B54\u4E0A\u8FF0\u95EE\u9898\uFF0C\u6216\u8F93\u5165 "done" \u8868\u793A\u56DE\u7B54\u5B8C\u6210'));
|
|
85
|
+
} else if (activeSession.phase === "spec") {
|
|
80
86
|
lines.push(chalk9.yellow("\u23F8\uFE0F \u7B49\u5F85\u89C4\u683C\u786E\u8BA4"));
|
|
81
87
|
lines.push("");
|
|
82
88
|
lines.push(chalk9.green(" y - \u786E\u8BA4\u89C4\u683C\uFF0C\u7EE7\u7EED\u5DE5\u4F5C\u6D41"));
|
|
@@ -95,7 +101,7 @@ async function executeWorkflow(ctx) {
|
|
|
95
101
|
const lines = [];
|
|
96
102
|
try {
|
|
97
103
|
if (activeSession.phase === "context") {
|
|
98
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/
|
|
104
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/8: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
|
|
99
105
|
lines.push("");
|
|
100
106
|
activeSession.context = await readProjectContext(ctx.options.workingDirectory);
|
|
101
107
|
lines.push(chalk9.gray(` \u9879\u76EE: ${activeSession.context.name}`));
|
|
@@ -105,13 +111,46 @@ async function executeWorkflow(ctx) {
|
|
|
105
111
|
if (activeSession.context.devStandards) {
|
|
106
112
|
lines.push(chalk9.green(" \u2713 \u5DF2\u8BFB\u53D6\u5F00\u53D1\u89C4\u8303"));
|
|
107
113
|
}
|
|
114
|
+
activeSession.phase = "clarify";
|
|
115
|
+
}
|
|
116
|
+
if (activeSession.phase === "clarify") {
|
|
117
|
+
lines.push("");
|
|
118
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/8: \u9700\u6C42\u6F84\u6E05 \u2501\u2501\u2501"));
|
|
119
|
+
lines.push("");
|
|
120
|
+
const clarityResult = analyzeRequirementClarity(
|
|
121
|
+
activeSession.requirement,
|
|
122
|
+
activeSession.context
|
|
123
|
+
);
|
|
124
|
+
activeSession.clarityScore = clarityResult.score;
|
|
125
|
+
activeSession.clarificationQuestions = clarityResult.questions;
|
|
126
|
+
lines.push(chalk9.gray(` \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(clarityResult.score * 100)}%`));
|
|
127
|
+
lines.push("");
|
|
128
|
+
if (clarityResult.score < CLARITY_THRESHOLD && clarityResult.questions.length > 0) {
|
|
129
|
+
lines.push(chalk9.yellow(" \u9700\u6C42\u4E0D\u591F\u660E\u786E\uFF0C\u8BF7\u8865\u5145\u4EE5\u4E0B\u4FE1\u606F\uFF1A"));
|
|
130
|
+
lines.push("");
|
|
131
|
+
const unansweredQuestions = clarityResult.questions.filter((q) => !q.answered);
|
|
132
|
+
for (let i = 0; i < Math.min(unansweredQuestions.length, 3); i++) {
|
|
133
|
+
const q = unansweredQuestions[i];
|
|
134
|
+
lines.push(chalk9.white(` ${i + 1}. ${q.question}`));
|
|
135
|
+
}
|
|
136
|
+
if (unansweredQuestions.length > 3) {
|
|
137
|
+
lines.push(chalk9.gray(` ... \u8FD8\u6709 ${unansweredQuestions.length - 3} \u4E2A\u95EE\u9898`));
|
|
138
|
+
}
|
|
139
|
+
lines.push("");
|
|
140
|
+
lines.push(chalk9.gray(' \u8BF7\u8F93\u5165\u56DE\u7B54\uFF0C\u6216\u8F93\u5165 "done" \u8DF3\u8FC7\u6F84\u6E05'));
|
|
141
|
+
return { output: lines.join("\n") };
|
|
142
|
+
}
|
|
143
|
+
lines.push(chalk9.green(" \u2713 \u9700\u6C42\u6E05\u6670\uFF0C\u7EE7\u7EED\u4E0B\u4E00\u6B65"));
|
|
108
144
|
activeSession.phase = "analysis";
|
|
109
145
|
}
|
|
110
146
|
if (activeSession.phase === "analysis") {
|
|
111
147
|
lines.push("");
|
|
112
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
148
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 3/8: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
|
|
113
149
|
lines.push("");
|
|
114
|
-
activeSession.complexity = analyzeComplexity(
|
|
150
|
+
activeSession.complexity = analyzeComplexity(
|
|
151
|
+
activeSession.refinedRequirement,
|
|
152
|
+
activeSession.context
|
|
153
|
+
);
|
|
115
154
|
const complexityBar = generateComplexityBar(activeSession.complexity);
|
|
116
155
|
lines.push(chalk9.gray(` \u590D\u6742\u5EA6: ${complexityBar} ${activeSession.complexity}/10`));
|
|
117
156
|
if (activeSession.complexity >= COMPLEXITY_THRESHOLD) {
|
|
@@ -123,9 +162,13 @@ async function executeWorkflow(ctx) {
|
|
|
123
162
|
}
|
|
124
163
|
if (activeSession.phase === "bdd") {
|
|
125
164
|
lines.push("");
|
|
126
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
165
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 4/8: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
127
166
|
lines.push("");
|
|
128
|
-
activeSession.bddScenarios = generateBDDScenarios(
|
|
167
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
168
|
+
activeSession.refinedRequirement,
|
|
169
|
+
activeSession.context,
|
|
170
|
+
activeSession.clarificationQuestions
|
|
171
|
+
);
|
|
129
172
|
for (const scenario of activeSession.bddScenarios) {
|
|
130
173
|
lines.push(chalk9.white(` Feature: ${scenario.feature}`));
|
|
131
174
|
for (const s of scenario.scenarios.slice(0, 3)) {
|
|
@@ -139,9 +182,14 @@ async function executeWorkflow(ctx) {
|
|
|
139
182
|
}
|
|
140
183
|
if (activeSession.phase === "spec") {
|
|
141
184
|
lines.push("");
|
|
142
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
185
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/8: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
143
186
|
lines.push("");
|
|
144
|
-
activeSession.specItems = generateSpecItems(
|
|
187
|
+
activeSession.specItems = generateSpecItems(
|
|
188
|
+
activeSession.refinedRequirement,
|
|
189
|
+
activeSession.context,
|
|
190
|
+
activeSession.bddScenarios,
|
|
191
|
+
activeSession.clarificationQuestions
|
|
192
|
+
);
|
|
145
193
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
146
194
|
lines.push(chalk9.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
147
195
|
lines.push(chalk9.gray(` \u8DEF\u5F84: ${specPath}`));
|
|
@@ -164,7 +212,7 @@ async function executeWorkflow(ctx) {
|
|
|
164
212
|
}
|
|
165
213
|
if (activeSession.phase === "tdd") {
|
|
166
214
|
lines.push("");
|
|
167
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
215
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/8: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
168
216
|
lines.push("");
|
|
169
217
|
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
170
218
|
lines.push(chalk9.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
@@ -175,7 +223,7 @@ async function executeWorkflow(ctx) {
|
|
|
175
223
|
}
|
|
176
224
|
if (activeSession.phase === "develop") {
|
|
177
225
|
lines.push("");
|
|
178
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
226
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/8: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
|
|
179
227
|
lines.push("");
|
|
180
228
|
lines.push(chalk9.yellow(" \u{1F4DD} \u5F00\u53D1\u9636\u6BB5"));
|
|
181
229
|
lines.push(chalk9.gray(" \u8BF7\u8C03\u7528 $frontend-dev \u6267\u884C\u5F00\u53D1\u4EFB\u52A1"));
|
|
@@ -184,7 +232,7 @@ async function executeWorkflow(ctx) {
|
|
|
184
232
|
}
|
|
185
233
|
if (activeSession.phase === "review") {
|
|
186
234
|
lines.push("");
|
|
187
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
235
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 8/8: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
|
|
188
236
|
lines.push("");
|
|
189
237
|
lines.push(chalk9.yellow(" \u{1F50D} \u4EE3\u7801\u5BA1\u6838\u9636\u6BB5"));
|
|
190
238
|
lines.push(chalk9.gray(" \u8BF7\u8C03\u7528 $code-reviewer \u6267\u884C\u4EE3\u7801\u5BA1\u6838"));
|
|
@@ -205,14 +253,58 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
205
253
|
output: chalk9.yellow("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u53D6\u6D88")
|
|
206
254
|
};
|
|
207
255
|
}
|
|
256
|
+
if (activeSession.phase === "clarify") {
|
|
257
|
+
if (trimmed === "done" || trimmed === "\u5B8C\u6210" || trimmed === "\u8DF3\u8FC7" || trimmed === "skip") {
|
|
258
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
259
|
+
activeSession.phase = "analysis";
|
|
260
|
+
return executeWorkflow(ctx);
|
|
261
|
+
}
|
|
262
|
+
activeSession.clarificationQuestions.filter((q) => q.answered).length;
|
|
263
|
+
const unansweredQuestions = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
264
|
+
if (unansweredQuestions.length > 0) {
|
|
265
|
+
const question = unansweredQuestions[0];
|
|
266
|
+
question.answer = input.trim();
|
|
267
|
+
question.answered = true;
|
|
268
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
269
|
+
const remaining = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
270
|
+
if (remaining.length > 0) {
|
|
271
|
+
activeSession.clarityScore = calculateClarityScore(activeSession.clarificationQuestions);
|
|
272
|
+
const lines = [];
|
|
273
|
+
lines.push(chalk9.green(" \u2713 \u5DF2\u8BB0\u5F55"));
|
|
274
|
+
lines.push("");
|
|
275
|
+
lines.push(chalk9.yellow(" \u7EE7\u7EED\u56DE\u7B54\uFF1A"));
|
|
276
|
+
for (let i = 0; i < Math.min(remaining.length, 3); i++) {
|
|
277
|
+
const q = remaining[i];
|
|
278
|
+
lines.push(chalk9.white(` ${i + 1}. ${q.question}`));
|
|
279
|
+
}
|
|
280
|
+
lines.push("");
|
|
281
|
+
lines.push(chalk9.gray(' \u8F93\u5165\u56DE\u7B54\uFF0C\u6216 "done" \u8DF3\u8FC7'));
|
|
282
|
+
return { output: lines.join("\n") };
|
|
283
|
+
}
|
|
284
|
+
activeSession.clarityScore = 1;
|
|
285
|
+
activeSession.phase = "analysis";
|
|
286
|
+
return executeWorkflow(ctx);
|
|
287
|
+
}
|
|
288
|
+
activeSession.phase = "analysis";
|
|
289
|
+
return executeWorkflow(ctx);
|
|
290
|
+
}
|
|
208
291
|
if (activeSession.phase === "spec") {
|
|
209
292
|
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
|
|
210
293
|
activeSession.phase = "tdd";
|
|
211
294
|
return executeWorkflow(ctx);
|
|
212
295
|
}
|
|
213
296
|
if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
|
|
214
|
-
activeSession.bddScenarios = generateBDDScenarios(
|
|
215
|
-
|
|
297
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
298
|
+
activeSession.refinedRequirement,
|
|
299
|
+
activeSession.context,
|
|
300
|
+
activeSession.clarificationQuestions
|
|
301
|
+
);
|
|
302
|
+
activeSession.specItems = generateSpecItems(
|
|
303
|
+
activeSession.refinedRequirement,
|
|
304
|
+
activeSession.context,
|
|
305
|
+
activeSession.bddScenarios,
|
|
306
|
+
activeSession.clarificationQuestions
|
|
307
|
+
);
|
|
216
308
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
217
309
|
return {
|
|
218
310
|
output: chalk9.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9.gray(`
|
|
@@ -229,11 +321,11 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
229
321
|
if (activeSession.phase === "review") {
|
|
230
322
|
if (trimmed === "review" || trimmed === "\u5BA1\u6838" || trimmed === "pass" || trimmed === "\u901A\u8FC7") {
|
|
231
323
|
await archiveWorkflow(ctx.options.workingDirectory);
|
|
232
|
-
const summary = activeSession.
|
|
324
|
+
const summary = activeSession.refinedRequirement;
|
|
233
325
|
activeSession = null;
|
|
234
326
|
return {
|
|
235
327
|
output: chalk9.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5B8C\u6210") + chalk9.gray(`
|
|
236
|
-
\u9700\u6C42: ${summary}
|
|
328
|
+
\u9700\u6C42: ${summary.slice(0, 60)}...`) + chalk9.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
|
|
237
329
|
};
|
|
238
330
|
}
|
|
239
331
|
if (trimmed === "fail" || trimmed === "\u5931\u8D25" || trimmed === "reject" || trimmed === "\u62D2\u7EDD") {
|
|
@@ -245,6 +337,122 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
245
337
|
}
|
|
246
338
|
return null;
|
|
247
339
|
}
|
|
340
|
+
function analyzeRequirementClarity(requirement, context) {
|
|
341
|
+
const questions = [];
|
|
342
|
+
let score = 0.5;
|
|
343
|
+
if (requirement.length < 10) {
|
|
344
|
+
score -= 0.2;
|
|
345
|
+
questions.push({
|
|
346
|
+
id: "q-length",
|
|
347
|
+
question: "\u9700\u6C42\u63CF\u8FF0\u8F83\u77ED\uFF0C\u80FD\u5426\u8BE6\u7EC6\u8BF4\u660E\u5177\u4F53\u8981\u5B9E\u73B0\u4EC0\u4E48\u529F\u80FD\uFF1F",
|
|
348
|
+
category: "scope",
|
|
349
|
+
answered: false
|
|
350
|
+
});
|
|
351
|
+
} else if (requirement.length >= 50) {
|
|
352
|
+
score += 0.1;
|
|
353
|
+
}
|
|
354
|
+
const actionKeywords = ["\u5B9E\u73B0", "\u6DFB\u52A0", "\u4FEE\u6539", "\u5220\u9664", "\u4F18\u5316", "\u4FEE\u590D", "\u91CD\u6784", "\u5F00\u53D1", "\u521B\u5EFA", "\u8BBE\u8BA1"];
|
|
355
|
+
const hasAction = actionKeywords.some((kw) => requirement.includes(kw));
|
|
356
|
+
if (!hasAction) {
|
|
357
|
+
score -= 0.15;
|
|
358
|
+
questions.push({
|
|
359
|
+
id: "q-action",
|
|
360
|
+
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",
|
|
361
|
+
category: "scope",
|
|
362
|
+
answered: false
|
|
363
|
+
});
|
|
364
|
+
} else {
|
|
365
|
+
score += 0.1;
|
|
366
|
+
}
|
|
367
|
+
if (requirement.match(/界面|页面|组件|按钮|表单|弹窗|布局|样式|UI/)) {
|
|
368
|
+
score += 0.1;
|
|
369
|
+
if (!requirement.match(/在.*页面|在.*位置|显示在|位于/)) {
|
|
370
|
+
questions.push({
|
|
371
|
+
id: "q-ui-position",
|
|
372
|
+
question: "\u8FD9\u4E2A\u529F\u80FD\u5E94\u8BE5\u653E\u5728\u54EA\u4E2A\u9875\u9762\u6216\u4F4D\u7F6E\uFF1F",
|
|
373
|
+
category: "ui",
|
|
374
|
+
answered: false
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
questions.push({
|
|
379
|
+
id: "q-ui-need",
|
|
380
|
+
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",
|
|
381
|
+
category: "ui",
|
|
382
|
+
answered: false
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
if (requirement.match(/数据|存储|保存|读取|API|接口|数据库|缓存/)) {
|
|
386
|
+
score += 0.1;
|
|
387
|
+
if (!requirement.match(/从.*获取|调用.*接口|读取.*数据|来源/)) {
|
|
388
|
+
questions.push({
|
|
389
|
+
id: "q-data-source",
|
|
390
|
+
question: "\u6570\u636E\u4ECE\u54EA\u91CC\u6765\uFF1F\u662F\u8C03\u7528API\u3001\u672C\u5730\u5B58\u50A8\u8FD8\u662F\u5176\u4ED6\u6765\u6E90\uFF1F",
|
|
391
|
+
category: "data",
|
|
392
|
+
answered: false
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (requirement.match(/点击|输入|选择|拖动|滑动|交互|操作/)) {
|
|
397
|
+
score += 0.1;
|
|
398
|
+
} else {
|
|
399
|
+
if (hasAction && requirement.match(/功能|特性|模块/)) {
|
|
400
|
+
questions.push({
|
|
401
|
+
id: "q-interaction",
|
|
402
|
+
question: "\u7528\u6237\u5982\u4F55\u64CD\u4F5C\u8FD9\u4E2A\u529F\u80FD\uFF1F\u6709\u4EC0\u4E48\u4EA4\u4E92\u6D41\u7A0B\uFF1F",
|
|
403
|
+
category: "interaction",
|
|
404
|
+
answered: false
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (requirement.match(/异常|错误|失败|边界|特殊情况|空值|验证/)) {
|
|
409
|
+
score += 0.15;
|
|
410
|
+
} else {
|
|
411
|
+
if (requirement.match(/功能|输入|表单|数据/)) {
|
|
412
|
+
questions.push({
|
|
413
|
+
id: "q-edge",
|
|
414
|
+
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",
|
|
415
|
+
category: "edge",
|
|
416
|
+
answered: false
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (requirement.match(/https?:\/\/|参考|参照|类似/)) {
|
|
421
|
+
score += 0.15;
|
|
422
|
+
}
|
|
423
|
+
if (context.framework) {
|
|
424
|
+
score += 0.05;
|
|
425
|
+
}
|
|
426
|
+
const limitedQuestions = questions.slice(0, 5);
|
|
427
|
+
score = Math.max(0, Math.min(1, score));
|
|
428
|
+
return { score, questions: limitedQuestions };
|
|
429
|
+
}
|
|
430
|
+
function calculateClarityScore(questions) {
|
|
431
|
+
const answered = questions.filter((q) => q.answered).length;
|
|
432
|
+
if (questions.length === 0) return 1;
|
|
433
|
+
return 0.5 + answered / questions.length * 0.5;
|
|
434
|
+
}
|
|
435
|
+
function buildRefinedRequirement(session) {
|
|
436
|
+
const parts = [session.requirement];
|
|
437
|
+
for (const q of session.clarificationQuestions) {
|
|
438
|
+
if (q.answered && q.answer) {
|
|
439
|
+
parts.push(`
|
|
440
|
+
\u3010${getCategoryLabel(q.category)}\u3011${q.answer}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return parts.join("");
|
|
444
|
+
}
|
|
445
|
+
function getCategoryLabel(category) {
|
|
446
|
+
const labels = {
|
|
447
|
+
scope: "\u8303\u56F4",
|
|
448
|
+
ui: "\u754C\u9762",
|
|
449
|
+
data: "\u6570\u636E",
|
|
450
|
+
interaction: "\u4EA4\u4E92",
|
|
451
|
+
edge: "\u8FB9\u754C",
|
|
452
|
+
tech: "\u6280\u672F"
|
|
453
|
+
};
|
|
454
|
+
return labels[category] || category;
|
|
455
|
+
}
|
|
248
456
|
async function readProjectContext(workingDir) {
|
|
249
457
|
const context = {
|
|
250
458
|
name: path5.basename(workingDir),
|
|
@@ -326,8 +534,11 @@ function analyzeComplexity(requirement, context) {
|
|
|
326
534
|
if (!context.framework) score += 0.5;
|
|
327
535
|
return Math.max(1, Math.min(10, Math.round(score)));
|
|
328
536
|
}
|
|
329
|
-
function generateBDDScenarios(requirement, context) {
|
|
537
|
+
function generateBDDScenarios(requirement, context, questions) {
|
|
330
538
|
const scenarios = [];
|
|
539
|
+
questions.find((q) => q.category === "ui" && q.answered)?.answer;
|
|
540
|
+
const interactionAnswer = questions.find((q) => q.category === "interaction" && q.answered)?.answer;
|
|
541
|
+
const edgeAnswer = questions.find((q) => q.category === "edge" && q.answered)?.answer;
|
|
331
542
|
const features = extractFeatures(requirement);
|
|
332
543
|
for (const feature of features) {
|
|
333
544
|
const scenario = {
|
|
@@ -341,12 +552,20 @@ function generateBDDScenarios(requirement, context) {
|
|
|
341
552
|
when: [`\u7528\u6237\u6267\u884C "${feature.title}" \u64CD\u4F5C`],
|
|
342
553
|
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5E76\u8FD4\u56DE\u9884\u671F\u7ED3\u679C`]
|
|
343
554
|
});
|
|
344
|
-
if (
|
|
555
|
+
if (interactionAnswer) {
|
|
345
556
|
scenario.scenarios.push({
|
|
346
|
-
name: `\
|
|
347
|
-
given: [`\u7528\u6237\u8FDB\u5165\
|
|
348
|
-
when: [`\u7528\u6237\
|
|
349
|
-
then: [`\u7CFB\u7EDF\u5E94\
|
|
557
|
+
name: `\u4EA4\u4E92\u6D41\u7A0B: \u7528\u6237\u64CD\u4F5C`,
|
|
558
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
559
|
+
when: [`\u7528\u6237\u6309\u7167\u4EE5\u4E0B\u6D41\u7A0B\u64CD\u4F5C: ${interactionAnswer}`],
|
|
560
|
+
then: [`\u7CFB\u7EDF\u54CD\u5E94\u5E76\u5B8C\u6210\u529F\u80FD`]
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
if (feature.hasInput || edgeAnswer) {
|
|
564
|
+
scenario.scenarios.push({
|
|
565
|
+
name: `\u8FB9\u754C\u60C5\u51B5: \u5F02\u5E38\u5904\u7406`,
|
|
566
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
567
|
+
when: [`\u53D1\u751F\u5F02\u5E38\u60C5\u51B5${edgeAnswer ? `: ${edgeAnswer}` : ""}`],
|
|
568
|
+
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5F02\u5E38\u5E76\u7ED9\u51FA\u63D0\u793A`]
|
|
350
569
|
});
|
|
351
570
|
}
|
|
352
571
|
scenarios.push(scenario);
|
|
@@ -393,7 +612,7 @@ function extractFeatures(requirement) {
|
|
|
393
612
|
}
|
|
394
613
|
return features;
|
|
395
614
|
}
|
|
396
|
-
function generateSpecItems(requirement, context, bddScenarios) {
|
|
615
|
+
function generateSpecItems(requirement, context, bddScenarios, questions) {
|
|
397
616
|
const items = [];
|
|
398
617
|
let id = 1;
|
|
399
618
|
for (const scenario of bddScenarios) {
|
|
@@ -430,11 +649,33 @@ function formatSpecFile(session) {
|
|
|
430
649
|
lines.push(`# \u9700\u6C42\u89C4\u683C: ${session.requirement.slice(0, 50)}`);
|
|
431
650
|
lines.push("");
|
|
432
651
|
lines.push(`> \u53D8\u66F4ID: ${session.id}`);
|
|
652
|
+
lines.push(`> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(session.clarityScore * 100)}%`);
|
|
433
653
|
lines.push(`> \u590D\u6742\u5EA6: ${session.complexity}/10`);
|
|
434
654
|
lines.push(`> \u751F\u6210\u65F6\u95F4: ${session.createdAt.toISOString()}`);
|
|
435
655
|
lines.push("");
|
|
436
656
|
lines.push("---");
|
|
437
657
|
lines.push("");
|
|
658
|
+
if (session.refinedRequirement !== session.requirement) {
|
|
659
|
+
lines.push("## \u9700\u6C42\u8BE6\u60C5");
|
|
660
|
+
lines.push("");
|
|
661
|
+
lines.push(session.refinedRequirement);
|
|
662
|
+
lines.push("");
|
|
663
|
+
lines.push("---");
|
|
664
|
+
lines.push("");
|
|
665
|
+
}
|
|
666
|
+
if (session.clarificationQuestions.some((q) => q.answered)) {
|
|
667
|
+
lines.push("## \u9700\u6C42\u6F84\u6E05");
|
|
668
|
+
lines.push("");
|
|
669
|
+
for (const q of session.clarificationQuestions) {
|
|
670
|
+
if (q.answered) {
|
|
671
|
+
lines.push(`**Q: ${q.question}**`);
|
|
672
|
+
lines.push(`A: ${q.answer}`);
|
|
673
|
+
lines.push("");
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
lines.push("---");
|
|
677
|
+
lines.push("");
|
|
678
|
+
}
|
|
438
679
|
lines.push("## BDD \u573A\u666F");
|
|
439
680
|
lines.push("");
|
|
440
681
|
for (const scenario of session.bddScenarios) {
|
|
@@ -498,11 +739,17 @@ async function archiveWorkflow(workingDir) {
|
|
|
498
739
|
const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
|
|
499
740
|
|
|
500
741
|
> \u5F52\u6863\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
742
|
+
> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(activeSession.clarityScore * 100)}%
|
|
501
743
|
> \u590D\u6742\u5EA6: ${activeSession.complexity}/10
|
|
502
744
|
|
|
745
|
+
## \u9700\u6C42\u8BE6\u60C5
|
|
746
|
+
|
|
747
|
+
${activeSession.refinedRequirement}
|
|
748
|
+
|
|
503
749
|
## \u5B8C\u6210\u60C5\u51B5
|
|
504
750
|
|
|
505
751
|
- [x] \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6
|
|
752
|
+
- [x] \u9700\u6C42\u6F84\u6E05
|
|
506
753
|
- [x] \u590D\u6742\u5EA6\u8BC4\u4F30
|
|
507
754
|
- [x] BDD \u573A\u666F\u62C6\u89E3
|
|
508
755
|
- [x] OpenSpec \u89C4\u683C
|
|
@@ -529,6 +776,7 @@ function generateComplexityBar(score) {
|
|
|
529
776
|
function getPhaseLabel(phase) {
|
|
530
777
|
const labels = {
|
|
531
778
|
context: "\u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6",
|
|
779
|
+
clarify: "\u9700\u6C42\u6F84\u6E05",
|
|
532
780
|
analysis: "\u590D\u6742\u5EA6\u8BC4\u4F30",
|
|
533
781
|
bdd: "BDD \u573A\u666F\u62C6\u89E3",
|
|
534
782
|
spec: "OpenSpec \u89C4\u683C",
|
|
@@ -544,12 +792,13 @@ function getActiveSession() {
|
|
|
544
792
|
function clearActiveSession() {
|
|
545
793
|
activeSession = null;
|
|
546
794
|
}
|
|
547
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, activeSession, new_default;
|
|
795
|
+
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
548
796
|
var init_new = __esm({
|
|
549
797
|
"src/commands/new.ts"() {
|
|
550
798
|
init_esm_shims();
|
|
551
799
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
552
800
|
COMPLEXITY_THRESHOLD = 6;
|
|
801
|
+
CLARITY_THRESHOLD = 0.6;
|
|
553
802
|
activeSession = null;
|
|
554
803
|
new_default = handleNew;
|
|
555
804
|
}
|