@nick848/sf-cli 1.0.10 → 1.0.12
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 +43 -6
- package/dist/cli/index.js +542 -35
- 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 +540 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +540 -35
- 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,20 +223,69 @@ 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
|
-
lines.push(chalk9.yellow(" \u{
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
228
|
+
lines.push(chalk9.yellow(" \u{1F680} \u6B63\u5728\u8C03\u7528 AI \u751F\u6210\u4EE3\u7801..."));
|
|
229
|
+
try {
|
|
230
|
+
const developResult = await executeDevelopment(ctx, activeSession);
|
|
231
|
+
if (developResult.success) {
|
|
232
|
+
lines.push(chalk9.green(" \u2713 \u4EE3\u7801\u751F\u6210\u5B8C\u6210"));
|
|
233
|
+
for (const file of developResult.files) {
|
|
234
|
+
lines.push(chalk9.gray(` - ${file}`));
|
|
235
|
+
}
|
|
236
|
+
activeSession.implFiles = developResult.files;
|
|
237
|
+
activeSession.phase = "review";
|
|
238
|
+
} else {
|
|
239
|
+
lines.push(chalk9.red(` \u2717 \u4EE3\u7801\u751F\u6210\u5931\u8D25: ${developResult.error}`));
|
|
240
|
+
lines.push(chalk9.gray(" \u8BF7\u624B\u52A8\u5B9E\u73B0\u4EE3\u7801\u540E\u8F93\u5165 continue \u7EE7\u7EED"));
|
|
241
|
+
return { output: lines.join("\n") };
|
|
242
|
+
}
|
|
243
|
+
} catch (error) {
|
|
244
|
+
lines.push(chalk9.red(` \u2717 \u5F00\u53D1\u9636\u6BB5\u51FA\u9519: ${error.message}`));
|
|
245
|
+
lines.push(chalk9.gray(" \u8BF7\u624B\u52A8\u5B9E\u73B0\u4EE3\u7801\u540E\u8F93\u5165 continue \u7EE7\u7EED"));
|
|
246
|
+
return { output: lines.join("\n") };
|
|
247
|
+
}
|
|
184
248
|
}
|
|
185
249
|
if (activeSession.phase === "review") {
|
|
186
250
|
lines.push("");
|
|
187
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
251
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 8/8: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
|
|
188
252
|
lines.push("");
|
|
189
|
-
lines.push(chalk9.yellow(" \u{1F50D} \u4EE3\u7801\u5BA1\u6838
|
|
190
|
-
|
|
191
|
-
|
|
253
|
+
lines.push(chalk9.yellow(" \u{1F50D} \u6B63\u5728\u8FDB\u884C\u4EE3\u7801\u5BA1\u6838..."));
|
|
254
|
+
try {
|
|
255
|
+
const reviewResult = await executeReview(ctx, activeSession);
|
|
256
|
+
if (reviewResult.passed) {
|
|
257
|
+
lines.push(chalk9.green(" \u2713 \u4EE3\u7801\u5BA1\u6838\u901A\u8FC7"));
|
|
258
|
+
if (reviewResult.suggestions.length > 0) {
|
|
259
|
+
lines.push(chalk9.gray(" \u5EFA\u8BAE:"));
|
|
260
|
+
for (const s of reviewResult.suggestions.slice(0, 3)) {
|
|
261
|
+
lines.push(chalk9.gray(` - ${s}`));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
await archiveWorkflow(ctx.options.workingDirectory);
|
|
265
|
+
const summary = activeSession.refinedRequirement;
|
|
266
|
+
activeSession = null;
|
|
267
|
+
lines.push("");
|
|
268
|
+
lines.push(chalk9.green.bold("\u{1F389} \u5DE5\u4F5C\u6D41\u5DF2\u5B8C\u6210\uFF01"));
|
|
269
|
+
lines.push(chalk9.gray(`\u9700\u6C42: ${summary.slice(0, 60)}${summary.length > 60 ? "..." : ""}`));
|
|
270
|
+
lines.push("");
|
|
271
|
+
lines.push(chalk9.cyan("\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41"));
|
|
272
|
+
return { output: lines.join("\n") };
|
|
273
|
+
} else {
|
|
274
|
+
lines.push(chalk9.red(" \u2717 \u4EE3\u7801\u5BA1\u6838\u672A\u901A\u8FC7"));
|
|
275
|
+
lines.push(chalk9.gray(" \u95EE\u9898:"));
|
|
276
|
+
for (const issue of reviewResult.issues.slice(0, 5)) {
|
|
277
|
+
lines.push(chalk9.red(` - ${issue}`));
|
|
278
|
+
}
|
|
279
|
+
lines.push("");
|
|
280
|
+
lines.push(chalk9.yellow(" \u8BF7\u4FEE\u590D\u95EE\u9898\u540E\u8F93\u5165 y \u91CD\u65B0\u5BA1\u6838"));
|
|
281
|
+
lines.push(chalk9.gray(" \u6216\u8F93\u5165 n \u56DE\u9000\u5230\u89C4\u683C\u9636\u6BB5"));
|
|
282
|
+
return { output: lines.join("\n") };
|
|
283
|
+
}
|
|
284
|
+
} catch (error) {
|
|
285
|
+
lines.push(chalk9.red(` \u2717 \u5BA1\u6838\u9636\u6BB5\u51FA\u9519: ${error.message}`));
|
|
286
|
+
lines.push(chalk9.gray(" \u8F93\u5165 pass \u5F3A\u5236\u901A\u8FC7\uFF0C\u6216 fix \u4FEE\u590D\u95EE\u9898"));
|
|
287
|
+
return { output: lines.join("\n") };
|
|
288
|
+
}
|
|
192
289
|
}
|
|
193
290
|
return { output: lines.join("\n") };
|
|
194
291
|
} catch (error) {
|
|
@@ -205,14 +302,58 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
205
302
|
output: chalk9.yellow("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u53D6\u6D88")
|
|
206
303
|
};
|
|
207
304
|
}
|
|
305
|
+
if (activeSession.phase === "clarify") {
|
|
306
|
+
if (trimmed === "done" || trimmed === "\u5B8C\u6210" || trimmed === "\u8DF3\u8FC7" || trimmed === "skip") {
|
|
307
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
308
|
+
activeSession.phase = "analysis";
|
|
309
|
+
return executeWorkflow(ctx);
|
|
310
|
+
}
|
|
311
|
+
activeSession.clarificationQuestions.filter((q) => q.answered).length;
|
|
312
|
+
const unansweredQuestions = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
313
|
+
if (unansweredQuestions.length > 0) {
|
|
314
|
+
const question = unansweredQuestions[0];
|
|
315
|
+
question.answer = input.trim();
|
|
316
|
+
question.answered = true;
|
|
317
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
318
|
+
const remaining = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
319
|
+
if (remaining.length > 0) {
|
|
320
|
+
activeSession.clarityScore = calculateClarityScore(activeSession.clarificationQuestions);
|
|
321
|
+
const lines = [];
|
|
322
|
+
lines.push(chalk9.green(" \u2713 \u5DF2\u8BB0\u5F55"));
|
|
323
|
+
lines.push("");
|
|
324
|
+
lines.push(chalk9.yellow(" \u7EE7\u7EED\u56DE\u7B54\uFF1A"));
|
|
325
|
+
for (let i = 0; i < Math.min(remaining.length, 3); i++) {
|
|
326
|
+
const q = remaining[i];
|
|
327
|
+
lines.push(chalk9.white(` ${i + 1}. ${q.question}`));
|
|
328
|
+
}
|
|
329
|
+
lines.push("");
|
|
330
|
+
lines.push(chalk9.gray(' \u8F93\u5165\u56DE\u7B54\uFF0C\u6216 "done" \u8DF3\u8FC7'));
|
|
331
|
+
return { output: lines.join("\n") };
|
|
332
|
+
}
|
|
333
|
+
activeSession.clarityScore = 1;
|
|
334
|
+
activeSession.phase = "analysis";
|
|
335
|
+
return executeWorkflow(ctx);
|
|
336
|
+
}
|
|
337
|
+
activeSession.phase = "analysis";
|
|
338
|
+
return executeWorkflow(ctx);
|
|
339
|
+
}
|
|
208
340
|
if (activeSession.phase === "spec") {
|
|
209
341
|
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
|
|
210
342
|
activeSession.phase = "tdd";
|
|
211
343
|
return executeWorkflow(ctx);
|
|
212
344
|
}
|
|
213
345
|
if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
|
|
214
|
-
activeSession.bddScenarios = generateBDDScenarios(
|
|
215
|
-
|
|
346
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
347
|
+
activeSession.refinedRequirement,
|
|
348
|
+
activeSession.context,
|
|
349
|
+
activeSession.clarificationQuestions
|
|
350
|
+
);
|
|
351
|
+
activeSession.specItems = generateSpecItems(
|
|
352
|
+
activeSession.refinedRequirement,
|
|
353
|
+
activeSession.context,
|
|
354
|
+
activeSession.bddScenarios,
|
|
355
|
+
activeSession.clarificationQuestions
|
|
356
|
+
);
|
|
216
357
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
217
358
|
return {
|
|
218
359
|
output: chalk9.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9.gray(`
|
|
@@ -227,24 +368,347 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
227
368
|
}
|
|
228
369
|
}
|
|
229
370
|
if (activeSession.phase === "review") {
|
|
230
|
-
if (trimmed === "
|
|
371
|
+
if (trimmed === "pass" || trimmed === "\u901A\u8FC7" || trimmed === "\u5F3A\u5236\u901A\u8FC7") {
|
|
231
372
|
await archiveWorkflow(ctx.options.workingDirectory);
|
|
232
|
-
const summary = activeSession.
|
|
373
|
+
const summary = activeSession.refinedRequirement;
|
|
233
374
|
activeSession = null;
|
|
234
375
|
return {
|
|
235
376
|
output: chalk9.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5B8C\u6210") + chalk9.gray(`
|
|
236
|
-
\u9700\u6C42: ${summary}`) + chalk9.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
|
|
377
|
+
\u9700\u6C42: ${summary.slice(0, 60)}${summary.length > 60 ? "..." : ""}`) + chalk9.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
|
|
237
378
|
};
|
|
238
379
|
}
|
|
239
|
-
if (trimmed === "
|
|
380
|
+
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u91CD\u65B0\u5BA1\u6838" || trimmed === "retry") {
|
|
381
|
+
return executeWorkflow(ctx);
|
|
382
|
+
}
|
|
383
|
+
if (trimmed === "n" || trimmed === "no" || trimmed === "\u56DE\u9000" || trimmed === "rollback") {
|
|
240
384
|
activeSession.phase = "spec";
|
|
385
|
+
return executeWorkflow(ctx);
|
|
386
|
+
}
|
|
387
|
+
if (trimmed === "fix" || trimmed === "\u4FEE\u590D") {
|
|
241
388
|
return {
|
|
242
|
-
output: chalk9.yellow("\
|
|
389
|
+
output: chalk9.yellow("\u{1F4DD} \u8BF7\u624B\u52A8\u4FEE\u590D\u4EE3\u7801\u95EE\u9898") + chalk9.gray("\n\u4FEE\u590D\u5B8C\u6210\u540E\u8F93\u5165 y \u91CD\u65B0\u5BA1\u6838") + chalk9.gray("\n\u6216\u8F93\u5165 n \u56DE\u9000\u5230\u89C4\u683C\u9636\u6BB5")
|
|
243
390
|
};
|
|
244
391
|
}
|
|
245
392
|
}
|
|
246
393
|
return null;
|
|
247
394
|
}
|
|
395
|
+
function analyzeRequirementClarity(requirement, context) {
|
|
396
|
+
const questions = [];
|
|
397
|
+
let score = 0.5;
|
|
398
|
+
if (requirement.length < 10) {
|
|
399
|
+
score -= 0.2;
|
|
400
|
+
questions.push({
|
|
401
|
+
id: "q-length",
|
|
402
|
+
question: "\u9700\u6C42\u63CF\u8FF0\u8F83\u77ED\uFF0C\u80FD\u5426\u8BE6\u7EC6\u8BF4\u660E\u5177\u4F53\u8981\u5B9E\u73B0\u4EC0\u4E48\u529F\u80FD\uFF1F",
|
|
403
|
+
category: "scope",
|
|
404
|
+
answered: false
|
|
405
|
+
});
|
|
406
|
+
} else if (requirement.length >= 50) {
|
|
407
|
+
score += 0.1;
|
|
408
|
+
}
|
|
409
|
+
const actionKeywords = ["\u5B9E\u73B0", "\u6DFB\u52A0", "\u4FEE\u6539", "\u5220\u9664", "\u4F18\u5316", "\u4FEE\u590D", "\u91CD\u6784", "\u5F00\u53D1", "\u521B\u5EFA", "\u8BBE\u8BA1"];
|
|
410
|
+
const hasAction = actionKeywords.some((kw) => requirement.includes(kw));
|
|
411
|
+
if (!hasAction) {
|
|
412
|
+
score -= 0.15;
|
|
413
|
+
questions.push({
|
|
414
|
+
id: "q-action",
|
|
415
|
+
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",
|
|
416
|
+
category: "scope",
|
|
417
|
+
answered: false
|
|
418
|
+
});
|
|
419
|
+
} else {
|
|
420
|
+
score += 0.1;
|
|
421
|
+
}
|
|
422
|
+
if (requirement.match(/界面|页面|组件|按钮|表单|弹窗|布局|样式|UI/)) {
|
|
423
|
+
score += 0.1;
|
|
424
|
+
if (!requirement.match(/在.*页面|在.*位置|显示在|位于/)) {
|
|
425
|
+
questions.push({
|
|
426
|
+
id: "q-ui-position",
|
|
427
|
+
question: "\u8FD9\u4E2A\u529F\u80FD\u5E94\u8BE5\u653E\u5728\u54EA\u4E2A\u9875\u9762\u6216\u4F4D\u7F6E\uFF1F",
|
|
428
|
+
category: "ui",
|
|
429
|
+
answered: false
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
} else {
|
|
433
|
+
questions.push({
|
|
434
|
+
id: "q-ui-need",
|
|
435
|
+
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",
|
|
436
|
+
category: "ui",
|
|
437
|
+
answered: false
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
if (requirement.match(/数据|存储|保存|读取|API|接口|数据库|缓存/)) {
|
|
441
|
+
score += 0.1;
|
|
442
|
+
if (!requirement.match(/从.*获取|调用.*接口|读取.*数据|来源/)) {
|
|
443
|
+
questions.push({
|
|
444
|
+
id: "q-data-source",
|
|
445
|
+
question: "\u6570\u636E\u4ECE\u54EA\u91CC\u6765\uFF1F\u662F\u8C03\u7528API\u3001\u672C\u5730\u5B58\u50A8\u8FD8\u662F\u5176\u4ED6\u6765\u6E90\uFF1F",
|
|
446
|
+
category: "data",
|
|
447
|
+
answered: false
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (requirement.match(/点击|输入|选择|拖动|滑动|交互|操作/)) {
|
|
452
|
+
score += 0.1;
|
|
453
|
+
} else {
|
|
454
|
+
if (hasAction && requirement.match(/功能|特性|模块/)) {
|
|
455
|
+
questions.push({
|
|
456
|
+
id: "q-interaction",
|
|
457
|
+
question: "\u7528\u6237\u5982\u4F55\u64CD\u4F5C\u8FD9\u4E2A\u529F\u80FD\uFF1F\u6709\u4EC0\u4E48\u4EA4\u4E92\u6D41\u7A0B\uFF1F",
|
|
458
|
+
category: "interaction",
|
|
459
|
+
answered: false
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (requirement.match(/异常|错误|失败|边界|特殊情况|空值|验证/)) {
|
|
464
|
+
score += 0.15;
|
|
465
|
+
} else {
|
|
466
|
+
if (requirement.match(/功能|输入|表单|数据/)) {
|
|
467
|
+
questions.push({
|
|
468
|
+
id: "q-edge",
|
|
469
|
+
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",
|
|
470
|
+
category: "edge",
|
|
471
|
+
answered: false
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (requirement.match(/https?:\/\/|参考|参照|类似/)) {
|
|
476
|
+
score += 0.15;
|
|
477
|
+
}
|
|
478
|
+
if (context.framework) {
|
|
479
|
+
score += 0.05;
|
|
480
|
+
}
|
|
481
|
+
const limitedQuestions = questions.slice(0, 5);
|
|
482
|
+
score = Math.max(0, Math.min(1, score));
|
|
483
|
+
return { score, questions: limitedQuestions };
|
|
484
|
+
}
|
|
485
|
+
function calculateClarityScore(questions) {
|
|
486
|
+
const answered = questions.filter((q) => q.answered).length;
|
|
487
|
+
if (questions.length === 0) return 1;
|
|
488
|
+
return 0.5 + answered / questions.length * 0.5;
|
|
489
|
+
}
|
|
490
|
+
function buildRefinedRequirement(session) {
|
|
491
|
+
const parts = [session.requirement];
|
|
492
|
+
for (const q of session.clarificationQuestions) {
|
|
493
|
+
if (q.answered && q.answer) {
|
|
494
|
+
parts.push(`
|
|
495
|
+
\u3010${getCategoryLabel(q.category)}\u3011${q.answer}`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return parts.join("");
|
|
499
|
+
}
|
|
500
|
+
function getCategoryLabel(category) {
|
|
501
|
+
const labels = {
|
|
502
|
+
scope: "\u8303\u56F4",
|
|
503
|
+
ui: "\u754C\u9762",
|
|
504
|
+
data: "\u6570\u636E",
|
|
505
|
+
interaction: "\u4EA4\u4E92",
|
|
506
|
+
edge: "\u8FB9\u754C",
|
|
507
|
+
tech: "\u6280\u672F"
|
|
508
|
+
};
|
|
509
|
+
return labels[category] || category;
|
|
510
|
+
}
|
|
511
|
+
async function executeDevelopment(ctx, session) {
|
|
512
|
+
const workingDir = ctx.options.workingDirectory;
|
|
513
|
+
const files = [];
|
|
514
|
+
try {
|
|
515
|
+
const systemPrompt = buildDevelopmentPrompt(session);
|
|
516
|
+
const messages = [
|
|
517
|
+
{
|
|
518
|
+
role: "system",
|
|
519
|
+
content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u9700\u6C42\u89C4\u683C\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002
|
|
520
|
+
|
|
521
|
+
\u8981\u6C42\uFF1A
|
|
522
|
+
1. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
523
|
+
2. \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u4EE3\u7801\u98CE\u683C\u548C\u89C4\u8303
|
|
524
|
+
3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808
|
|
525
|
+
4. \u4EE3\u7801\u8981\u6709\u9002\u5F53\u7684\u6CE8\u91CA
|
|
526
|
+
5. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
527
|
+
|
|
528
|
+
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
529
|
+
- \u540D\u79F0: ${session.context?.name}
|
|
530
|
+
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
531
|
+
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
532
|
+
|
|
533
|
+
${session.context?.devStandards ? `\u5F00\u53D1\u89C4\u8303\uFF1A
|
|
534
|
+
${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
role: "user",
|
|
538
|
+
content: systemPrompt
|
|
539
|
+
}
|
|
540
|
+
];
|
|
541
|
+
const response = await ctx.modelService.sendMessage(messages, {
|
|
542
|
+
temperature: 0.3,
|
|
543
|
+
maxTokens: 8e3,
|
|
544
|
+
agent: "frontend-dev"
|
|
545
|
+
});
|
|
546
|
+
const codeBlocks = parseCodeBlocks(response.content);
|
|
547
|
+
for (const block of codeBlocks) {
|
|
548
|
+
const filePath = path5.join(workingDir, block.filename);
|
|
549
|
+
const dir = path5.dirname(filePath);
|
|
550
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
551
|
+
await fs4.writeFile(filePath, block.code, "utf-8");
|
|
552
|
+
files.push(block.filename);
|
|
553
|
+
}
|
|
554
|
+
if (files.length === 0) {
|
|
555
|
+
const implDir = path5.join(workingDir, "src", "features");
|
|
556
|
+
await fs4.mkdir(implDir, { recursive: true });
|
|
557
|
+
const featureName = session.specItems[0]?.title || "feature";
|
|
558
|
+
const fileName = `${featureName.replace(/[^a-zA-Z0-9]/g, "_")}.ts`;
|
|
559
|
+
const filePath = path5.join(implDir, fileName);
|
|
560
|
+
const stubCode = `/**
|
|
561
|
+
* ${session.requirement}
|
|
562
|
+
*
|
|
563
|
+
* TODO: \u6B64\u6587\u4EF6\u7531 AI \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u6839\u636E\u9700\u6C42\u5B8C\u5584\u5B9E\u73B0
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
567
|
+
// TODO: \u5B9E\u73B0\u529F\u80FD
|
|
568
|
+
console.log('${featureName} - \u5F85\u5B9E\u73B0');
|
|
569
|
+
}
|
|
570
|
+
`;
|
|
571
|
+
await fs4.writeFile(filePath, stubCode, "utf-8");
|
|
572
|
+
files.push(`src/features/${fileName}`);
|
|
573
|
+
}
|
|
574
|
+
return { success: true, files };
|
|
575
|
+
} catch (error) {
|
|
576
|
+
return {
|
|
577
|
+
success: false,
|
|
578
|
+
files: [],
|
|
579
|
+
error: error.message
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function buildDevelopmentPrompt(session) {
|
|
584
|
+
const lines = [];
|
|
585
|
+
lines.push("## \u9700\u6C42\u63CF\u8FF0");
|
|
586
|
+
lines.push(session.refinedRequirement);
|
|
587
|
+
lines.push("");
|
|
588
|
+
lines.push("## BDD \u573A\u666F");
|
|
589
|
+
for (const scenario of session.bddScenarios) {
|
|
590
|
+
lines.push(`### ${scenario.feature}`);
|
|
591
|
+
for (const s of scenario.scenarios) {
|
|
592
|
+
lines.push(`- ${s.name}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
lines.push("");
|
|
596
|
+
lines.push("## \u4EFB\u52A1\u5217\u8868");
|
|
597
|
+
for (const item of session.specItems) {
|
|
598
|
+
lines.push(`- [${item.id}] ${item.title}: ${item.description}`);
|
|
599
|
+
}
|
|
600
|
+
lines.push("");
|
|
601
|
+
lines.push("\u8BF7\u6839\u636E\u4EE5\u4E0A\u9700\u6C42\u89C4\u683C\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002");
|
|
602
|
+
return lines.join("\n");
|
|
603
|
+
}
|
|
604
|
+
function parseCodeBlocks(content) {
|
|
605
|
+
const blocks = [];
|
|
606
|
+
const regex = /```(\S+)\n([\s\S]*?)```/g;
|
|
607
|
+
let match;
|
|
608
|
+
while ((match = regex.exec(content)) !== null) {
|
|
609
|
+
const filename = match[1];
|
|
610
|
+
const code = match[2].trim();
|
|
611
|
+
if (["text", "json", "markdown", "md"].includes(filename.toLowerCase())) {
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
blocks.push({ filename, code });
|
|
615
|
+
}
|
|
616
|
+
return blocks;
|
|
617
|
+
}
|
|
618
|
+
async function executeReview(ctx, session) {
|
|
619
|
+
const workingDir = ctx.options.workingDirectory;
|
|
620
|
+
const issues = [];
|
|
621
|
+
const suggestions = [];
|
|
622
|
+
try {
|
|
623
|
+
const codeContents = [];
|
|
624
|
+
for (const file of session.implFiles) {
|
|
625
|
+
try {
|
|
626
|
+
const content = await fs4.readFile(path5.join(workingDir, file), "utf-8");
|
|
627
|
+
codeContents.push(`// ${file}
|
|
628
|
+
${content}`);
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const testContents = [];
|
|
633
|
+
for (const file of session.testFiles) {
|
|
634
|
+
try {
|
|
635
|
+
const content = await fs4.readFile(path5.join(workingDir, file), "utf-8");
|
|
636
|
+
testContents.push(`// ${file}
|
|
637
|
+
${content}`);
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
const messages = [
|
|
642
|
+
{
|
|
643
|
+
role: "system",
|
|
644
|
+
content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u4EE3\u7801\u5BA1\u6838\u4E13\u5BB6\u3002\u8BF7\u5BA1\u6838\u4EE5\u4E0B\u4EE3\u7801\u5B9E\u73B0\u662F\u5426\u7B26\u5408\u9700\u6C42\u89C4\u683C\u3002
|
|
645
|
+
|
|
646
|
+
\u5BA1\u6838\u6807\u51C6\uFF1A
|
|
647
|
+
1. \u4EE3\u7801\u662F\u5426\u6B63\u786E\u5B9E\u73B0\u4E86\u9700\u6C42\u89C4\u683C\u4E2D\u7684\u529F\u80FD
|
|
648
|
+
2. \u4EE3\u7801\u8D28\u91CF\uFF08\u53EF\u8BFB\u6027\u3001\u53EF\u7EF4\u62A4\u6027\uFF09
|
|
649
|
+
3. \u6F5C\u5728\u7684 bug \u548C\u8FB9\u754C\u60C5\u51B5\u5904\u7406
|
|
650
|
+
4. \u4EE3\u7801\u98CE\u683C\u662F\u5426\u7B26\u5408\u9879\u76EE\u89C4\u8303
|
|
651
|
+
5. \u6D4B\u8BD5\u8986\u76D6\u662F\u5426\u5145\u5206
|
|
652
|
+
|
|
653
|
+
\u8FD4\u56DE\u683C\u5F0F\uFF1A
|
|
654
|
+
- \u5982\u679C\u901A\u8FC7\u5BA1\u6838\uFF0C\u8FD4\u56DE "\u5BA1\u6838\u901A\u8FC7" \u5E76\u5217\u51FA\u6539\u8FDB\u5EFA\u8BAE
|
|
655
|
+
- \u5982\u679C\u4E0D\u901A\u8FC7\uFF0C\u5217\u51FA\u5177\u4F53\u95EE\u9898
|
|
656
|
+
|
|
657
|
+
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
658
|
+
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
659
|
+
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
660
|
+
|
|
661
|
+
${session.context?.devStandards ? `\u5F00\u53D1\u89C4\u8303\uFF1A
|
|
662
|
+
${session.context.devStandards.slice(0, 1e3)}` : ""}`
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
role: "user",
|
|
666
|
+
content: `## \u9700\u6C42\u89C4\u683C
|
|
667
|
+
${session.refinedRequirement}
|
|
668
|
+
|
|
669
|
+
## \u4EFB\u52A1\u5217\u8868
|
|
670
|
+
${session.specItems.map((item) => `- [${item.id}] ${item.title}`).join("\n")}
|
|
671
|
+
|
|
672
|
+
## \u5B9E\u73B0\u4EE3\u7801
|
|
673
|
+
${codeContents.join("\n\n") || "\uFF08\u65E0\u4EE3\u7801\u6587\u4EF6\uFF09"}
|
|
674
|
+
|
|
675
|
+
## \u6D4B\u8BD5\u4EE3\u7801
|
|
676
|
+
${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
|
|
677
|
+
|
|
678
|
+
\u8BF7\u5BA1\u6838\u4EE5\u4E0A\u4EE3\u7801\u5B9E\u73B0\u3002`
|
|
679
|
+
}
|
|
680
|
+
];
|
|
681
|
+
const response = await ctx.modelService.sendMessage(messages, {
|
|
682
|
+
temperature: 0.2,
|
|
683
|
+
maxTokens: 2e3,
|
|
684
|
+
agent: "code-reviewer"
|
|
685
|
+
});
|
|
686
|
+
const result = response.content;
|
|
687
|
+
const passed = result.includes("\u5BA1\u6838\u901A\u8FC7") || result.includes("\u901A\u8FC7") || !result.includes("\u4E0D\u901A\u8FC7");
|
|
688
|
+
const issueMatches = result.match(/问题[::]\s*([\s\S]*?)(?=建议|$)/i);
|
|
689
|
+
if (issueMatches) {
|
|
690
|
+
const issueList = issueMatches[1].split(/[\n-]/).filter((s) => s.trim());
|
|
691
|
+
issues.push(...issueList.map((s) => s.trim()).filter((s) => s));
|
|
692
|
+
}
|
|
693
|
+
const suggestionMatches = result.match(/建议[::]\s*([\s\S]*?)$/i);
|
|
694
|
+
if (suggestionMatches) {
|
|
695
|
+
const suggestionList = suggestionMatches[1].split(/[\n-]/).filter((s) => s.trim());
|
|
696
|
+
suggestions.push(...suggestionList.map((s) => s.trim()).filter((s) => s));
|
|
697
|
+
}
|
|
698
|
+
if (issues.length === 0 && !passed) {
|
|
699
|
+
const lines = result.split("\n").filter((l) => l.includes("\u95EE\u9898") || l.includes("\u9519\u8BEF") || l.includes("\u7F3A\u9677"));
|
|
700
|
+
issues.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
|
|
701
|
+
}
|
|
702
|
+
if (suggestions.length === 0) {
|
|
703
|
+
const lines = result.split("\n").filter((l) => l.includes("\u5EFA\u8BAE") || l.includes("\u6539\u8FDB") || l.includes("\u4F18\u5316"));
|
|
704
|
+
suggestions.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
|
|
705
|
+
}
|
|
706
|
+
return { passed, issues, suggestions };
|
|
707
|
+
} catch (error) {
|
|
708
|
+
suggestions.push(`\u5BA1\u6838\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
|
|
709
|
+
return { passed: true, issues, suggestions };
|
|
710
|
+
}
|
|
711
|
+
}
|
|
248
712
|
async function readProjectContext(workingDir) {
|
|
249
713
|
const context = {
|
|
250
714
|
name: path5.basename(workingDir),
|
|
@@ -326,8 +790,11 @@ function analyzeComplexity(requirement, context) {
|
|
|
326
790
|
if (!context.framework) score += 0.5;
|
|
327
791
|
return Math.max(1, Math.min(10, Math.round(score)));
|
|
328
792
|
}
|
|
329
|
-
function generateBDDScenarios(requirement, context) {
|
|
793
|
+
function generateBDDScenarios(requirement, context, questions) {
|
|
330
794
|
const scenarios = [];
|
|
795
|
+
questions.find((q) => q.category === "ui" && q.answered)?.answer;
|
|
796
|
+
const interactionAnswer = questions.find((q) => q.category === "interaction" && q.answered)?.answer;
|
|
797
|
+
const edgeAnswer = questions.find((q) => q.category === "edge" && q.answered)?.answer;
|
|
331
798
|
const features = extractFeatures(requirement);
|
|
332
799
|
for (const feature of features) {
|
|
333
800
|
const scenario = {
|
|
@@ -341,12 +808,20 @@ function generateBDDScenarios(requirement, context) {
|
|
|
341
808
|
when: [`\u7528\u6237\u6267\u884C "${feature.title}" \u64CD\u4F5C`],
|
|
342
809
|
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5E76\u8FD4\u56DE\u9884\u671F\u7ED3\u679C`]
|
|
343
810
|
});
|
|
344
|
-
if (
|
|
811
|
+
if (interactionAnswer) {
|
|
345
812
|
scenario.scenarios.push({
|
|
346
|
-
name: `\
|
|
347
|
-
given: [`\u7528\u6237\u8FDB\u5165\
|
|
348
|
-
when: [`\u7528\u6237\
|
|
349
|
-
then: [`\u7CFB\u7EDF\u5E94\
|
|
813
|
+
name: `\u4EA4\u4E92\u6D41\u7A0B: \u7528\u6237\u64CD\u4F5C`,
|
|
814
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
815
|
+
when: [`\u7528\u6237\u6309\u7167\u4EE5\u4E0B\u6D41\u7A0B\u64CD\u4F5C: ${interactionAnswer}`],
|
|
816
|
+
then: [`\u7CFB\u7EDF\u54CD\u5E94\u5E76\u5B8C\u6210\u529F\u80FD`]
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
if (feature.hasInput || edgeAnswer) {
|
|
820
|
+
scenario.scenarios.push({
|
|
821
|
+
name: `\u8FB9\u754C\u60C5\u51B5: \u5F02\u5E38\u5904\u7406`,
|
|
822
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
823
|
+
when: [`\u53D1\u751F\u5F02\u5E38\u60C5\u51B5${edgeAnswer ? `: ${edgeAnswer}` : ""}`],
|
|
824
|
+
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5F02\u5E38\u5E76\u7ED9\u51FA\u63D0\u793A`]
|
|
350
825
|
});
|
|
351
826
|
}
|
|
352
827
|
scenarios.push(scenario);
|
|
@@ -393,7 +868,7 @@ function extractFeatures(requirement) {
|
|
|
393
868
|
}
|
|
394
869
|
return features;
|
|
395
870
|
}
|
|
396
|
-
function generateSpecItems(requirement, context, bddScenarios) {
|
|
871
|
+
function generateSpecItems(requirement, context, bddScenarios, questions) {
|
|
397
872
|
const items = [];
|
|
398
873
|
let id = 1;
|
|
399
874
|
for (const scenario of bddScenarios) {
|
|
@@ -430,11 +905,33 @@ function formatSpecFile(session) {
|
|
|
430
905
|
lines.push(`# \u9700\u6C42\u89C4\u683C: ${session.requirement.slice(0, 50)}`);
|
|
431
906
|
lines.push("");
|
|
432
907
|
lines.push(`> \u53D8\u66F4ID: ${session.id}`);
|
|
908
|
+
lines.push(`> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(session.clarityScore * 100)}%`);
|
|
433
909
|
lines.push(`> \u590D\u6742\u5EA6: ${session.complexity}/10`);
|
|
434
910
|
lines.push(`> \u751F\u6210\u65F6\u95F4: ${session.createdAt.toISOString()}`);
|
|
435
911
|
lines.push("");
|
|
436
912
|
lines.push("---");
|
|
437
913
|
lines.push("");
|
|
914
|
+
if (session.refinedRequirement !== session.requirement) {
|
|
915
|
+
lines.push("## \u9700\u6C42\u8BE6\u60C5");
|
|
916
|
+
lines.push("");
|
|
917
|
+
lines.push(session.refinedRequirement);
|
|
918
|
+
lines.push("");
|
|
919
|
+
lines.push("---");
|
|
920
|
+
lines.push("");
|
|
921
|
+
}
|
|
922
|
+
if (session.clarificationQuestions.some((q) => q.answered)) {
|
|
923
|
+
lines.push("## \u9700\u6C42\u6F84\u6E05");
|
|
924
|
+
lines.push("");
|
|
925
|
+
for (const q of session.clarificationQuestions) {
|
|
926
|
+
if (q.answered) {
|
|
927
|
+
lines.push(`**Q: ${q.question}**`);
|
|
928
|
+
lines.push(`A: ${q.answer}`);
|
|
929
|
+
lines.push("");
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
lines.push("---");
|
|
933
|
+
lines.push("");
|
|
934
|
+
}
|
|
438
935
|
lines.push("## BDD \u573A\u666F");
|
|
439
936
|
lines.push("");
|
|
440
937
|
for (const scenario of session.bddScenarios) {
|
|
@@ -498,11 +995,17 @@ async function archiveWorkflow(workingDir) {
|
|
|
498
995
|
const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
|
|
499
996
|
|
|
500
997
|
> \u5F52\u6863\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
998
|
+
> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(activeSession.clarityScore * 100)}%
|
|
501
999
|
> \u590D\u6742\u5EA6: ${activeSession.complexity}/10
|
|
502
1000
|
|
|
1001
|
+
## \u9700\u6C42\u8BE6\u60C5
|
|
1002
|
+
|
|
1003
|
+
${activeSession.refinedRequirement}
|
|
1004
|
+
|
|
503
1005
|
## \u5B8C\u6210\u60C5\u51B5
|
|
504
1006
|
|
|
505
1007
|
- [x] \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6
|
|
1008
|
+
- [x] \u9700\u6C42\u6F84\u6E05
|
|
506
1009
|
- [x] \u590D\u6742\u5EA6\u8BC4\u4F30
|
|
507
1010
|
- [x] BDD \u573A\u666F\u62C6\u89E3
|
|
508
1011
|
- [x] OpenSpec \u89C4\u683C
|
|
@@ -529,6 +1032,7 @@ function generateComplexityBar(score) {
|
|
|
529
1032
|
function getPhaseLabel(phase) {
|
|
530
1033
|
const labels = {
|
|
531
1034
|
context: "\u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6",
|
|
1035
|
+
clarify: "\u9700\u6C42\u6F84\u6E05",
|
|
532
1036
|
analysis: "\u590D\u6742\u5EA6\u8BC4\u4F30",
|
|
533
1037
|
bdd: "BDD \u573A\u666F\u62C6\u89E3",
|
|
534
1038
|
spec: "OpenSpec \u89C4\u683C",
|
|
@@ -544,12 +1048,13 @@ function getActiveSession() {
|
|
|
544
1048
|
function clearActiveSession() {
|
|
545
1049
|
activeSession = null;
|
|
546
1050
|
}
|
|
547
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, activeSession, new_default;
|
|
1051
|
+
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
548
1052
|
var init_new = __esm({
|
|
549
1053
|
"src/commands/new.ts"() {
|
|
550
1054
|
init_esm_shims();
|
|
551
1055
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
552
1056
|
COMPLEXITY_THRESHOLD = 6;
|
|
1057
|
+
CLARITY_THRESHOLD = 0.6;
|
|
553
1058
|
activeSession = null;
|
|
554
1059
|
new_default = handleNew;
|
|
555
1060
|
}
|