@nick848/sf-cli 1.0.19 → 1.0.20

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
@@ -229,23 +229,38 @@ ${resource.analysis}`;
229
229
  lines.push("");
230
230
  lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
231
231
  lines.push("");
232
- activeSession.specItems = generateSpecItems(
233
- activeSession.refinedRequirement,
234
- activeSession.context,
235
- activeSession.bddScenarios,
236
- activeSession.clarificationQuestions,
237
- activeSession.referenceResources
238
- );
232
+ const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
233
+ loader.start();
234
+ try {
235
+ activeSession.specItems = await generateSpecItemsWithAI(
236
+ activeSession.refinedRequirement,
237
+ activeSession.context,
238
+ activeSession.bddScenarios,
239
+ activeSession.clarificationQuestions,
240
+ activeSession.referenceResources,
241
+ ctx
242
+ );
243
+ loader.stop();
244
+ } catch {
245
+ loader.stop(chalk9.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u89C4\u683C\u62C6\u5206"));
246
+ activeSession.specItems = generateSpecItems(
247
+ activeSession.refinedRequirement,
248
+ activeSession.context,
249
+ activeSession.bddScenarios,
250
+ activeSession.clarificationQuestions,
251
+ activeSession.referenceResources
252
+ );
253
+ }
239
254
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
240
255
  lines.push(chalk9.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
241
256
  lines.push(chalk9.gray(` \u8DEF\u5F84: ${specPath}`));
242
257
  lines.push("");
243
258
  lines.push(chalk9.cyan(" \u4EFB\u52A1\u6982\u89C8:"));
244
- for (const item of activeSession.specItems.slice(0, 5)) {
259
+ for (const item of activeSession.specItems.slice(0, 8)) {
245
260
  const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
246
261
  lines.push(chalk9.gray(` ${icon} [${item.id}] ${item.title}`));
247
262
  }
248
- if (activeSession.specItems.length > 5) {
263
+ if (activeSession.specItems.length > 8) {
249
264
  lines.push(chalk9.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
250
265
  }
251
266
  lines.push("");
@@ -392,13 +407,15 @@ async function handleWorkflowInput(input, ctx) {
392
407
  activeSession.bddScenarios = generateBDDScenarios(
393
408
  activeSession.refinedRequirement,
394
409
  activeSession.context,
395
- activeSession.clarificationQuestions
410
+ activeSession.clarificationQuestions,
411
+ activeSession.referenceResources
396
412
  );
397
413
  activeSession.specItems = generateSpecItems(
398
414
  activeSession.refinedRequirement,
399
415
  activeSession.context,
400
416
  activeSession.bddScenarios,
401
- activeSession.clarificationQuestions
417
+ activeSession.clarificationQuestions,
418
+ activeSession.referenceResources
402
419
  );
403
420
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
404
421
  return {
@@ -1124,6 +1141,89 @@ function generateSpecItems(requirement, context, bddScenarios, questions, refere
1124
1141
  });
1125
1142
  return items;
1126
1143
  }
1144
+ async function generateSpecItemsWithAI(requirement, context, bddScenarios, questions, references, ctx) {
1145
+ const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u9879\u76EE\u7ECF\u7406\u548C\u6280\u672F\u67B6\u6784\u5E08\u3002\u8BF7\u5C06\u4EE5\u4E0B\u9700\u6C42\u62C6\u5206\u4E3A\u7CBE\u7EC6\u5316\u7684\u5F00\u53D1\u4EFB\u52A1\u3002
1146
+
1147
+ ## \u9700\u6C42\u63CF\u8FF0
1148
+ ${requirement}
1149
+
1150
+ ## \u9879\u76EE\u4E0A\u4E0B\u6587
1151
+ - \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
1152
+ - \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
1153
+ ${context.devStandards ? `
1154
+ ## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
1155
+ ${context.devStandards.slice(0, 2e3)}
1156
+ ` : ""}
1157
+
1158
+ ## BDD \u573A\u666F\u53C2\u8003
1159
+ ${bddScenarios.map((s) => `- Feature: ${s.feature} (${s.scenarios.length} \u4E2A\u573A\u666F)`).join("\n")}
1160
+
1161
+ ## \u6F84\u6E05\u4FE1\u606F
1162
+ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`).join("\n") || "\u65E0"}
1163
+
1164
+ ## \u62C6\u5206\u8981\u6C42
1165
+
1166
+ \u8BF7\u5C06\u9700\u6C42\u62C6\u5206\u4E3A **\u7EC6\u7C92\u5EA6\u7684\u5F00\u53D1\u4EFB\u52A1**\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\uFF1A
1167
+ 1. **\u5355\u4E00\u804C\u8D23** - \u4E00\u4E2A\u4EFB\u52A1\u53EA\u505A\u4E00\u4EF6\u4E8B
1168
+ 2. **\u53EF\u72EC\u7ACB\u6D4B\u8BD5** - \u6709\u660E\u786E\u7684\u9A8C\u6536\u6807\u51C6
1169
+ 3. **2-4\u5C0F\u65F6\u53EF\u5B8C\u6210** - \u5982\u679C\u4EFB\u52A1\u592A\u5927\uFF0C\u7EE7\u7EED\u62C6\u5206
1170
+ 4. **\u6709\u660E\u786E\u7684\u8F93\u5165\u8F93\u51FA** - \u6E05\u695A\u77E5\u9053\u9700\u8981\u4EC0\u4E48\u3001\u4EA7\u51FA\u4EC0\u4E48
1171
+
1172
+ ## \u8F93\u51FA\u683C\u5F0F (JSON)
1173
+ \`\`\`json
1174
+ [
1175
+ {
1176
+ "id": "T001",
1177
+ "title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
1178
+ "description": "\u8BE6\u7EC6\u63CF\u8FF0\uFF1A\u8981\u505A\u4EC0\u4E48\u3001\u5982\u4F55\u505A\u3001\u9A8C\u6536\u6807\u51C6",
1179
+ "priority": "high",
1180
+ "estimatedHours": 2,
1181
+ "dependencies": [],
1182
+ "acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
1183
+ }
1184
+ ]
1185
+ \`\`\`
1186
+
1187
+ ## \u62C6\u5206\u5EFA\u8BAE
1188
+ \u5BF9\u4E8E\u590D\u6742\u529F\u80FD\uFF08\u5982\u7B97\u6CD5\u7C7B\uFF09\uFF0C\u5E94\u8BE5\u62C6\u5206\u4E3A\uFF1A
1189
+ - \u6570\u636E\u7ED3\u6784/\u6A21\u578B\u5B9A\u4E49
1190
+ - \u6838\u5FC3\u7B97\u6CD5\u5206\u6B65\u5B9E\u73B0\uFF08\u6BCF\u4E2A\u8BA1\u7B97\u6B65\u9AA4\u4E00\u4E2A\u4EFB\u52A1\uFF09
1191
+ - \u8F93\u5165\u9A8C\u8BC1
1192
+ - \u7ED3\u679C\u683C\u5F0F\u5316
1193
+ - UI \u5C55\u793A\u7EC4\u4EF6
1194
+ - \u96C6\u6210\u6D4B\u8BD5
1195
+
1196
+ \u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
1197
+ const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
1198
+ loader.start();
1199
+ try {
1200
+ const response = await ctx.modelService.sendMessage([
1201
+ { role: "user", content: prompt2 }
1202
+ ], {
1203
+ temperature: 0.3,
1204
+ maxTokens: 4e3,
1205
+ timeout: 12e4
1206
+ });
1207
+ const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
1208
+ if (jsonMatch) {
1209
+ const parsed = JSON.parse(jsonMatch[1].trim());
1210
+ loader.stop(chalk9.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
1211
+ return parsed.map((item) => ({
1212
+ id: item.id || `T${String(parsed.indexOf(item) + 1).padStart(3, "0")}`,
1213
+ title: item.title,
1214
+ description: item.description,
1215
+ priority: item.priority || "medium",
1216
+ files: [],
1217
+ tests: item.acceptanceCriteria || []
1218
+ }));
1219
+ }
1220
+ loader.stop(chalk9.yellow(" \u26A0 \u89E3\u6790\u5931\u8D25\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
1221
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1222
+ } catch (error) {
1223
+ loader.stop(chalk9.yellow(" \u26A0 AI \u62C6\u5206\u5931\u8D25\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
1224
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1225
+ }
1226
+ }
1127
1227
  async function saveSpecFile(workingDir, session) {
1128
1228
  const specDir = path5.join(workingDir, "openspec", "changes");
1129
1229
  await fs4.mkdir(specDir, { recursive: true });