@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.d.mts
CHANGED
|
@@ -408,7 +408,7 @@ interface CLIConfig {
|
|
|
408
408
|
theme: 'light' | 'dark' | 'auto';
|
|
409
409
|
}
|
|
410
410
|
type WorkflowStep = 'explore' | 'new' | 'continue' | 'apply' | 'archive' | 'propose';
|
|
411
|
-
type WorkflowPhase = 'context' | 'analysis' | 'bdd' | 'spec' | 'tdd' | 'develop' | 'review';
|
|
411
|
+
type WorkflowPhase = 'context' | 'clarify' | 'analysis' | 'bdd' | 'spec' | 'tdd' | 'develop' | 'review';
|
|
412
412
|
type WorkflowType = 'complex' | 'simple';
|
|
413
413
|
type WorkflowStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
414
414
|
interface WorkflowState {
|
package/dist/index.d.ts
CHANGED
|
@@ -408,7 +408,7 @@ interface CLIConfig {
|
|
|
408
408
|
theme: 'light' | 'dark' | 'auto';
|
|
409
409
|
}
|
|
410
410
|
type WorkflowStep = 'explore' | 'new' | 'continue' | 'apply' | 'archive' | 'propose';
|
|
411
|
-
type WorkflowPhase = 'context' | 'analysis' | 'bdd' | 'spec' | 'tdd' | 'develop' | 'review';
|
|
411
|
+
type WorkflowPhase = 'context' | 'clarify' | 'analysis' | 'bdd' | 'spec' | 'tdd' | 'develop' | 'review';
|
|
412
412
|
type WorkflowType = 'complex' | 'simple';
|
|
413
413
|
type WorkflowStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
414
414
|
interface WorkflowState {
|
package/dist/index.js
CHANGED
|
@@ -73,14 +73,17 @@ async function handleNew(args, ctx) {
|
|
|
73
73
|
const requirement = args.join(" ").trim();
|
|
74
74
|
if (!requirement) {
|
|
75
75
|
return {
|
|
76
|
-
output: chalk9__default.default.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9__default.default.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>")
|
|
76
|
+
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")
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
79
|
activeSession = {
|
|
80
80
|
id: generateSessionId(),
|
|
81
81
|
requirement,
|
|
82
|
+
refinedRequirement: requirement,
|
|
82
83
|
phase: "context",
|
|
83
84
|
context: null,
|
|
85
|
+
clarityScore: 0,
|
|
86
|
+
clarificationQuestions: [],
|
|
84
87
|
complexity: 0,
|
|
85
88
|
bddScenarios: [],
|
|
86
89
|
specItems: [],
|
|
@@ -98,10 +101,13 @@ function handleActiveSession(ctx) {
|
|
|
98
101
|
const lines = [];
|
|
99
102
|
lines.push(chalk9__default.default.cyan("\u{1F4CB} \u5F53\u524D\u5DE5\u4F5C\u6D41\u72B6\u6001"));
|
|
100
103
|
lines.push("");
|
|
101
|
-
lines.push(chalk9__default.default.white(`\u9700\u6C42: ${activeSession.requirement}`));
|
|
104
|
+
lines.push(chalk9__default.default.white(`\u9700\u6C42: ${activeSession.requirement.slice(0, 60)}${activeSession.requirement.length > 60 ? "..." : ""}`));
|
|
102
105
|
lines.push(chalk9__default.default.gray(`\u9636\u6BB5: ${getPhaseLabel(activeSession.phase)}`));
|
|
103
106
|
lines.push("");
|
|
104
|
-
if (activeSession.phase === "
|
|
107
|
+
if (activeSession.phase === "clarify") {
|
|
108
|
+
lines.push(chalk9__default.default.yellow("\u23F8\uFE0F \u7B49\u5F85\u9700\u6C42\u6F84\u6E05"));
|
|
109
|
+
lines.push(chalk9__default.default.gray('\u8BF7\u56DE\u7B54\u4E0A\u8FF0\u95EE\u9898\uFF0C\u6216\u8F93\u5165 "done" \u8868\u793A\u56DE\u7B54\u5B8C\u6210'));
|
|
110
|
+
} else if (activeSession.phase === "spec") {
|
|
105
111
|
lines.push(chalk9__default.default.yellow("\u23F8\uFE0F \u7B49\u5F85\u89C4\u683C\u786E\u8BA4"));
|
|
106
112
|
lines.push("");
|
|
107
113
|
lines.push(chalk9__default.default.green(" y - \u786E\u8BA4\u89C4\u683C\uFF0C\u7EE7\u7EED\u5DE5\u4F5C\u6D41"));
|
|
@@ -120,7 +126,7 @@ async function executeWorkflow(ctx) {
|
|
|
120
126
|
const lines = [];
|
|
121
127
|
try {
|
|
122
128
|
if (activeSession.phase === "context") {
|
|
123
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/
|
|
129
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/8: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
|
|
124
130
|
lines.push("");
|
|
125
131
|
activeSession.context = await readProjectContext(ctx.options.workingDirectory);
|
|
126
132
|
lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${activeSession.context.name}`));
|
|
@@ -130,13 +136,46 @@ async function executeWorkflow(ctx) {
|
|
|
130
136
|
if (activeSession.context.devStandards) {
|
|
131
137
|
lines.push(chalk9__default.default.green(" \u2713 \u5DF2\u8BFB\u53D6\u5F00\u53D1\u89C4\u8303"));
|
|
132
138
|
}
|
|
139
|
+
activeSession.phase = "clarify";
|
|
140
|
+
}
|
|
141
|
+
if (activeSession.phase === "clarify") {
|
|
142
|
+
lines.push("");
|
|
143
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/8: \u9700\u6C42\u6F84\u6E05 \u2501\u2501\u2501"));
|
|
144
|
+
lines.push("");
|
|
145
|
+
const clarityResult = analyzeRequirementClarity(
|
|
146
|
+
activeSession.requirement,
|
|
147
|
+
activeSession.context
|
|
148
|
+
);
|
|
149
|
+
activeSession.clarityScore = clarityResult.score;
|
|
150
|
+
activeSession.clarificationQuestions = clarityResult.questions;
|
|
151
|
+
lines.push(chalk9__default.default.gray(` \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(clarityResult.score * 100)}%`));
|
|
152
|
+
lines.push("");
|
|
153
|
+
if (clarityResult.score < CLARITY_THRESHOLD && clarityResult.questions.length > 0) {
|
|
154
|
+
lines.push(chalk9__default.default.yellow(" \u9700\u6C42\u4E0D\u591F\u660E\u786E\uFF0C\u8BF7\u8865\u5145\u4EE5\u4E0B\u4FE1\u606F\uFF1A"));
|
|
155
|
+
lines.push("");
|
|
156
|
+
const unansweredQuestions = clarityResult.questions.filter((q) => !q.answered);
|
|
157
|
+
for (let i = 0; i < Math.min(unansweredQuestions.length, 3); i++) {
|
|
158
|
+
const q = unansweredQuestions[i];
|
|
159
|
+
lines.push(chalk9__default.default.white(` ${i + 1}. ${q.question}`));
|
|
160
|
+
}
|
|
161
|
+
if (unansweredQuestions.length > 3) {
|
|
162
|
+
lines.push(chalk9__default.default.gray(` ... \u8FD8\u6709 ${unansweredQuestions.length - 3} \u4E2A\u95EE\u9898`));
|
|
163
|
+
}
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push(chalk9__default.default.gray(' \u8BF7\u8F93\u5165\u56DE\u7B54\uFF0C\u6216\u8F93\u5165 "done" \u8DF3\u8FC7\u6F84\u6E05'));
|
|
166
|
+
return { output: lines.join("\n") };
|
|
167
|
+
}
|
|
168
|
+
lines.push(chalk9__default.default.green(" \u2713 \u9700\u6C42\u6E05\u6670\uFF0C\u7EE7\u7EED\u4E0B\u4E00\u6B65"));
|
|
133
169
|
activeSession.phase = "analysis";
|
|
134
170
|
}
|
|
135
171
|
if (activeSession.phase === "analysis") {
|
|
136
172
|
lines.push("");
|
|
137
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
173
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 3/8: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
|
|
138
174
|
lines.push("");
|
|
139
|
-
activeSession.complexity = analyzeComplexity(
|
|
175
|
+
activeSession.complexity = analyzeComplexity(
|
|
176
|
+
activeSession.refinedRequirement,
|
|
177
|
+
activeSession.context
|
|
178
|
+
);
|
|
140
179
|
const complexityBar = generateComplexityBar(activeSession.complexity);
|
|
141
180
|
lines.push(chalk9__default.default.gray(` \u590D\u6742\u5EA6: ${complexityBar} ${activeSession.complexity}/10`));
|
|
142
181
|
if (activeSession.complexity >= COMPLEXITY_THRESHOLD) {
|
|
@@ -148,9 +187,13 @@ async function executeWorkflow(ctx) {
|
|
|
148
187
|
}
|
|
149
188
|
if (activeSession.phase === "bdd") {
|
|
150
189
|
lines.push("");
|
|
151
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
190
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 4/8: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
152
191
|
lines.push("");
|
|
153
|
-
activeSession.bddScenarios = generateBDDScenarios(
|
|
192
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
193
|
+
activeSession.refinedRequirement,
|
|
194
|
+
activeSession.context,
|
|
195
|
+
activeSession.clarificationQuestions
|
|
196
|
+
);
|
|
154
197
|
for (const scenario of activeSession.bddScenarios) {
|
|
155
198
|
lines.push(chalk9__default.default.white(` Feature: ${scenario.feature}`));
|
|
156
199
|
for (const s of scenario.scenarios.slice(0, 3)) {
|
|
@@ -164,9 +207,14 @@ async function executeWorkflow(ctx) {
|
|
|
164
207
|
}
|
|
165
208
|
if (activeSession.phase === "spec") {
|
|
166
209
|
lines.push("");
|
|
167
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
210
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/8: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
168
211
|
lines.push("");
|
|
169
|
-
activeSession.specItems = generateSpecItems(
|
|
212
|
+
activeSession.specItems = generateSpecItems(
|
|
213
|
+
activeSession.refinedRequirement,
|
|
214
|
+
activeSession.context,
|
|
215
|
+
activeSession.bddScenarios,
|
|
216
|
+
activeSession.clarificationQuestions
|
|
217
|
+
);
|
|
170
218
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
171
219
|
lines.push(chalk9__default.default.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
172
220
|
lines.push(chalk9__default.default.gray(` \u8DEF\u5F84: ${specPath}`));
|
|
@@ -189,7 +237,7 @@ async function executeWorkflow(ctx) {
|
|
|
189
237
|
}
|
|
190
238
|
if (activeSession.phase === "tdd") {
|
|
191
239
|
lines.push("");
|
|
192
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
240
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/8: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
193
241
|
lines.push("");
|
|
194
242
|
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
195
243
|
lines.push(chalk9__default.default.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
@@ -200,7 +248,7 @@ async function executeWorkflow(ctx) {
|
|
|
200
248
|
}
|
|
201
249
|
if (activeSession.phase === "develop") {
|
|
202
250
|
lines.push("");
|
|
203
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
251
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/8: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
|
|
204
252
|
lines.push("");
|
|
205
253
|
lines.push(chalk9__default.default.yellow(" \u{1F4DD} \u5F00\u53D1\u9636\u6BB5"));
|
|
206
254
|
lines.push(chalk9__default.default.gray(" \u8BF7\u8C03\u7528 $frontend-dev \u6267\u884C\u5F00\u53D1\u4EFB\u52A1"));
|
|
@@ -209,7 +257,7 @@ async function executeWorkflow(ctx) {
|
|
|
209
257
|
}
|
|
210
258
|
if (activeSession.phase === "review") {
|
|
211
259
|
lines.push("");
|
|
212
|
-
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
260
|
+
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 8/8: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
|
|
213
261
|
lines.push("");
|
|
214
262
|
lines.push(chalk9__default.default.yellow(" \u{1F50D} \u4EE3\u7801\u5BA1\u6838\u9636\u6BB5"));
|
|
215
263
|
lines.push(chalk9__default.default.gray(" \u8BF7\u8C03\u7528 $code-reviewer \u6267\u884C\u4EE3\u7801\u5BA1\u6838"));
|
|
@@ -230,14 +278,58 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
230
278
|
output: chalk9__default.default.yellow("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u53D6\u6D88")
|
|
231
279
|
};
|
|
232
280
|
}
|
|
281
|
+
if (activeSession.phase === "clarify") {
|
|
282
|
+
if (trimmed === "done" || trimmed === "\u5B8C\u6210" || trimmed === "\u8DF3\u8FC7" || trimmed === "skip") {
|
|
283
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
284
|
+
activeSession.phase = "analysis";
|
|
285
|
+
return executeWorkflow(ctx);
|
|
286
|
+
}
|
|
287
|
+
activeSession.clarificationQuestions.filter((q) => q.answered).length;
|
|
288
|
+
const unansweredQuestions = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
289
|
+
if (unansweredQuestions.length > 0) {
|
|
290
|
+
const question = unansweredQuestions[0];
|
|
291
|
+
question.answer = input.trim();
|
|
292
|
+
question.answered = true;
|
|
293
|
+
activeSession.refinedRequirement = buildRefinedRequirement(activeSession);
|
|
294
|
+
const remaining = activeSession.clarificationQuestions.filter((q) => !q.answered);
|
|
295
|
+
if (remaining.length > 0) {
|
|
296
|
+
activeSession.clarityScore = calculateClarityScore(activeSession.clarificationQuestions);
|
|
297
|
+
const lines = [];
|
|
298
|
+
lines.push(chalk9__default.default.green(" \u2713 \u5DF2\u8BB0\u5F55"));
|
|
299
|
+
lines.push("");
|
|
300
|
+
lines.push(chalk9__default.default.yellow(" \u7EE7\u7EED\u56DE\u7B54\uFF1A"));
|
|
301
|
+
for (let i = 0; i < Math.min(remaining.length, 3); i++) {
|
|
302
|
+
const q = remaining[i];
|
|
303
|
+
lines.push(chalk9__default.default.white(` ${i + 1}. ${q.question}`));
|
|
304
|
+
}
|
|
305
|
+
lines.push("");
|
|
306
|
+
lines.push(chalk9__default.default.gray(' \u8F93\u5165\u56DE\u7B54\uFF0C\u6216 "done" \u8DF3\u8FC7'));
|
|
307
|
+
return { output: lines.join("\n") };
|
|
308
|
+
}
|
|
309
|
+
activeSession.clarityScore = 1;
|
|
310
|
+
activeSession.phase = "analysis";
|
|
311
|
+
return executeWorkflow(ctx);
|
|
312
|
+
}
|
|
313
|
+
activeSession.phase = "analysis";
|
|
314
|
+
return executeWorkflow(ctx);
|
|
315
|
+
}
|
|
233
316
|
if (activeSession.phase === "spec") {
|
|
234
317
|
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
|
|
235
318
|
activeSession.phase = "tdd";
|
|
236
319
|
return executeWorkflow(ctx);
|
|
237
320
|
}
|
|
238
321
|
if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
|
|
239
|
-
activeSession.bddScenarios = generateBDDScenarios(
|
|
240
|
-
|
|
322
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
323
|
+
activeSession.refinedRequirement,
|
|
324
|
+
activeSession.context,
|
|
325
|
+
activeSession.clarificationQuestions
|
|
326
|
+
);
|
|
327
|
+
activeSession.specItems = generateSpecItems(
|
|
328
|
+
activeSession.refinedRequirement,
|
|
329
|
+
activeSession.context,
|
|
330
|
+
activeSession.bddScenarios,
|
|
331
|
+
activeSession.clarificationQuestions
|
|
332
|
+
);
|
|
241
333
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
242
334
|
return {
|
|
243
335
|
output: chalk9__default.default.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9__default.default.gray(`
|
|
@@ -254,11 +346,11 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
254
346
|
if (activeSession.phase === "review") {
|
|
255
347
|
if (trimmed === "review" || trimmed === "\u5BA1\u6838" || trimmed === "pass" || trimmed === "\u901A\u8FC7") {
|
|
256
348
|
await archiveWorkflow(ctx.options.workingDirectory);
|
|
257
|
-
const summary = activeSession.
|
|
349
|
+
const summary = activeSession.refinedRequirement;
|
|
258
350
|
activeSession = null;
|
|
259
351
|
return {
|
|
260
352
|
output: chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5B8C\u6210") + chalk9__default.default.gray(`
|
|
261
|
-
\u9700\u6C42: ${summary}
|
|
353
|
+
\u9700\u6C42: ${summary.slice(0, 60)}...`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /new <\u9700\u6C42> \u5F00\u59CB\u65B0\u7684\u5DE5\u4F5C\u6D41")
|
|
262
354
|
};
|
|
263
355
|
}
|
|
264
356
|
if (trimmed === "fail" || trimmed === "\u5931\u8D25" || trimmed === "reject" || trimmed === "\u62D2\u7EDD") {
|
|
@@ -270,6 +362,122 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
270
362
|
}
|
|
271
363
|
return null;
|
|
272
364
|
}
|
|
365
|
+
function analyzeRequirementClarity(requirement, context) {
|
|
366
|
+
const questions = [];
|
|
367
|
+
let score = 0.5;
|
|
368
|
+
if (requirement.length < 10) {
|
|
369
|
+
score -= 0.2;
|
|
370
|
+
questions.push({
|
|
371
|
+
id: "q-length",
|
|
372
|
+
question: "\u9700\u6C42\u63CF\u8FF0\u8F83\u77ED\uFF0C\u80FD\u5426\u8BE6\u7EC6\u8BF4\u660E\u5177\u4F53\u8981\u5B9E\u73B0\u4EC0\u4E48\u529F\u80FD\uFF1F",
|
|
373
|
+
category: "scope",
|
|
374
|
+
answered: false
|
|
375
|
+
});
|
|
376
|
+
} else if (requirement.length >= 50) {
|
|
377
|
+
score += 0.1;
|
|
378
|
+
}
|
|
379
|
+
const actionKeywords = ["\u5B9E\u73B0", "\u6DFB\u52A0", "\u4FEE\u6539", "\u5220\u9664", "\u4F18\u5316", "\u4FEE\u590D", "\u91CD\u6784", "\u5F00\u53D1", "\u521B\u5EFA", "\u8BBE\u8BA1"];
|
|
380
|
+
const hasAction = actionKeywords.some((kw) => requirement.includes(kw));
|
|
381
|
+
if (!hasAction) {
|
|
382
|
+
score -= 0.15;
|
|
383
|
+
questions.push({
|
|
384
|
+
id: "q-action",
|
|
385
|
+
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",
|
|
386
|
+
category: "scope",
|
|
387
|
+
answered: false
|
|
388
|
+
});
|
|
389
|
+
} else {
|
|
390
|
+
score += 0.1;
|
|
391
|
+
}
|
|
392
|
+
if (requirement.match(/界面|页面|组件|按钮|表单|弹窗|布局|样式|UI/)) {
|
|
393
|
+
score += 0.1;
|
|
394
|
+
if (!requirement.match(/在.*页面|在.*位置|显示在|位于/)) {
|
|
395
|
+
questions.push({
|
|
396
|
+
id: "q-ui-position",
|
|
397
|
+
question: "\u8FD9\u4E2A\u529F\u80FD\u5E94\u8BE5\u653E\u5728\u54EA\u4E2A\u9875\u9762\u6216\u4F4D\u7F6E\uFF1F",
|
|
398
|
+
category: "ui",
|
|
399
|
+
answered: false
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
questions.push({
|
|
404
|
+
id: "q-ui-need",
|
|
405
|
+
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",
|
|
406
|
+
category: "ui",
|
|
407
|
+
answered: false
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (requirement.match(/数据|存储|保存|读取|API|接口|数据库|缓存/)) {
|
|
411
|
+
score += 0.1;
|
|
412
|
+
if (!requirement.match(/从.*获取|调用.*接口|读取.*数据|来源/)) {
|
|
413
|
+
questions.push({
|
|
414
|
+
id: "q-data-source",
|
|
415
|
+
question: "\u6570\u636E\u4ECE\u54EA\u91CC\u6765\uFF1F\u662F\u8C03\u7528API\u3001\u672C\u5730\u5B58\u50A8\u8FD8\u662F\u5176\u4ED6\u6765\u6E90\uFF1F",
|
|
416
|
+
category: "data",
|
|
417
|
+
answered: false
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (requirement.match(/点击|输入|选择|拖动|滑动|交互|操作/)) {
|
|
422
|
+
score += 0.1;
|
|
423
|
+
} else {
|
|
424
|
+
if (hasAction && requirement.match(/功能|特性|模块/)) {
|
|
425
|
+
questions.push({
|
|
426
|
+
id: "q-interaction",
|
|
427
|
+
question: "\u7528\u6237\u5982\u4F55\u64CD\u4F5C\u8FD9\u4E2A\u529F\u80FD\uFF1F\u6709\u4EC0\u4E48\u4EA4\u4E92\u6D41\u7A0B\uFF1F",
|
|
428
|
+
category: "interaction",
|
|
429
|
+
answered: false
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (requirement.match(/异常|错误|失败|边界|特殊情况|空值|验证/)) {
|
|
434
|
+
score += 0.15;
|
|
435
|
+
} else {
|
|
436
|
+
if (requirement.match(/功能|输入|表单|数据/)) {
|
|
437
|
+
questions.push({
|
|
438
|
+
id: "q-edge",
|
|
439
|
+
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",
|
|
440
|
+
category: "edge",
|
|
441
|
+
answered: false
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (requirement.match(/https?:\/\/|参考|参照|类似/)) {
|
|
446
|
+
score += 0.15;
|
|
447
|
+
}
|
|
448
|
+
if (context.framework) {
|
|
449
|
+
score += 0.05;
|
|
450
|
+
}
|
|
451
|
+
const limitedQuestions = questions.slice(0, 5);
|
|
452
|
+
score = Math.max(0, Math.min(1, score));
|
|
453
|
+
return { score, questions: limitedQuestions };
|
|
454
|
+
}
|
|
455
|
+
function calculateClarityScore(questions) {
|
|
456
|
+
const answered = questions.filter((q) => q.answered).length;
|
|
457
|
+
if (questions.length === 0) return 1;
|
|
458
|
+
return 0.5 + answered / questions.length * 0.5;
|
|
459
|
+
}
|
|
460
|
+
function buildRefinedRequirement(session) {
|
|
461
|
+
const parts = [session.requirement];
|
|
462
|
+
for (const q of session.clarificationQuestions) {
|
|
463
|
+
if (q.answered && q.answer) {
|
|
464
|
+
parts.push(`
|
|
465
|
+
\u3010${getCategoryLabel(q.category)}\u3011${q.answer}`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return parts.join("");
|
|
469
|
+
}
|
|
470
|
+
function getCategoryLabel(category) {
|
|
471
|
+
const labels = {
|
|
472
|
+
scope: "\u8303\u56F4",
|
|
473
|
+
ui: "\u754C\u9762",
|
|
474
|
+
data: "\u6570\u636E",
|
|
475
|
+
interaction: "\u4EA4\u4E92",
|
|
476
|
+
edge: "\u8FB9\u754C",
|
|
477
|
+
tech: "\u6280\u672F"
|
|
478
|
+
};
|
|
479
|
+
return labels[category] || category;
|
|
480
|
+
}
|
|
273
481
|
async function readProjectContext(workingDir) {
|
|
274
482
|
const context = {
|
|
275
483
|
name: path4__namespace.basename(workingDir),
|
|
@@ -351,8 +559,11 @@ function analyzeComplexity(requirement, context) {
|
|
|
351
559
|
if (!context.framework) score += 0.5;
|
|
352
560
|
return Math.max(1, Math.min(10, Math.round(score)));
|
|
353
561
|
}
|
|
354
|
-
function generateBDDScenarios(requirement, context) {
|
|
562
|
+
function generateBDDScenarios(requirement, context, questions) {
|
|
355
563
|
const scenarios = [];
|
|
564
|
+
questions.find((q) => q.category === "ui" && q.answered)?.answer;
|
|
565
|
+
const interactionAnswer = questions.find((q) => q.category === "interaction" && q.answered)?.answer;
|
|
566
|
+
const edgeAnswer = questions.find((q) => q.category === "edge" && q.answered)?.answer;
|
|
356
567
|
const features = extractFeatures(requirement);
|
|
357
568
|
for (const feature of features) {
|
|
358
569
|
const scenario = {
|
|
@@ -366,12 +577,20 @@ function generateBDDScenarios(requirement, context) {
|
|
|
366
577
|
when: [`\u7528\u6237\u6267\u884C "${feature.title}" \u64CD\u4F5C`],
|
|
367
578
|
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5E76\u8FD4\u56DE\u9884\u671F\u7ED3\u679C`]
|
|
368
579
|
});
|
|
369
|
-
if (
|
|
580
|
+
if (interactionAnswer) {
|
|
370
581
|
scenario.scenarios.push({
|
|
371
|
-
name: `\
|
|
372
|
-
given: [`\u7528\u6237\u8FDB\u5165\
|
|
373
|
-
when: [`\u7528\u6237\
|
|
374
|
-
then: [`\u7CFB\u7EDF\u5E94\
|
|
582
|
+
name: `\u4EA4\u4E92\u6D41\u7A0B: \u7528\u6237\u64CD\u4F5C`,
|
|
583
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
584
|
+
when: [`\u7528\u6237\u6309\u7167\u4EE5\u4E0B\u6D41\u7A0B\u64CD\u4F5C: ${interactionAnswer}`],
|
|
585
|
+
then: [`\u7CFB\u7EDF\u54CD\u5E94\u5E76\u5B8C\u6210\u529F\u80FD`]
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
if (feature.hasInput || edgeAnswer) {
|
|
589
|
+
scenario.scenarios.push({
|
|
590
|
+
name: `\u8FB9\u754C\u60C5\u51B5: \u5F02\u5E38\u5904\u7406`,
|
|
591
|
+
given: [`\u7528\u6237\u8FDB\u5165\u529F\u80FD\u754C\u9762`],
|
|
592
|
+
when: [`\u53D1\u751F\u5F02\u5E38\u60C5\u51B5${edgeAnswer ? `: ${edgeAnswer}` : ""}`],
|
|
593
|
+
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5F02\u5E38\u5E76\u7ED9\u51FA\u63D0\u793A`]
|
|
375
594
|
});
|
|
376
595
|
}
|
|
377
596
|
scenarios.push(scenario);
|
|
@@ -418,7 +637,7 @@ function extractFeatures(requirement) {
|
|
|
418
637
|
}
|
|
419
638
|
return features;
|
|
420
639
|
}
|
|
421
|
-
function generateSpecItems(requirement, context, bddScenarios) {
|
|
640
|
+
function generateSpecItems(requirement, context, bddScenarios, questions) {
|
|
422
641
|
const items = [];
|
|
423
642
|
let id = 1;
|
|
424
643
|
for (const scenario of bddScenarios) {
|
|
@@ -455,11 +674,33 @@ function formatSpecFile(session) {
|
|
|
455
674
|
lines.push(`# \u9700\u6C42\u89C4\u683C: ${session.requirement.slice(0, 50)}`);
|
|
456
675
|
lines.push("");
|
|
457
676
|
lines.push(`> \u53D8\u66F4ID: ${session.id}`);
|
|
677
|
+
lines.push(`> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(session.clarityScore * 100)}%`);
|
|
458
678
|
lines.push(`> \u590D\u6742\u5EA6: ${session.complexity}/10`);
|
|
459
679
|
lines.push(`> \u751F\u6210\u65F6\u95F4: ${session.createdAt.toISOString()}`);
|
|
460
680
|
lines.push("");
|
|
461
681
|
lines.push("---");
|
|
462
682
|
lines.push("");
|
|
683
|
+
if (session.refinedRequirement !== session.requirement) {
|
|
684
|
+
lines.push("## \u9700\u6C42\u8BE6\u60C5");
|
|
685
|
+
lines.push("");
|
|
686
|
+
lines.push(session.refinedRequirement);
|
|
687
|
+
lines.push("");
|
|
688
|
+
lines.push("---");
|
|
689
|
+
lines.push("");
|
|
690
|
+
}
|
|
691
|
+
if (session.clarificationQuestions.some((q) => q.answered)) {
|
|
692
|
+
lines.push("## \u9700\u6C42\u6F84\u6E05");
|
|
693
|
+
lines.push("");
|
|
694
|
+
for (const q of session.clarificationQuestions) {
|
|
695
|
+
if (q.answered) {
|
|
696
|
+
lines.push(`**Q: ${q.question}**`);
|
|
697
|
+
lines.push(`A: ${q.answer}`);
|
|
698
|
+
lines.push("");
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
lines.push("---");
|
|
702
|
+
lines.push("");
|
|
703
|
+
}
|
|
463
704
|
lines.push("## BDD \u573A\u666F");
|
|
464
705
|
lines.push("");
|
|
465
706
|
for (const scenario of session.bddScenarios) {
|
|
@@ -523,11 +764,17 @@ async function archiveWorkflow(workingDir) {
|
|
|
523
764
|
const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
|
|
524
765
|
|
|
525
766
|
> \u5F52\u6863\u65F6\u95F4: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
767
|
+
> \u9700\u6C42\u6E05\u6670\u5EA6: ${Math.round(activeSession.clarityScore * 100)}%
|
|
526
768
|
> \u590D\u6742\u5EA6: ${activeSession.complexity}/10
|
|
527
769
|
|
|
770
|
+
## \u9700\u6C42\u8BE6\u60C5
|
|
771
|
+
|
|
772
|
+
${activeSession.refinedRequirement}
|
|
773
|
+
|
|
528
774
|
## \u5B8C\u6210\u60C5\u51B5
|
|
529
775
|
|
|
530
776
|
- [x] \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6
|
|
777
|
+
- [x] \u9700\u6C42\u6F84\u6E05
|
|
531
778
|
- [x] \u590D\u6742\u5EA6\u8BC4\u4F30
|
|
532
779
|
- [x] BDD \u573A\u666F\u62C6\u89E3
|
|
533
780
|
- [x] OpenSpec \u89C4\u683C
|
|
@@ -554,6 +801,7 @@ function generateComplexityBar(score) {
|
|
|
554
801
|
function getPhaseLabel(phase) {
|
|
555
802
|
const labels = {
|
|
556
803
|
context: "\u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6",
|
|
804
|
+
clarify: "\u9700\u6C42\u6F84\u6E05",
|
|
557
805
|
analysis: "\u590D\u6742\u5EA6\u8BC4\u4F30",
|
|
558
806
|
bdd: "BDD \u573A\u666F\u62C6\u89E3",
|
|
559
807
|
spec: "OpenSpec \u89C4\u683C",
|
|
@@ -569,12 +817,13 @@ function getActiveSession() {
|
|
|
569
817
|
function clearActiveSession() {
|
|
570
818
|
activeSession = null;
|
|
571
819
|
}
|
|
572
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, activeSession, new_default;
|
|
820
|
+
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
573
821
|
var init_new = __esm({
|
|
574
822
|
"src/commands/new.ts"() {
|
|
575
823
|
init_cjs_shims();
|
|
576
824
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
577
825
|
COMPLEXITY_THRESHOLD = 6;
|
|
826
|
+
CLARITY_THRESHOLD = 0.6;
|
|
578
827
|
activeSession = null;
|
|
579
828
|
new_default = handleNew;
|
|
580
829
|
}
|