@nick848/sf-cli 1.0.17 → 1.0.18
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 +330 -72
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +330 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +330 -72
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -219,12 +219,26 @@ ${resource.analysis}`;
|
|
|
219
219
|
lines.push("");
|
|
220
220
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
221
221
|
lines.push("");
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
activeSession.
|
|
226
|
-
|
|
227
|
-
|
|
222
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
|
|
223
|
+
loader.start();
|
|
224
|
+
try {
|
|
225
|
+
activeSession.bddScenarios = await generateBDDScenariosWithAI(
|
|
226
|
+
activeSession.refinedRequirement,
|
|
227
|
+
activeSession.context,
|
|
228
|
+
activeSession.clarificationQuestions,
|
|
229
|
+
activeSession.referenceResources,
|
|
230
|
+
ctx
|
|
231
|
+
);
|
|
232
|
+
loader.stop(chalk9__default.default.green(" \u2713 BDD \u573A\u666F\u5DF2\u751F\u6210"));
|
|
233
|
+
} catch {
|
|
234
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840 BDD \u751F\u6210"));
|
|
235
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
236
|
+
activeSession.refinedRequirement,
|
|
237
|
+
activeSession.context,
|
|
238
|
+
activeSession.clarificationQuestions,
|
|
239
|
+
activeSession.referenceResources
|
|
240
|
+
);
|
|
241
|
+
}
|
|
228
242
|
for (const scenario of activeSession.bddScenarios) {
|
|
229
243
|
lines.push(chalk9__default.default.white(` Feature: ${scenario.feature}`));
|
|
230
244
|
for (const s of scenario.scenarios.slice(0, 3)) {
|
|
@@ -271,7 +285,7 @@ ${resource.analysis}`;
|
|
|
271
285
|
lines.push("");
|
|
272
286
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/9: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
273
287
|
lines.push("");
|
|
274
|
-
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
288
|
+
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession, ctx);
|
|
275
289
|
lines.push(chalk9__default.default.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
276
290
|
for (const file of activeSession.testFiles) {
|
|
277
291
|
lines.push(chalk9__default.default.gray(` - ${file}`));
|
|
@@ -568,6 +582,8 @@ function getCategoryLabel(category) {
|
|
|
568
582
|
async function executeDevelopment(ctx, session) {
|
|
569
583
|
const workingDir = ctx.options.workingDirectory;
|
|
570
584
|
const files = [];
|
|
585
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210\u4EE3\u7801");
|
|
586
|
+
loader.start();
|
|
571
587
|
try {
|
|
572
588
|
const systemPrompt = buildDevelopmentPrompt(session);
|
|
573
589
|
const messages = [
|
|
@@ -595,11 +611,15 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
595
611
|
content: systemPrompt
|
|
596
612
|
}
|
|
597
613
|
];
|
|
614
|
+
loader.update("\u6B63\u5728\u8C03\u7528 AI \u6A21\u578B");
|
|
598
615
|
const response = await ctx.modelService.sendMessage(messages, {
|
|
599
616
|
temperature: 0.3,
|
|
600
617
|
maxTokens: 8e3,
|
|
601
|
-
agent: "frontend-dev"
|
|
618
|
+
agent: "frontend-dev",
|
|
619
|
+
timeout: 18e4
|
|
620
|
+
// 3 分钟超时
|
|
602
621
|
});
|
|
622
|
+
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
603
623
|
const codeBlocks = parseCodeBlocks(response.content);
|
|
604
624
|
for (const block of codeBlocks) {
|
|
605
625
|
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
@@ -628,8 +648,10 @@ export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
|
628
648
|
await fs4__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
629
649
|
files.push(`src/features/${fileName}`);
|
|
630
650
|
}
|
|
651
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u751F\u6210 ${files.length} \u4E2A\u6587\u4EF6`));
|
|
631
652
|
return { success: true, files };
|
|
632
653
|
} catch (error) {
|
|
654
|
+
loader.stop();
|
|
633
655
|
return {
|
|
634
656
|
success: false,
|
|
635
657
|
files: [],
|
|
@@ -913,36 +935,125 @@ function generateBDDScenarios(requirement, context, questions, references = [])
|
|
|
913
935
|
}
|
|
914
936
|
return scenarios;
|
|
915
937
|
}
|
|
938
|
+
async function generateBDDScenariosWithAI(requirement, context, questions, references, ctx) {
|
|
939
|
+
const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\u548C\u4E1A\u52A1\u5206\u6790\u5E08\u3002\u8BF7\u6839\u636E\u4EE5\u4E0B\u9700\u6C42\u751F\u6210\u8BE6\u7EC6\u7684 BDD (Behavior Driven Development) \u573A\u666F\u3002
|
|
940
|
+
|
|
941
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
942
|
+
${requirement}
|
|
943
|
+
|
|
944
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
945
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "\u672A\u6307\u5B9A"}
|
|
946
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
947
|
+
|
|
948
|
+
## \u6F84\u6E05\u95EE\u7B54
|
|
949
|
+
${questions.filter((q) => q.answered).map((q) => `- Q: ${q.question}
|
|
950
|
+
A: ${q.answer}`).join("\n")}
|
|
951
|
+
|
|
952
|
+
## \u53C2\u8003\u8D44\u6E90\u5206\u6790
|
|
953
|
+
${references.map((r) => `### ${r.url}
|
|
954
|
+
${r.analysis}`).join("\n\n")}
|
|
955
|
+
|
|
956
|
+
## \u8981\u6C42
|
|
957
|
+
1. \u6BCF\u4E2A\u529F\u80FD\u6A21\u5757\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684 Feature
|
|
958
|
+
2. \u6BCF\u4E2A Feature \u5305\u542B\u591A\u4E2A\u5177\u4F53\u7684 Scenario
|
|
959
|
+
3. \u4F7F\u7528 Given-When-Then \u683C\u5F0F
|
|
960
|
+
4. \u573A\u666F\u8981\u8986\u76D6: \u6B63\u5E38\u6D41\u7A0B\u3001\u8FB9\u754C\u60C5\u51B5\u3001\u5F02\u5E38\u5904\u7406
|
|
961
|
+
5. \u573A\u666F\u8981\u5177\u4F53\u53EF\u6D4B\u8BD5\uFF0C\u4E0D\u8981\u6CDB\u6CDB\u800C\u8C08
|
|
962
|
+
|
|
963
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
964
|
+
\`\`\`json
|
|
965
|
+
[
|
|
966
|
+
{
|
|
967
|
+
"feature": "\u529F\u80FD\u540D\u79F0",
|
|
968
|
+
"description": "\u529F\u80FD\u63CF\u8FF0",
|
|
969
|
+
"scenarios": [
|
|
970
|
+
{
|
|
971
|
+
"name": "\u573A\u666F\u540D\u79F0",
|
|
972
|
+
"given": ["\u524D\u7F6E\u6761\u4EF61", "\u524D\u7F6E\u6761\u4EF62"],
|
|
973
|
+
"when": ["\u64CD\u4F5C1", "\u64CD\u4F5C2"],
|
|
974
|
+
"then": ["\u9884\u671F\u7ED3\u679C1", "\u9884\u671F\u7ED3\u679C2"]
|
|
975
|
+
}
|
|
976
|
+
]
|
|
977
|
+
}
|
|
978
|
+
]
|
|
979
|
+
\`\`\`
|
|
980
|
+
|
|
981
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u6709\u5176\u4ED6\u5185\u5BB9\u3002`;
|
|
982
|
+
const response = await ctx.modelService.sendMessage([
|
|
983
|
+
{ role: "user", content: prompt2 }
|
|
984
|
+
], {
|
|
985
|
+
temperature: 0.3,
|
|
986
|
+
maxTokens: 4e3,
|
|
987
|
+
timeout: 12e4
|
|
988
|
+
});
|
|
989
|
+
try {
|
|
990
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
991
|
+
if (jsonMatch) {
|
|
992
|
+
return JSON.parse(jsonMatch[1].trim());
|
|
993
|
+
}
|
|
994
|
+
return JSON.parse(response.content);
|
|
995
|
+
} catch {
|
|
996
|
+
return generateBDDScenarios(requirement, context, questions, references);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
916
999
|
function extractFeaturesFromReference(ref) {
|
|
917
1000
|
const features = [];
|
|
918
|
-
const analysis = ref.analysis
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
930
|
-
hasInput: false
|
|
931
|
-
});
|
|
1001
|
+
const analysis = ref.analysis;
|
|
1002
|
+
const featureSection = analysis.match(/###?\s*4\.\s*功能拆分建议[\s\S]*?(?=###?\s*\d|$)/i);
|
|
1003
|
+
if (featureSection) {
|
|
1004
|
+
const taskMatches = featureSection[0].matchAll(/[-*]\s*\*\*([^*]+)\*\*[::]?\s*([^\n]+)/g);
|
|
1005
|
+
for (const match of taskMatches) {
|
|
1006
|
+
features.push({
|
|
1007
|
+
title: match[1].trim(),
|
|
1008
|
+
description: match[2].trim(),
|
|
1009
|
+
hasInput: match[2].includes("\u8F93\u5165") || match[2].includes("\u8868\u5355") || match[2].includes("\u7528\u6237")
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
932
1012
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1013
|
+
const bizSection = analysis.match(/###?\s*1\.\s*业务功能分析[\s\S]*?(?=###?\s*\d|$)/i);
|
|
1014
|
+
if (bizSection && features.length === 0) {
|
|
1015
|
+
const lines = bizSection[0].split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*"));
|
|
1016
|
+
for (const line of lines.slice(0, 5)) {
|
|
1017
|
+
const content = line.replace(/^[-*]\s*/, "").trim();
|
|
1018
|
+
if (content.length > 5) {
|
|
1019
|
+
features.push({
|
|
1020
|
+
title: content.slice(0, 20),
|
|
1021
|
+
description: content,
|
|
1022
|
+
hasInput: content.includes("\u8F93\u5165") || content.includes("\u586B\u5199")
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
939
1026
|
}
|
|
940
|
-
if (
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1027
|
+
if (features.length === 0) {
|
|
1028
|
+
const lowerAnalysis = analysis.toLowerCase();
|
|
1029
|
+
if (lowerAnalysis.includes("\u8F93\u5165") || lowerAnalysis.includes("\u8868\u5355")) {
|
|
1030
|
+
features.push({
|
|
1031
|
+
title: "\u8F93\u5165\u8868\u5355",
|
|
1032
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
|
|
1033
|
+
hasInput: true
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
if (lowerAnalysis.includes("\u6309\u94AE") || lowerAnalysis.includes("\u64CD\u4F5C")) {
|
|
1037
|
+
features.push({
|
|
1038
|
+
title: "\u4EA4\u4E92\u6309\u94AE",
|
|
1039
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
1040
|
+
hasInput: false
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
if (lowerAnalysis.includes("\u8868\u683C") || lowerAnalysis.includes("\u5217\u8868")) {
|
|
1044
|
+
features.push({
|
|
1045
|
+
title: "\u6570\u636E\u5217\u8868",
|
|
1046
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
|
|
1047
|
+
hasInput: false
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
if (lowerAnalysis.includes("\u56FE\u8868") || lowerAnalysis.includes("\u53EF\u89C6\u5316")) {
|
|
1051
|
+
features.push({
|
|
1052
|
+
title: "\u56FE\u8868\u5C55\u793A",
|
|
1053
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
|
|
1054
|
+
hasInput: false
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
946
1057
|
}
|
|
947
1058
|
if (features.length === 0) {
|
|
948
1059
|
features.push({
|
|
@@ -1106,33 +1217,119 @@ function formatSpecFile(session) {
|
|
|
1106
1217
|
lines.push("**\u786E\u8BA4\u72B6\u6001**: \u23F3 \u7B49\u5F85\u786E\u8BA4");
|
|
1107
1218
|
return lines.join("\n");
|
|
1108
1219
|
}
|
|
1109
|
-
async function generateTests(workingDir, session) {
|
|
1220
|
+
async function generateTests(workingDir, session, ctx) {
|
|
1110
1221
|
const testDir = path4__namespace.join(workingDir, "tests");
|
|
1111
1222
|
await fs4__namespace.mkdir(testDir, { recursive: true });
|
|
1112
1223
|
const testFiles = [];
|
|
1113
|
-
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1224
|
+
if (ctx?.modelService) {
|
|
1225
|
+
for (const scenario of session.bddScenarios) {
|
|
1226
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1227
|
+
const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
|
|
1228
|
+
const loader = new LoadingIndicator(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
|
|
1229
|
+
loader.start();
|
|
1230
|
+
try {
|
|
1231
|
+
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
1232
|
+
await fs4__namespace.writeFile(testPath, content, "utf-8");
|
|
1233
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1234
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
|
|
1235
|
+
} catch {
|
|
1236
|
+
const content = generateTestFile(scenario, session);
|
|
1237
|
+
await fs4__namespace.writeFile(testPath, content, "utf-8");
|
|
1238
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1239
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
} else {
|
|
1243
|
+
for (const scenario of session.bddScenarios) {
|
|
1244
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1245
|
+
const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
|
|
1246
|
+
const content = generateTestFile(scenario, session);
|
|
1247
|
+
await fs4__namespace.writeFile(testPath, content, "utf-8");
|
|
1248
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1249
|
+
}
|
|
1119
1250
|
}
|
|
1120
1251
|
return testFiles;
|
|
1121
1252
|
}
|
|
1122
|
-
function
|
|
1253
|
+
async function generateTestFileWithAI(scenario, session, ctx) {
|
|
1254
|
+
const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u4EE5\u4E0B BDD \u573A\u666F\u751F\u6210\u5B8C\u6574\u7684 Vitest \u6D4B\u8BD5\u4EE3\u7801\u3002
|
|
1255
|
+
|
|
1256
|
+
## \u529F\u80FD\u540D\u79F0
|
|
1257
|
+
${scenario.feature}
|
|
1258
|
+
|
|
1259
|
+
## BDD \u573A\u666F
|
|
1260
|
+
${scenario.scenarios.map((s) => `
|
|
1261
|
+
### ${s.name}
|
|
1262
|
+
- Given: ${s.given.join(", ")}
|
|
1263
|
+
- When: ${s.when.join(", ")}
|
|
1264
|
+
- Then: ${s.then.join(", ")}
|
|
1265
|
+
`).join("\n")}
|
|
1266
|
+
|
|
1267
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
1268
|
+
- \u6280\u672F\u6808: ${session.context?.techStack?.join(", ") || "TypeScript"}
|
|
1269
|
+
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
1270
|
+
|
|
1271
|
+
## \u8981\u6C42
|
|
1272
|
+
1. \u4F7F\u7528 vitest \u6D4B\u8BD5\u6846\u67B6 (describe, it, expect, beforeEach \u7B49)
|
|
1273
|
+
2. \u6BCF\u4E2A\u573A\u666F\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684\u6D4B\u8BD5\u7528\u4F8B
|
|
1274
|
+
3. \u6D4B\u8BD5\u4EE3\u7801\u8981\u5B8C\u6574\u53EF\u8FD0\u884C\uFF0C\u5305\u542B\u5FC5\u8981\u7684 mock \u548C setup
|
|
1275
|
+
4. \u4F7F\u7528\u4E2D\u6587\u6CE8\u91CA\u8BF4\u660E\u6D4B\u8BD5\u610F\u56FE
|
|
1276
|
+
5. \u6D4B\u8BD5\u8981\u8986\u76D6\u6B63\u5E38\u6D41\u7A0B\u548C\u8FB9\u754C\u60C5\u51B5
|
|
1277
|
+
|
|
1278
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801\uFF0C\u4E0D\u9700\u8981\u89E3\u91CA\u3002`;
|
|
1279
|
+
const response = await ctx.modelService.sendMessage([
|
|
1280
|
+
{ role: "user", content: prompt2 }
|
|
1281
|
+
], {
|
|
1282
|
+
temperature: 0.3,
|
|
1283
|
+
maxTokens: 4e3
|
|
1284
|
+
});
|
|
1285
|
+
const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
|
|
1286
|
+
if (codeMatch) {
|
|
1287
|
+
return codeMatch[1].trim();
|
|
1288
|
+
}
|
|
1289
|
+
return response.content;
|
|
1290
|
+
}
|
|
1291
|
+
function generateTestFile(scenario, session) {
|
|
1123
1292
|
const lines = [];
|
|
1124
|
-
lines.push(`import { describe, it, expect } from 'vitest';`);
|
|
1293
|
+
lines.push(`import { describe, it, expect, beforeEach } from 'vitest';`);
|
|
1125
1294
|
lines.push("");
|
|
1295
|
+
lines.push(`/**`);
|
|
1296
|
+
lines.push(` * ${scenario.feature} \u529F\u80FD\u6D4B\u8BD5`);
|
|
1297
|
+
lines.push(` * `);
|
|
1298
|
+
lines.push(` * BDD \u573A\u666F\u6570\u91CF: ${scenario.scenarios.length}`);
|
|
1299
|
+
if (session?.context?.techStack) {
|
|
1300
|
+
lines.push(` * \u6280\u672F\u6808: ${session.context.techStack.join(", ")}`);
|
|
1301
|
+
}
|
|
1302
|
+
lines.push(` */`);
|
|
1126
1303
|
lines.push(`describe('${scenario.feature}', () => {`);
|
|
1127
1304
|
for (const s of scenario.scenarios) {
|
|
1128
|
-
lines.push(` it('${s.name}', () => {`);
|
|
1129
|
-
lines.push(` // Given: ${s.given.join(", ")}`);
|
|
1130
|
-
lines.push(` // When: ${s.when.join(", ")}`);
|
|
1131
|
-
lines.push(` // Then: ${s.then.join(", ")}`);
|
|
1132
|
-
lines.push(` expect(true).toBe(true); // TODO: \u5B9E\u73B0\u6D4B\u8BD5`);
|
|
1133
|
-
lines.push(` });`);
|
|
1134
1305
|
lines.push("");
|
|
1306
|
+
lines.push(` /**`);
|
|
1307
|
+
lines.push(` * \u573A\u666F: ${s.name}`);
|
|
1308
|
+
lines.push(` * Given: ${s.given.join(", ")}`);
|
|
1309
|
+
lines.push(` * When: ${s.when.join(", ")}`);
|
|
1310
|
+
lines.push(` * Then: ${s.then.join(", ")}`);
|
|
1311
|
+
lines.push(` */`);
|
|
1312
|
+
lines.push(` it('${s.name}', async () => {`);
|
|
1313
|
+
lines.push(` // Arrange (Given)`);
|
|
1314
|
+
for (const g of s.given) {
|
|
1315
|
+
lines.push(` // ${g}`);
|
|
1316
|
+
}
|
|
1317
|
+
lines.push(` const input = {}; // TODO: \u8BBE\u7F6E\u521D\u59CB\u72B6\u6001`);
|
|
1318
|
+
lines.push("");
|
|
1319
|
+
lines.push(` // Act (When)`);
|
|
1320
|
+
for (const w of s.when) {
|
|
1321
|
+
lines.push(` // ${w}`);
|
|
1322
|
+
}
|
|
1323
|
+
lines.push(` const result = {}; // TODO: \u6267\u884C\u64CD\u4F5C`);
|
|
1324
|
+
lines.push("");
|
|
1325
|
+
lines.push(` // Assert (Then)`);
|
|
1326
|
+
for (const t of s.then) {
|
|
1327
|
+
lines.push(` // ${t}`);
|
|
1328
|
+
}
|
|
1329
|
+
lines.push(` expect(result).toBeDefined(); // TODO: \u5B8C\u5584\u65AD\u8A00`);
|
|
1330
|
+
lines.push(` });`);
|
|
1135
1331
|
}
|
|
1332
|
+
lines.push("");
|
|
1136
1333
|
lines.push(`});`);
|
|
1137
1334
|
return lines.join("\n");
|
|
1138
1335
|
}
|
|
@@ -1215,39 +1412,67 @@ function detectResourceType(url) {
|
|
|
1215
1412
|
return "webpage";
|
|
1216
1413
|
}
|
|
1217
1414
|
async function analyzeReferenceContent(url, content, type, ctx) {
|
|
1218
|
-
const typePrompts = {
|
|
1219
|
-
webpage: "\u5206\u6790\u8FD9\u4E2A\u7F51\u9875\u7684\u529F\u80FD\u3001UI\u7EC4\u4EF6\u548C\u4EA4\u4E92\u65B9\u5F0F",
|
|
1220
|
-
design: "\u5206\u6790\u8FD9\u4E2A\u8BBE\u8BA1\u7A3F\u7684\u5E03\u5C40\u3001\u7EC4\u4EF6\u548C\u6837\u5F0F",
|
|
1221
|
-
image: "\u63CF\u8FF0\u8FD9\u4E2A\u56FE\u7247\u7684\u5185\u5BB9\u548C\u8BBE\u8BA1\u5143\u7D20",
|
|
1222
|
-
api: "\u5206\u6790\u8FD9\u4E2AAPI\u7684\u7ED3\u6784\u548C\u53C2\u6570"
|
|
1223
|
-
};
|
|
1224
1415
|
const prompt2 = `
|
|
1225
|
-
\u8BF7\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\
|
|
1416
|
+
\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u4EA7\u54C1\u7ECF\u7406\u548C\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6DF1\u5165\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\uFF0C\u63D0\u53D6\u4E1A\u52A1\u529F\u80FD\u548C\u6280\u672F\u5B9E\u73B0\u7EC6\u8282\u3002
|
|
1417
|
+
|
|
1418
|
+
## \u53C2\u8003\u8D44\u6E90\u4FE1\u606F
|
|
1419
|
+
- URL: ${url}
|
|
1420
|
+
- \u7C7B\u578B: ${type}
|
|
1421
|
+
|
|
1422
|
+
## \u7F51\u9875\u5185\u5BB9
|
|
1423
|
+
\`\`\`html
|
|
1424
|
+
${content.slice(0, 8e3)}
|
|
1425
|
+
\`\`\`
|
|
1226
1426
|
|
|
1227
|
-
|
|
1228
|
-
\u7C7B\u578B: ${type}
|
|
1427
|
+
## \u5206\u6790\u8981\u6C42
|
|
1229
1428
|
|
|
1230
|
-
\
|
|
1231
|
-
${content.slice(0, 5e3)}
|
|
1429
|
+
\u8BF7\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u8FDB\u884C\u8BE6\u7EC6\u5206\u6790\uFF1A
|
|
1232
1430
|
|
|
1233
|
-
|
|
1431
|
+
### 1. \u4E1A\u52A1\u529F\u80FD\u5206\u6790
|
|
1432
|
+
- \u6838\u5FC3\u4E1A\u52A1\u529F\u80FD\u662F\u4EC0\u4E48\uFF1F\uFF08\u8BE6\u7EC6\u63CF\u8FF0\uFF09
|
|
1433
|
+
- \u7528\u6237\u53EF\u4EE5\u505A\u4EC0\u4E48\u64CD\u4F5C\uFF1F
|
|
1434
|
+
- \u4E1A\u52A1\u6D41\u7A0B\u662F\u4EC0\u4E48\uFF1F
|
|
1435
|
+
- \u6570\u636E\u8F93\u5165\u8F93\u51FA\u662F\u4EC0\u4E48\uFF1F
|
|
1234
1436
|
|
|
1235
|
-
\
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
1437
|
+
### 2. UI/UX \u7ED3\u6784\u5206\u6790
|
|
1438
|
+
- \u9875\u9762\u5E03\u5C40\u7ED3\u6784
|
|
1439
|
+
- \u4E3B\u8981\u7EC4\u4EF6\u6709\u54EA\u4E9B\uFF1F
|
|
1440
|
+
- \u7EC4\u4EF6\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
1441
|
+
- \u4EA4\u4E92\u65B9\u5F0F\uFF08\u70B9\u51FB\u3001\u8F93\u5165\u3001\u62D6\u62FD\u7B49\uFF09
|
|
1241
1442
|
|
|
1242
|
-
\
|
|
1443
|
+
### 3. \u6570\u636E\u6A21\u578B\u5206\u6790
|
|
1444
|
+
- \u9700\u8981\u54EA\u4E9B\u6570\u636E\uFF1F
|
|
1445
|
+
- \u6570\u636E\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
1446
|
+
- \u6570\u636E\u6765\u6E90\uFF08\u7528\u6237\u8F93\u5165/\u8BA1\u7B97/API\uFF09
|
|
1447
|
+
|
|
1448
|
+
### 4. \u529F\u80FD\u62C6\u5206\u5EFA\u8BAE
|
|
1449
|
+
\u8BF7\u5C06\u529F\u80FD\u62C6\u5206\u4E3A\u53EF\u72EC\u7ACB\u5F00\u53D1\u7684\u4EFB\u52A1\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5305\u542B\uFF1A
|
|
1450
|
+
- \u4EFB\u52A1\u540D\u79F0
|
|
1451
|
+
- \u4EFB\u52A1\u63CF\u8FF0
|
|
1452
|
+
- \u6280\u672F\u8981\u70B9
|
|
1453
|
+
- \u4F9D\u8D56\u5173\u7CFB
|
|
1454
|
+
|
|
1455
|
+
### 5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
1456
|
+
- \u63A8\u8350\u7684\u6280\u672F\u65B9\u6848
|
|
1457
|
+
- \u9700\u8981\u6CE8\u610F\u7684\u6280\u672F\u96BE\u70B9
|
|
1458
|
+
- \u6027\u80FD\u4F18\u5316\u5EFA\u8BAE
|
|
1459
|
+
|
|
1460
|
+
\u8BF7\u4EE5 Markdown \u683C\u5F0F\u8F93\u51FA\uFF0C\u91CD\u70B9\u7A81\u51FA\u4E1A\u52A1\u903B\u8F91\u548C\u529F\u80FD\u5B9E\u73B0\u7EC6\u8282\u3002
|
|
1243
1461
|
`;
|
|
1462
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
|
|
1463
|
+
loader.start();
|
|
1244
1464
|
try {
|
|
1245
1465
|
const response = await ctx.modelService.sendMessage([
|
|
1246
1466
|
{ role: "user", content: prompt2 }
|
|
1247
|
-
], {
|
|
1467
|
+
], {
|
|
1468
|
+
temperature: 0.3,
|
|
1469
|
+
maxTokens: 4e3
|
|
1470
|
+
});
|
|
1471
|
+
loader.stop(chalk9__default.default.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
|
|
1248
1472
|
return response.content;
|
|
1249
|
-
} catch {
|
|
1250
|
-
|
|
1473
|
+
} catch (error) {
|
|
1474
|
+
loader.stop();
|
|
1475
|
+
throw error;
|
|
1251
1476
|
}
|
|
1252
1477
|
}
|
|
1253
1478
|
function extractBasicInfo(content, type) {
|
|
@@ -1288,10 +1513,43 @@ function getActiveSession() {
|
|
|
1288
1513
|
function clearActiveSession() {
|
|
1289
1514
|
activeSession = null;
|
|
1290
1515
|
}
|
|
1291
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
1516
|
+
var LoadingIndicator, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
1292
1517
|
var init_new = __esm({
|
|
1293
1518
|
"src/commands/new.ts"() {
|
|
1294
1519
|
init_cjs_shims();
|
|
1520
|
+
LoadingIndicator = class {
|
|
1521
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1522
|
+
frameIndex = 0;
|
|
1523
|
+
interval = null;
|
|
1524
|
+
message;
|
|
1525
|
+
constructor(message) {
|
|
1526
|
+
this.message = message;
|
|
1527
|
+
}
|
|
1528
|
+
start() {
|
|
1529
|
+
process.stdout.write("\x1B[?25l");
|
|
1530
|
+
this.interval = setInterval(() => {
|
|
1531
|
+
const frame = this.frames[this.frameIndex];
|
|
1532
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
1533
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
1534
|
+
}, 80);
|
|
1535
|
+
}
|
|
1536
|
+
update(message) {
|
|
1537
|
+
this.message = message;
|
|
1538
|
+
}
|
|
1539
|
+
stop(finalMessage) {
|
|
1540
|
+
if (this.interval) {
|
|
1541
|
+
clearInterval(this.interval);
|
|
1542
|
+
this.interval = null;
|
|
1543
|
+
}
|
|
1544
|
+
process.stdout.write("\x1B[?25h");
|
|
1545
|
+
if (finalMessage) {
|
|
1546
|
+
process.stdout.write(`\r${finalMessage}
|
|
1547
|
+
`);
|
|
1548
|
+
} else {
|
|
1549
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1295
1553
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
1296
1554
|
COMPLEXITY_THRESHOLD = 6;
|
|
1297
1555
|
CLARITY_THRESHOLD = 0.6;
|