@nick848/sf-cli 1.0.20 → 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 +122 -92
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +121 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -91
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -599,107 +599,115 @@ function getCategoryLabel(category) {
|
|
|
599
599
|
async function executeDevelopment(ctx, session) {
|
|
600
600
|
const workingDir = ctx.options.workingDirectory;
|
|
601
601
|
const files = [];
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
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
|
|
610
617
|
|
|
611
618
|
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
612
|
-
1. \
|
|
613
|
-
2. \
|
|
614
|
-
3. \
|
|
615
|
-
|
|
616
|
-
\u4EE3\u7801\u8981\u6C42\uFF1A
|
|
617
|
-
1. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
618
|
-
2. \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u4EE3\u7801\u98CE\u683C\u548C\u89C4\u8303
|
|
619
|
-
3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808
|
|
620
|
-
4. \u4EE3\u7801\u8981\u6709\u9002\u5F53\u7684\u6CE8\u91CA
|
|
621
|
-
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
|
|
622
623
|
|
|
623
624
|
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
624
625
|
- \u540D\u79F0: ${session.context?.name}
|
|
625
626
|
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
626
627
|
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
627
628
|
|
|
628
|
-
${session.context?.devStandards ? `\u3010\
|
|
629
|
-
${session.context.devStandards.slice(0,
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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));
|
|
634
668
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const response = await ctx.modelService.sendMessage(messages, {
|
|
638
|
-
temperature: 0.3,
|
|
639
|
-
maxTokens: 8e3,
|
|
640
|
-
agent: "frontend-dev",
|
|
641
|
-
timeout: 18e4
|
|
642
|
-
// 3 分钟超时
|
|
643
|
-
});
|
|
644
|
-
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
645
|
-
const codeBlocks = parseCodeBlocks(response.content);
|
|
646
|
-
for (const block of codeBlocks) {
|
|
647
|
-
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
648
|
-
const dir = path4__namespace.dirname(filePath);
|
|
649
|
-
await fs4__namespace.mkdir(dir, { recursive: true });
|
|
650
|
-
await fs4__namespace.writeFile(filePath, block.code, "utf-8");
|
|
651
|
-
files.push(block.filename);
|
|
652
|
-
}
|
|
653
|
-
if (files.length === 0) {
|
|
654
|
-
const implDir = path4__namespace.join(workingDir, "src", "features");
|
|
655
|
-
await fs4__namespace.mkdir(implDir, { recursive: true });
|
|
656
|
-
const featureName = session.specItems[0]?.title || "feature";
|
|
657
|
-
const fileName = `${featureName.replace(/[^a-zA-Z0-9]/g, "_")}.ts`;
|
|
658
|
-
const filePath = path4__namespace.join(implDir, fileName);
|
|
659
|
-
const stubCode = `/**
|
|
660
|
-
* ${session.requirement}
|
|
661
|
-
*
|
|
662
|
-
* TODO: \u6B64\u6587\u4EF6\u7531 AI \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u6839\u636E\u9700\u6C42\u5B8C\u5584\u5B9E\u73B0
|
|
663
|
-
*/
|
|
664
|
-
|
|
665
|
-
export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
666
|
-
// TODO: \u5B9E\u73B0\u529F\u80FD
|
|
667
|
-
console.log('${featureName} - \u5F85\u5B9E\u73B0');
|
|
668
|
-
}
|
|
669
|
-
`;
|
|
670
|
-
await fs4__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
671
|
-
files.push(`src/features/${fileName}`);
|
|
669
|
+
} catch (error) {
|
|
670
|
+
loader.stop(chalk9__default.default.red(`${prefix} \u2717 \u5931\u8D25: ${error.message.slice(0, 40)}`));
|
|
672
671
|
}
|
|
673
|
-
|
|
672
|
+
}
|
|
673
|
+
if (files.length > 0) {
|
|
674
674
|
return { success: true, files };
|
|
675
|
-
}
|
|
676
|
-
loader.stop();
|
|
675
|
+
} else {
|
|
677
676
|
return {
|
|
678
677
|
success: false,
|
|
679
678
|
files: [],
|
|
680
|
-
error:
|
|
679
|
+
error: "\u6240\u6709\u4EFB\u52A1\u4EE3\u7801\u751F\u6210\u5931\u8D25"
|
|
681
680
|
};
|
|
682
681
|
}
|
|
683
682
|
}
|
|
684
|
-
function
|
|
683
|
+
function buildTaskPrompt(session, item, index) {
|
|
685
684
|
const lines = [];
|
|
686
|
-
lines.push(
|
|
687
|
-
lines.push(
|
|
688
|
-
lines.push(
|
|
689
|
-
lines.push(
|
|
690
|
-
|
|
691
|
-
lines.push(
|
|
692
|
-
for (const
|
|
693
|
-
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}`);
|
|
694
693
|
}
|
|
695
694
|
}
|
|
696
695
|
lines.push("");
|
|
697
|
-
lines.push(
|
|
698
|
-
|
|
699
|
-
|
|
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
|
+
}
|
|
700
708
|
}
|
|
701
709
|
lines.push("");
|
|
702
|
-
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");
|
|
703
711
|
return lines.join("\n");
|
|
704
712
|
}
|
|
705
713
|
function parseCodeBlocks(content) {
|
|
@@ -1227,25 +1235,47 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
1227
1235
|
], {
|
|
1228
1236
|
temperature: 0.3,
|
|
1229
1237
|
maxTokens: 4e3,
|
|
1230
|
-
timeout:
|
|
1238
|
+
timeout: 18e4
|
|
1239
|
+
// 增加到3分钟
|
|
1231
1240
|
});
|
|
1232
1241
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
1233
1242
|
if (jsonMatch) {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
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 {
|
|
1244
1273
|
}
|
|
1245
|
-
loader.stop(chalk9__default.default.yellow(" \u26A0 \u89E3\u6790\
|
|
1274
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u672A\u80FD\u89E3\u6790 AI \u54CD\u5E94\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
|
|
1246
1275
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1247
1276
|
} catch (error) {
|
|
1248
|
-
|
|
1277
|
+
const errMsg = error.message.slice(0, 80);
|
|
1278
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 AI \u8C03\u7528\u5931\u8D25: ${errMsg}`));
|
|
1249
1279
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1250
1280
|
}
|
|
1251
1281
|
}
|