@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/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 === "spec") {
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/7: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
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 2/7: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
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(activeSession.requirement, activeSession.context);
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 3/7: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
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(activeSession.requirement, activeSession.context);
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 4/7: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
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(activeSession.requirement, activeSession.context, activeSession.bddScenarios);
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 5/7: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
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 6/7: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
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 7/7: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
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(activeSession.requirement, activeSession.context);
215
- activeSession.specItems = generateSpecItems(activeSession.requirement, activeSession.context, activeSession.bddScenarios);
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.requirement;
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}`) + chalk9.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
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 (feature.hasInput) {
555
+ if (interactionAnswer) {
345
556
  scenario.scenarios.push({
346
- name: `\u8FB9\u754C\u60C5\u51B5: \u8F93\u5165\u9A8C\u8BC1`,
347
- given: [`\u7528\u6237\u8FDB\u5165\u8F93\u5165\u754C\u9762`],
348
- when: [`\u7528\u6237\u8F93\u5165\u8FB9\u754C\u503C\u6216\u7A7A\u503C`],
349
- then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u8FB9\u754C\u60C5\u51B5`]
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
  }