@nick848/sf-cli 1.0.19 → 1.0.21
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/cli/index.js +219 -89
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +219 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +219 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -254,23 +254,38 @@ ${resource.analysis}`;
|
|
|
254
254
|
lines.push("");
|
|
255
255
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
256
256
|
lines.push("");
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
activeSession.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
258
|
+
loader.start();
|
|
259
|
+
try {
|
|
260
|
+
activeSession.specItems = await generateSpecItemsWithAI(
|
|
261
|
+
activeSession.refinedRequirement,
|
|
262
|
+
activeSession.context,
|
|
263
|
+
activeSession.bddScenarios,
|
|
264
|
+
activeSession.clarificationQuestions,
|
|
265
|
+
activeSession.referenceResources,
|
|
266
|
+
ctx
|
|
267
|
+
);
|
|
268
|
+
loader.stop();
|
|
269
|
+
} catch {
|
|
270
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u89C4\u683C\u62C6\u5206"));
|
|
271
|
+
activeSession.specItems = generateSpecItems(
|
|
272
|
+
activeSession.refinedRequirement,
|
|
273
|
+
activeSession.context,
|
|
274
|
+
activeSession.bddScenarios,
|
|
275
|
+
activeSession.clarificationQuestions,
|
|
276
|
+
activeSession.referenceResources
|
|
277
|
+
);
|
|
278
|
+
}
|
|
264
279
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
265
280
|
lines.push(chalk9__default.default.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
266
281
|
lines.push(chalk9__default.default.gray(` \u8DEF\u5F84: ${specPath}`));
|
|
267
282
|
lines.push("");
|
|
268
283
|
lines.push(chalk9__default.default.cyan(" \u4EFB\u52A1\u6982\u89C8:"));
|
|
269
|
-
for (const item of activeSession.specItems.slice(0,
|
|
284
|
+
for (const item of activeSession.specItems.slice(0, 8)) {
|
|
270
285
|
const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
271
286
|
lines.push(chalk9__default.default.gray(` ${icon} [${item.id}] ${item.title}`));
|
|
272
287
|
}
|
|
273
|
-
if (activeSession.specItems.length >
|
|
288
|
+
if (activeSession.specItems.length > 8) {
|
|
274
289
|
lines.push(chalk9__default.default.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
|
|
275
290
|
}
|
|
276
291
|
lines.push("");
|
|
@@ -417,13 +432,15 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
417
432
|
activeSession.bddScenarios = generateBDDScenarios(
|
|
418
433
|
activeSession.refinedRequirement,
|
|
419
434
|
activeSession.context,
|
|
420
|
-
activeSession.clarificationQuestions
|
|
435
|
+
activeSession.clarificationQuestions,
|
|
436
|
+
activeSession.referenceResources
|
|
421
437
|
);
|
|
422
438
|
activeSession.specItems = generateSpecItems(
|
|
423
439
|
activeSession.refinedRequirement,
|
|
424
440
|
activeSession.context,
|
|
425
441
|
activeSession.bddScenarios,
|
|
426
|
-
activeSession.clarificationQuestions
|
|
442
|
+
activeSession.clarificationQuestions,
|
|
443
|
+
activeSession.referenceResources
|
|
427
444
|
);
|
|
428
445
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
429
446
|
return {
|
|
@@ -582,107 +599,115 @@ function getCategoryLabel(category) {
|
|
|
582
599
|
async function executeDevelopment(ctx, session) {
|
|
583
600
|
const workingDir = ctx.options.workingDirectory;
|
|
584
601
|
const files = [];
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
602
|
+
console.log("");
|
|
603
|
+
for (let i = 0; i < session.specItems.length; i++) {
|
|
604
|
+
const item = session.specItems[i];
|
|
605
|
+
const prefix = `[${i + 1}/${session.specItems.length}]`;
|
|
606
|
+
if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
const loader = new LoadingIndicator(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
|
|
610
|
+
loader.start();
|
|
611
|
+
try {
|
|
612
|
+
const taskPrompt = buildTaskPrompt(session, item, i);
|
|
613
|
+
const messages = [
|
|
614
|
+
{
|
|
615
|
+
role: "system",
|
|
616
|
+
content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u4EFB\u52A1\u63CF\u8FF0\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002
|
|
593
617
|
|
|
594
618
|
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
595
|
-
1. \
|
|
596
|
-
2. \
|
|
597
|
-
3. \
|
|
598
|
-
|
|
599
|
-
\u4EE3\u7801\u8981\u6C42\uFF1A
|
|
600
|
-
1. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
601
|
-
2. \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u4EE3\u7801\u98CE\u683C\u548C\u89C4\u8303
|
|
602
|
-
3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808
|
|
603
|
-
4. \u4EE3\u7801\u8981\u6709\u9002\u5F53\u7684\u6CE8\u91CA
|
|
604
|
-
5. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
619
|
+
1. \u53EA\u751F\u6210\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u4EE3\u7801\uFF0C\u4E0D\u8981\u751F\u6210\u5176\u4ED6\u4EFB\u52A1\u7684\u4EE3\u7801
|
|
620
|
+
2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
|
|
621
|
+
3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
622
|
+
4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
605
623
|
|
|
606
624
|
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
607
625
|
- \u540D\u79F0: ${session.context?.name}
|
|
608
626
|
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
609
627
|
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
610
628
|
|
|
611
|
-
${session.context?.devStandards ? `\u3010\
|
|
612
|
-
${session.context.devStandards.slice(0,
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
629
|
+
${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
|
|
630
|
+
${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
role: "user",
|
|
634
|
+
content: taskPrompt
|
|
635
|
+
}
|
|
636
|
+
];
|
|
637
|
+
const response = await ctx.modelService.sendMessage(messages, {
|
|
638
|
+
temperature: 0.3,
|
|
639
|
+
maxTokens: 4e3,
|
|
640
|
+
// 单个任务减少 token
|
|
641
|
+
agent: "frontend-dev",
|
|
642
|
+
timeout: 12e4
|
|
643
|
+
// 2分钟超时
|
|
644
|
+
});
|
|
645
|
+
const codeBlocks = parseCodeBlocks(response.content);
|
|
646
|
+
if (codeBlocks.length > 0) {
|
|
647
|
+
for (const block of codeBlocks) {
|
|
648
|
+
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
649
|
+
const dir = path4__namespace.dirname(filePath);
|
|
650
|
+
await fs4__namespace.mkdir(dir, { recursive: true });
|
|
651
|
+
await fs4__namespace.writeFile(filePath, block.code, "utf-8");
|
|
652
|
+
files.push(block.filename);
|
|
653
|
+
}
|
|
654
|
+
loader.stop(chalk9__default.default.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
|
|
655
|
+
} else {
|
|
656
|
+
const implDir = path4__namespace.join(workingDir, "src");
|
|
657
|
+
await fs4__namespace.mkdir(implDir, { recursive: true });
|
|
658
|
+
const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
|
|
659
|
+
const filePath = path4__namespace.join(implDir, fileName);
|
|
660
|
+
await fs4__namespace.writeFile(filePath, `// TODO: ${item.title}
|
|
661
|
+
// ${item.description}
|
|
662
|
+
`, "utf-8");
|
|
663
|
+
files.push(`src/${fileName}`);
|
|
664
|
+
loader.stop(chalk9__default.default.yellow(`${prefix} \u26A0 \u751F\u6210\u57FA\u7840\u6A21\u677F: ${item.title.slice(0, 20)}`));
|
|
665
|
+
}
|
|
666
|
+
if (i < session.specItems.length - 1) {
|
|
667
|
+
await new Promise((resolve4) => setTimeout(resolve4, 500));
|
|
617
668
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const response = await ctx.modelService.sendMessage(messages, {
|
|
621
|
-
temperature: 0.3,
|
|
622
|
-
maxTokens: 8e3,
|
|
623
|
-
agent: "frontend-dev",
|
|
624
|
-
timeout: 18e4
|
|
625
|
-
// 3 分钟超时
|
|
626
|
-
});
|
|
627
|
-
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
628
|
-
const codeBlocks = parseCodeBlocks(response.content);
|
|
629
|
-
for (const block of codeBlocks) {
|
|
630
|
-
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
631
|
-
const dir = path4__namespace.dirname(filePath);
|
|
632
|
-
await fs4__namespace.mkdir(dir, { recursive: true });
|
|
633
|
-
await fs4__namespace.writeFile(filePath, block.code, "utf-8");
|
|
634
|
-
files.push(block.filename);
|
|
635
|
-
}
|
|
636
|
-
if (files.length === 0) {
|
|
637
|
-
const implDir = path4__namespace.join(workingDir, "src", "features");
|
|
638
|
-
await fs4__namespace.mkdir(implDir, { recursive: true });
|
|
639
|
-
const featureName = session.specItems[0]?.title || "feature";
|
|
640
|
-
const fileName = `${featureName.replace(/[^a-zA-Z0-9]/g, "_")}.ts`;
|
|
641
|
-
const filePath = path4__namespace.join(implDir, fileName);
|
|
642
|
-
const stubCode = `/**
|
|
643
|
-
* ${session.requirement}
|
|
644
|
-
*
|
|
645
|
-
* TODO: \u6B64\u6587\u4EF6\u7531 AI \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u6839\u636E\u9700\u6C42\u5B8C\u5584\u5B9E\u73B0
|
|
646
|
-
*/
|
|
647
|
-
|
|
648
|
-
export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
649
|
-
// TODO: \u5B9E\u73B0\u529F\u80FD
|
|
650
|
-
console.log('${featureName} - \u5F85\u5B9E\u73B0');
|
|
651
|
-
}
|
|
652
|
-
`;
|
|
653
|
-
await fs4__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
654
|
-
files.push(`src/features/${fileName}`);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
loader.stop(chalk9__default.default.red(`${prefix} \u2717 \u5931\u8D25: ${error.message.slice(0, 40)}`));
|
|
655
671
|
}
|
|
656
|
-
|
|
672
|
+
}
|
|
673
|
+
if (files.length > 0) {
|
|
657
674
|
return { success: true, files };
|
|
658
|
-
}
|
|
659
|
-
loader.stop();
|
|
675
|
+
} else {
|
|
660
676
|
return {
|
|
661
677
|
success: false,
|
|
662
678
|
files: [],
|
|
663
|
-
error:
|
|
679
|
+
error: "\u6240\u6709\u4EFB\u52A1\u4EE3\u7801\u751F\u6210\u5931\u8D25"
|
|
664
680
|
};
|
|
665
681
|
}
|
|
666
682
|
}
|
|
667
|
-
function
|
|
683
|
+
function buildTaskPrompt(session, item, index) {
|
|
668
684
|
const lines = [];
|
|
669
|
-
lines.push(
|
|
670
|
-
lines.push(
|
|
671
|
-
lines.push(
|
|
672
|
-
lines.push(
|
|
673
|
-
|
|
674
|
-
lines.push(
|
|
675
|
-
for (const
|
|
676
|
-
lines.push(`- ${
|
|
685
|
+
lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
|
|
686
|
+
lines.push(`**\u6807\u9898**: ${item.title}`);
|
|
687
|
+
lines.push(`**\u63CF\u8FF0**: ${item.description}`);
|
|
688
|
+
lines.push(`**\u4F18\u5148\u7EA7**: ${item.priority}`);
|
|
689
|
+
if (item.tests && item.tests.length > 0) {
|
|
690
|
+
lines.push(`**\u9A8C\u6536\u6807\u51C6**:`);
|
|
691
|
+
for (const t of item.tests) {
|
|
692
|
+
lines.push(`- ${t}`);
|
|
677
693
|
}
|
|
678
694
|
}
|
|
679
695
|
lines.push("");
|
|
680
|
-
lines.push(
|
|
681
|
-
|
|
682
|
-
|
|
696
|
+
lines.push(`## \u6574\u4F53\u9700\u6C42\u80CC\u666F`);
|
|
697
|
+
lines.push(session.requirement);
|
|
698
|
+
const relatedScenario = session.bddScenarios.find(
|
|
699
|
+
(s) => item.title.includes(s.feature) || s.feature.includes(item.title)
|
|
700
|
+
);
|
|
701
|
+
if (relatedScenario) {
|
|
702
|
+
lines.push("");
|
|
703
|
+
lines.push(`## \u76F8\u5173 BDD \u573A\u666F`);
|
|
704
|
+
lines.push(`Feature: ${relatedScenario.feature}`);
|
|
705
|
+
for (const s of relatedScenario.scenarios.slice(0, 2)) {
|
|
706
|
+
lines.push(`- ${s.name}`);
|
|
707
|
+
}
|
|
683
708
|
}
|
|
684
709
|
lines.push("");
|
|
685
|
-
lines.push("\u8BF7\
|
|
710
|
+
lines.push("\u8BF7\u751F\u6210\u5B9E\u73B0\u6B64\u4EFB\u52A1\u7684\u4EE3\u7801\u3002\u53EA\u751F\u6210\u5F53\u524D\u4EFB\u52A1\u9700\u8981\u7684\u6587\u4EF6\u3002");
|
|
686
711
|
return lines.join("\n");
|
|
687
712
|
}
|
|
688
713
|
function parseCodeBlocks(content) {
|
|
@@ -1149,6 +1174,111 @@ function generateSpecItems(requirement, context, bddScenarios, questions, refere
|
|
|
1149
1174
|
});
|
|
1150
1175
|
return items;
|
|
1151
1176
|
}
|
|
1177
|
+
async function generateSpecItemsWithAI(requirement, context, bddScenarios, questions, references, ctx) {
|
|
1178
|
+
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
|
|
1179
|
+
|
|
1180
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
1181
|
+
${requirement}
|
|
1182
|
+
|
|
1183
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
1184
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
|
|
1185
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
1186
|
+
${context.devStandards ? `
|
|
1187
|
+
## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
|
|
1188
|
+
${context.devStandards.slice(0, 2e3)}
|
|
1189
|
+
` : ""}
|
|
1190
|
+
|
|
1191
|
+
## BDD \u573A\u666F\u53C2\u8003
|
|
1192
|
+
${bddScenarios.map((s) => `- Feature: ${s.feature} (${s.scenarios.length} \u4E2A\u573A\u666F)`).join("\n")}
|
|
1193
|
+
|
|
1194
|
+
## \u6F84\u6E05\u4FE1\u606F
|
|
1195
|
+
${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`).join("\n") || "\u65E0"}
|
|
1196
|
+
|
|
1197
|
+
## \u62C6\u5206\u8981\u6C42
|
|
1198
|
+
|
|
1199
|
+
\u8BF7\u5C06\u9700\u6C42\u62C6\u5206\u4E3A **\u7EC6\u7C92\u5EA6\u7684\u5F00\u53D1\u4EFB\u52A1**\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\uFF1A
|
|
1200
|
+
1. **\u5355\u4E00\u804C\u8D23** - \u4E00\u4E2A\u4EFB\u52A1\u53EA\u505A\u4E00\u4EF6\u4E8B
|
|
1201
|
+
2. **\u53EF\u72EC\u7ACB\u6D4B\u8BD5** - \u6709\u660E\u786E\u7684\u9A8C\u6536\u6807\u51C6
|
|
1202
|
+
3. **2-4\u5C0F\u65F6\u53EF\u5B8C\u6210** - \u5982\u679C\u4EFB\u52A1\u592A\u5927\uFF0C\u7EE7\u7EED\u62C6\u5206
|
|
1203
|
+
4. **\u6709\u660E\u786E\u7684\u8F93\u5165\u8F93\u51FA** - \u6E05\u695A\u77E5\u9053\u9700\u8981\u4EC0\u4E48\u3001\u4EA7\u51FA\u4EC0\u4E48
|
|
1204
|
+
|
|
1205
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
1206
|
+
\`\`\`json
|
|
1207
|
+
[
|
|
1208
|
+
{
|
|
1209
|
+
"id": "T001",
|
|
1210
|
+
"title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
|
|
1211
|
+
"description": "\u8BE6\u7EC6\u63CF\u8FF0\uFF1A\u8981\u505A\u4EC0\u4E48\u3001\u5982\u4F55\u505A\u3001\u9A8C\u6536\u6807\u51C6",
|
|
1212
|
+
"priority": "high",
|
|
1213
|
+
"estimatedHours": 2,
|
|
1214
|
+
"dependencies": [],
|
|
1215
|
+
"acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
|
|
1216
|
+
}
|
|
1217
|
+
]
|
|
1218
|
+
\`\`\`
|
|
1219
|
+
|
|
1220
|
+
## \u62C6\u5206\u5EFA\u8BAE
|
|
1221
|
+
\u5BF9\u4E8E\u590D\u6742\u529F\u80FD\uFF08\u5982\u7B97\u6CD5\u7C7B\uFF09\uFF0C\u5E94\u8BE5\u62C6\u5206\u4E3A\uFF1A
|
|
1222
|
+
- \u6570\u636E\u7ED3\u6784/\u6A21\u578B\u5B9A\u4E49
|
|
1223
|
+
- \u6838\u5FC3\u7B97\u6CD5\u5206\u6B65\u5B9E\u73B0\uFF08\u6BCF\u4E2A\u8BA1\u7B97\u6B65\u9AA4\u4E00\u4E2A\u4EFB\u52A1\uFF09
|
|
1224
|
+
- \u8F93\u5165\u9A8C\u8BC1
|
|
1225
|
+
- \u7ED3\u679C\u683C\u5F0F\u5316
|
|
1226
|
+
- UI \u5C55\u793A\u7EC4\u4EF6
|
|
1227
|
+
- \u96C6\u6210\u6D4B\u8BD5
|
|
1228
|
+
|
|
1229
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
|
|
1230
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
1231
|
+
loader.start();
|
|
1232
|
+
try {
|
|
1233
|
+
const response = await ctx.modelService.sendMessage([
|
|
1234
|
+
{ role: "user", content: prompt2 }
|
|
1235
|
+
], {
|
|
1236
|
+
temperature: 0.3,
|
|
1237
|
+
maxTokens: 4e3,
|
|
1238
|
+
timeout: 18e4
|
|
1239
|
+
// 增加到3分钟
|
|
1240
|
+
});
|
|
1241
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
1242
|
+
if (jsonMatch) {
|
|
1243
|
+
try {
|
|
1244
|
+
const parsed = JSON.parse(jsonMatch[1].trim());
|
|
1245
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
|
|
1246
|
+
return parsed.map((item, index) => ({
|
|
1247
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
1248
|
+
title: item.title,
|
|
1249
|
+
description: item.description,
|
|
1250
|
+
priority: item.priority || "medium",
|
|
1251
|
+
files: [],
|
|
1252
|
+
tests: item.acceptanceCriteria || []
|
|
1253
|
+
}));
|
|
1254
|
+
} catch (parseError) {
|
|
1255
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 JSON \u89E3\u6790\u5931\u8D25: ${parseError.message.slice(0, 50)}`));
|
|
1256
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
try {
|
|
1260
|
+
const parsed = JSON.parse(response.content);
|
|
1261
|
+
if (Array.isArray(parsed)) {
|
|
1262
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
|
|
1263
|
+
return parsed.map((item, index) => ({
|
|
1264
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
1265
|
+
title: item.title,
|
|
1266
|
+
description: item.description,
|
|
1267
|
+
priority: item.priority || "medium",
|
|
1268
|
+
files: [],
|
|
1269
|
+
tests: item.acceptanceCriteria || []
|
|
1270
|
+
}));
|
|
1271
|
+
}
|
|
1272
|
+
} catch {
|
|
1273
|
+
}
|
|
1274
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u672A\u80FD\u89E3\u6790 AI \u54CD\u5E94\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
|
|
1275
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
const errMsg = error.message.slice(0, 80);
|
|
1278
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 AI \u8C03\u7528\u5931\u8D25: ${errMsg}`));
|
|
1279
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1152
1282
|
async function saveSpecFile(workingDir, session) {
|
|
1153
1283
|
const specDir = path4__namespace.join(workingDir, "openspec", "changes");
|
|
1154
1284
|
await fs4__namespace.mkdir(specDir, { recursive: true });
|