@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.mjs
CHANGED
|
@@ -194,12 +194,26 @@ ${resource.analysis}`;
|
|
|
194
194
|
lines.push("");
|
|
195
195
|
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
196
196
|
lines.push("");
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
activeSession.
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
|
|
198
|
+
loader.start();
|
|
199
|
+
try {
|
|
200
|
+
activeSession.bddScenarios = await generateBDDScenariosWithAI(
|
|
201
|
+
activeSession.refinedRequirement,
|
|
202
|
+
activeSession.context,
|
|
203
|
+
activeSession.clarificationQuestions,
|
|
204
|
+
activeSession.referenceResources,
|
|
205
|
+
ctx
|
|
206
|
+
);
|
|
207
|
+
loader.stop(chalk9.green(" \u2713 BDD \u573A\u666F\u5DF2\u751F\u6210"));
|
|
208
|
+
} catch {
|
|
209
|
+
loader.stop(chalk9.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840 BDD \u751F\u6210"));
|
|
210
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
211
|
+
activeSession.refinedRequirement,
|
|
212
|
+
activeSession.context,
|
|
213
|
+
activeSession.clarificationQuestions,
|
|
214
|
+
activeSession.referenceResources
|
|
215
|
+
);
|
|
216
|
+
}
|
|
203
217
|
for (const scenario of activeSession.bddScenarios) {
|
|
204
218
|
lines.push(chalk9.white(` Feature: ${scenario.feature}`));
|
|
205
219
|
for (const s of scenario.scenarios.slice(0, 3)) {
|
|
@@ -246,7 +260,7 @@ ${resource.analysis}`;
|
|
|
246
260
|
lines.push("");
|
|
247
261
|
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/9: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
248
262
|
lines.push("");
|
|
249
|
-
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
263
|
+
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession, ctx);
|
|
250
264
|
lines.push(chalk9.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
251
265
|
for (const file of activeSession.testFiles) {
|
|
252
266
|
lines.push(chalk9.gray(` - ${file}`));
|
|
@@ -543,6 +557,8 @@ function getCategoryLabel(category) {
|
|
|
543
557
|
async function executeDevelopment(ctx, session) {
|
|
544
558
|
const workingDir = ctx.options.workingDirectory;
|
|
545
559
|
const files = [];
|
|
560
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210\u4EE3\u7801");
|
|
561
|
+
loader.start();
|
|
546
562
|
try {
|
|
547
563
|
const systemPrompt = buildDevelopmentPrompt(session);
|
|
548
564
|
const messages = [
|
|
@@ -570,11 +586,15 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
570
586
|
content: systemPrompt
|
|
571
587
|
}
|
|
572
588
|
];
|
|
589
|
+
loader.update("\u6B63\u5728\u8C03\u7528 AI \u6A21\u578B");
|
|
573
590
|
const response = await ctx.modelService.sendMessage(messages, {
|
|
574
591
|
temperature: 0.3,
|
|
575
592
|
maxTokens: 8e3,
|
|
576
|
-
agent: "frontend-dev"
|
|
593
|
+
agent: "frontend-dev",
|
|
594
|
+
timeout: 18e4
|
|
595
|
+
// 3 分钟超时
|
|
577
596
|
});
|
|
597
|
+
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
578
598
|
const codeBlocks = parseCodeBlocks(response.content);
|
|
579
599
|
for (const block of codeBlocks) {
|
|
580
600
|
const filePath = path5.join(workingDir, block.filename);
|
|
@@ -603,8 +623,10 @@ export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
|
603
623
|
await fs4.writeFile(filePath, stubCode, "utf-8");
|
|
604
624
|
files.push(`src/features/${fileName}`);
|
|
605
625
|
}
|
|
626
|
+
loader.stop(chalk9.green(` \u2713 \u5DF2\u751F\u6210 ${files.length} \u4E2A\u6587\u4EF6`));
|
|
606
627
|
return { success: true, files };
|
|
607
628
|
} catch (error) {
|
|
629
|
+
loader.stop();
|
|
608
630
|
return {
|
|
609
631
|
success: false,
|
|
610
632
|
files: [],
|
|
@@ -888,36 +910,125 @@ function generateBDDScenarios(requirement, context, questions, references = [])
|
|
|
888
910
|
}
|
|
889
911
|
return scenarios;
|
|
890
912
|
}
|
|
913
|
+
async function generateBDDScenariosWithAI(requirement, context, questions, references, ctx) {
|
|
914
|
+
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
|
|
915
|
+
|
|
916
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
917
|
+
${requirement}
|
|
918
|
+
|
|
919
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
920
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "\u672A\u6307\u5B9A"}
|
|
921
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
922
|
+
|
|
923
|
+
## \u6F84\u6E05\u95EE\u7B54
|
|
924
|
+
${questions.filter((q) => q.answered).map((q) => `- Q: ${q.question}
|
|
925
|
+
A: ${q.answer}`).join("\n")}
|
|
926
|
+
|
|
927
|
+
## \u53C2\u8003\u8D44\u6E90\u5206\u6790
|
|
928
|
+
${references.map((r) => `### ${r.url}
|
|
929
|
+
${r.analysis}`).join("\n\n")}
|
|
930
|
+
|
|
931
|
+
## \u8981\u6C42
|
|
932
|
+
1. \u6BCF\u4E2A\u529F\u80FD\u6A21\u5757\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684 Feature
|
|
933
|
+
2. \u6BCF\u4E2A Feature \u5305\u542B\u591A\u4E2A\u5177\u4F53\u7684 Scenario
|
|
934
|
+
3. \u4F7F\u7528 Given-When-Then \u683C\u5F0F
|
|
935
|
+
4. \u573A\u666F\u8981\u8986\u76D6: \u6B63\u5E38\u6D41\u7A0B\u3001\u8FB9\u754C\u60C5\u51B5\u3001\u5F02\u5E38\u5904\u7406
|
|
936
|
+
5. \u573A\u666F\u8981\u5177\u4F53\u53EF\u6D4B\u8BD5\uFF0C\u4E0D\u8981\u6CDB\u6CDB\u800C\u8C08
|
|
937
|
+
|
|
938
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
939
|
+
\`\`\`json
|
|
940
|
+
[
|
|
941
|
+
{
|
|
942
|
+
"feature": "\u529F\u80FD\u540D\u79F0",
|
|
943
|
+
"description": "\u529F\u80FD\u63CF\u8FF0",
|
|
944
|
+
"scenarios": [
|
|
945
|
+
{
|
|
946
|
+
"name": "\u573A\u666F\u540D\u79F0",
|
|
947
|
+
"given": ["\u524D\u7F6E\u6761\u4EF61", "\u524D\u7F6E\u6761\u4EF62"],
|
|
948
|
+
"when": ["\u64CD\u4F5C1", "\u64CD\u4F5C2"],
|
|
949
|
+
"then": ["\u9884\u671F\u7ED3\u679C1", "\u9884\u671F\u7ED3\u679C2"]
|
|
950
|
+
}
|
|
951
|
+
]
|
|
952
|
+
}
|
|
953
|
+
]
|
|
954
|
+
\`\`\`
|
|
955
|
+
|
|
956
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u6709\u5176\u4ED6\u5185\u5BB9\u3002`;
|
|
957
|
+
const response = await ctx.modelService.sendMessage([
|
|
958
|
+
{ role: "user", content: prompt2 }
|
|
959
|
+
], {
|
|
960
|
+
temperature: 0.3,
|
|
961
|
+
maxTokens: 4e3,
|
|
962
|
+
timeout: 12e4
|
|
963
|
+
});
|
|
964
|
+
try {
|
|
965
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
966
|
+
if (jsonMatch) {
|
|
967
|
+
return JSON.parse(jsonMatch[1].trim());
|
|
968
|
+
}
|
|
969
|
+
return JSON.parse(response.content);
|
|
970
|
+
} catch {
|
|
971
|
+
return generateBDDScenarios(requirement, context, questions, references);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
891
974
|
function extractFeaturesFromReference(ref) {
|
|
892
975
|
const features = [];
|
|
893
|
-
const analysis = ref.analysis
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
905
|
-
hasInput: false
|
|
906
|
-
});
|
|
976
|
+
const analysis = ref.analysis;
|
|
977
|
+
const featureSection = analysis.match(/###?\s*4\.\s*功能拆分建议[\s\S]*?(?=###?\s*\d|$)/i);
|
|
978
|
+
if (featureSection) {
|
|
979
|
+
const taskMatches = featureSection[0].matchAll(/[-*]\s*\*\*([^*]+)\*\*[::]?\s*([^\n]+)/g);
|
|
980
|
+
for (const match of taskMatches) {
|
|
981
|
+
features.push({
|
|
982
|
+
title: match[1].trim(),
|
|
983
|
+
description: match[2].trim(),
|
|
984
|
+
hasInput: match[2].includes("\u8F93\u5165") || match[2].includes("\u8868\u5355") || match[2].includes("\u7528\u6237")
|
|
985
|
+
});
|
|
986
|
+
}
|
|
907
987
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
988
|
+
const bizSection = analysis.match(/###?\s*1\.\s*业务功能分析[\s\S]*?(?=###?\s*\d|$)/i);
|
|
989
|
+
if (bizSection && features.length === 0) {
|
|
990
|
+
const lines = bizSection[0].split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*"));
|
|
991
|
+
for (const line of lines.slice(0, 5)) {
|
|
992
|
+
const content = line.replace(/^[-*]\s*/, "").trim();
|
|
993
|
+
if (content.length > 5) {
|
|
994
|
+
features.push({
|
|
995
|
+
title: content.slice(0, 20),
|
|
996
|
+
description: content,
|
|
997
|
+
hasInput: content.includes("\u8F93\u5165") || content.includes("\u586B\u5199")
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
914
1001
|
}
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1002
|
+
if (features.length === 0) {
|
|
1003
|
+
const lowerAnalysis = analysis.toLowerCase();
|
|
1004
|
+
if (lowerAnalysis.includes("\u8F93\u5165") || lowerAnalysis.includes("\u8868\u5355")) {
|
|
1005
|
+
features.push({
|
|
1006
|
+
title: "\u8F93\u5165\u8868\u5355",
|
|
1007
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
|
|
1008
|
+
hasInput: true
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
if (lowerAnalysis.includes("\u6309\u94AE") || lowerAnalysis.includes("\u64CD\u4F5C")) {
|
|
1012
|
+
features.push({
|
|
1013
|
+
title: "\u4EA4\u4E92\u6309\u94AE",
|
|
1014
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
1015
|
+
hasInput: false
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
if (lowerAnalysis.includes("\u8868\u683C") || lowerAnalysis.includes("\u5217\u8868")) {
|
|
1019
|
+
features.push({
|
|
1020
|
+
title: "\u6570\u636E\u5217\u8868",
|
|
1021
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
|
|
1022
|
+
hasInput: false
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
if (lowerAnalysis.includes("\u56FE\u8868") || lowerAnalysis.includes("\u53EF\u89C6\u5316")) {
|
|
1026
|
+
features.push({
|
|
1027
|
+
title: "\u56FE\u8868\u5C55\u793A",
|
|
1028
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
|
|
1029
|
+
hasInput: false
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
921
1032
|
}
|
|
922
1033
|
if (features.length === 0) {
|
|
923
1034
|
features.push({
|
|
@@ -1081,33 +1192,119 @@ function formatSpecFile(session) {
|
|
|
1081
1192
|
lines.push("**\u786E\u8BA4\u72B6\u6001**: \u23F3 \u7B49\u5F85\u786E\u8BA4");
|
|
1082
1193
|
return lines.join("\n");
|
|
1083
1194
|
}
|
|
1084
|
-
async function generateTests(workingDir, session) {
|
|
1195
|
+
async function generateTests(workingDir, session, ctx) {
|
|
1085
1196
|
const testDir = path5.join(workingDir, "tests");
|
|
1086
1197
|
await fs4.mkdir(testDir, { recursive: true });
|
|
1087
1198
|
const testFiles = [];
|
|
1088
|
-
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1199
|
+
if (ctx?.modelService) {
|
|
1200
|
+
for (const scenario of session.bddScenarios) {
|
|
1201
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1202
|
+
const testPath = path5.join(testDir, `${testName}.test.ts`);
|
|
1203
|
+
const loader = new LoadingIndicator(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
|
|
1204
|
+
loader.start();
|
|
1205
|
+
try {
|
|
1206
|
+
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
1207
|
+
await fs4.writeFile(testPath, content, "utf-8");
|
|
1208
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1209
|
+
loader.stop(chalk9.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
|
|
1210
|
+
} catch {
|
|
1211
|
+
const content = generateTestFile(scenario, session);
|
|
1212
|
+
await fs4.writeFile(testPath, content, "utf-8");
|
|
1213
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1214
|
+
loader.stop(chalk9.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
} else {
|
|
1218
|
+
for (const scenario of session.bddScenarios) {
|
|
1219
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1220
|
+
const testPath = path5.join(testDir, `${testName}.test.ts`);
|
|
1221
|
+
const content = generateTestFile(scenario, session);
|
|
1222
|
+
await fs4.writeFile(testPath, content, "utf-8");
|
|
1223
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
1224
|
+
}
|
|
1094
1225
|
}
|
|
1095
1226
|
return testFiles;
|
|
1096
1227
|
}
|
|
1097
|
-
function
|
|
1228
|
+
async function generateTestFileWithAI(scenario, session, ctx) {
|
|
1229
|
+
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
|
|
1230
|
+
|
|
1231
|
+
## \u529F\u80FD\u540D\u79F0
|
|
1232
|
+
${scenario.feature}
|
|
1233
|
+
|
|
1234
|
+
## BDD \u573A\u666F
|
|
1235
|
+
${scenario.scenarios.map((s) => `
|
|
1236
|
+
### ${s.name}
|
|
1237
|
+
- Given: ${s.given.join(", ")}
|
|
1238
|
+
- When: ${s.when.join(", ")}
|
|
1239
|
+
- Then: ${s.then.join(", ")}
|
|
1240
|
+
`).join("\n")}
|
|
1241
|
+
|
|
1242
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
1243
|
+
- \u6280\u672F\u6808: ${session.context?.techStack?.join(", ") || "TypeScript"}
|
|
1244
|
+
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
1245
|
+
|
|
1246
|
+
## \u8981\u6C42
|
|
1247
|
+
1. \u4F7F\u7528 vitest \u6D4B\u8BD5\u6846\u67B6 (describe, it, expect, beforeEach \u7B49)
|
|
1248
|
+
2. \u6BCF\u4E2A\u573A\u666F\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684\u6D4B\u8BD5\u7528\u4F8B
|
|
1249
|
+
3. \u6D4B\u8BD5\u4EE3\u7801\u8981\u5B8C\u6574\u53EF\u8FD0\u884C\uFF0C\u5305\u542B\u5FC5\u8981\u7684 mock \u548C setup
|
|
1250
|
+
4. \u4F7F\u7528\u4E2D\u6587\u6CE8\u91CA\u8BF4\u660E\u6D4B\u8BD5\u610F\u56FE
|
|
1251
|
+
5. \u6D4B\u8BD5\u8981\u8986\u76D6\u6B63\u5E38\u6D41\u7A0B\u548C\u8FB9\u754C\u60C5\u51B5
|
|
1252
|
+
|
|
1253
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801\uFF0C\u4E0D\u9700\u8981\u89E3\u91CA\u3002`;
|
|
1254
|
+
const response = await ctx.modelService.sendMessage([
|
|
1255
|
+
{ role: "user", content: prompt2 }
|
|
1256
|
+
], {
|
|
1257
|
+
temperature: 0.3,
|
|
1258
|
+
maxTokens: 4e3
|
|
1259
|
+
});
|
|
1260
|
+
const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
|
|
1261
|
+
if (codeMatch) {
|
|
1262
|
+
return codeMatch[1].trim();
|
|
1263
|
+
}
|
|
1264
|
+
return response.content;
|
|
1265
|
+
}
|
|
1266
|
+
function generateTestFile(scenario, session) {
|
|
1098
1267
|
const lines = [];
|
|
1099
|
-
lines.push(`import { describe, it, expect } from 'vitest';`);
|
|
1268
|
+
lines.push(`import { describe, it, expect, beforeEach } from 'vitest';`);
|
|
1100
1269
|
lines.push("");
|
|
1270
|
+
lines.push(`/**`);
|
|
1271
|
+
lines.push(` * ${scenario.feature} \u529F\u80FD\u6D4B\u8BD5`);
|
|
1272
|
+
lines.push(` * `);
|
|
1273
|
+
lines.push(` * BDD \u573A\u666F\u6570\u91CF: ${scenario.scenarios.length}`);
|
|
1274
|
+
if (session?.context?.techStack) {
|
|
1275
|
+
lines.push(` * \u6280\u672F\u6808: ${session.context.techStack.join(", ")}`);
|
|
1276
|
+
}
|
|
1277
|
+
lines.push(` */`);
|
|
1101
1278
|
lines.push(`describe('${scenario.feature}', () => {`);
|
|
1102
1279
|
for (const s of scenario.scenarios) {
|
|
1103
|
-
lines.push(` it('${s.name}', () => {`);
|
|
1104
|
-
lines.push(` // Given: ${s.given.join(", ")}`);
|
|
1105
|
-
lines.push(` // When: ${s.when.join(", ")}`);
|
|
1106
|
-
lines.push(` // Then: ${s.then.join(", ")}`);
|
|
1107
|
-
lines.push(` expect(true).toBe(true); // TODO: \u5B9E\u73B0\u6D4B\u8BD5`);
|
|
1108
|
-
lines.push(` });`);
|
|
1109
1280
|
lines.push("");
|
|
1281
|
+
lines.push(` /**`);
|
|
1282
|
+
lines.push(` * \u573A\u666F: ${s.name}`);
|
|
1283
|
+
lines.push(` * Given: ${s.given.join(", ")}`);
|
|
1284
|
+
lines.push(` * When: ${s.when.join(", ")}`);
|
|
1285
|
+
lines.push(` * Then: ${s.then.join(", ")}`);
|
|
1286
|
+
lines.push(` */`);
|
|
1287
|
+
lines.push(` it('${s.name}', async () => {`);
|
|
1288
|
+
lines.push(` // Arrange (Given)`);
|
|
1289
|
+
for (const g of s.given) {
|
|
1290
|
+
lines.push(` // ${g}`);
|
|
1291
|
+
}
|
|
1292
|
+
lines.push(` const input = {}; // TODO: \u8BBE\u7F6E\u521D\u59CB\u72B6\u6001`);
|
|
1293
|
+
lines.push("");
|
|
1294
|
+
lines.push(` // Act (When)`);
|
|
1295
|
+
for (const w of s.when) {
|
|
1296
|
+
lines.push(` // ${w}`);
|
|
1297
|
+
}
|
|
1298
|
+
lines.push(` const result = {}; // TODO: \u6267\u884C\u64CD\u4F5C`);
|
|
1299
|
+
lines.push("");
|
|
1300
|
+
lines.push(` // Assert (Then)`);
|
|
1301
|
+
for (const t of s.then) {
|
|
1302
|
+
lines.push(` // ${t}`);
|
|
1303
|
+
}
|
|
1304
|
+
lines.push(` expect(result).toBeDefined(); // TODO: \u5B8C\u5584\u65AD\u8A00`);
|
|
1305
|
+
lines.push(` });`);
|
|
1110
1306
|
}
|
|
1307
|
+
lines.push("");
|
|
1111
1308
|
lines.push(`});`);
|
|
1112
1309
|
return lines.join("\n");
|
|
1113
1310
|
}
|
|
@@ -1190,39 +1387,67 @@ function detectResourceType(url) {
|
|
|
1190
1387
|
return "webpage";
|
|
1191
1388
|
}
|
|
1192
1389
|
async function analyzeReferenceContent(url, content, type, ctx) {
|
|
1193
|
-
const typePrompts = {
|
|
1194
|
-
webpage: "\u5206\u6790\u8FD9\u4E2A\u7F51\u9875\u7684\u529F\u80FD\u3001UI\u7EC4\u4EF6\u548C\u4EA4\u4E92\u65B9\u5F0F",
|
|
1195
|
-
design: "\u5206\u6790\u8FD9\u4E2A\u8BBE\u8BA1\u7A3F\u7684\u5E03\u5C40\u3001\u7EC4\u4EF6\u548C\u6837\u5F0F",
|
|
1196
|
-
image: "\u63CF\u8FF0\u8FD9\u4E2A\u56FE\u7247\u7684\u5185\u5BB9\u548C\u8BBE\u8BA1\u5143\u7D20",
|
|
1197
|
-
api: "\u5206\u6790\u8FD9\u4E2AAPI\u7684\u7ED3\u6784\u548C\u53C2\u6570"
|
|
1198
|
-
};
|
|
1199
1390
|
const prompt2 = `
|
|
1200
|
-
\u8BF7\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\
|
|
1391
|
+
\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
|
|
1392
|
+
|
|
1393
|
+
## \u53C2\u8003\u8D44\u6E90\u4FE1\u606F
|
|
1394
|
+
- URL: ${url}
|
|
1395
|
+
- \u7C7B\u578B: ${type}
|
|
1396
|
+
|
|
1397
|
+
## \u7F51\u9875\u5185\u5BB9
|
|
1398
|
+
\`\`\`html
|
|
1399
|
+
${content.slice(0, 8e3)}
|
|
1400
|
+
\`\`\`
|
|
1201
1401
|
|
|
1202
|
-
|
|
1203
|
-
\u7C7B\u578B: ${type}
|
|
1402
|
+
## \u5206\u6790\u8981\u6C42
|
|
1204
1403
|
|
|
1205
|
-
\
|
|
1206
|
-
${content.slice(0, 5e3)}
|
|
1404
|
+
\u8BF7\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u8FDB\u884C\u8BE6\u7EC6\u5206\u6790\uFF1A
|
|
1207
1405
|
|
|
1208
|
-
|
|
1406
|
+
### 1. \u4E1A\u52A1\u529F\u80FD\u5206\u6790
|
|
1407
|
+
- \u6838\u5FC3\u4E1A\u52A1\u529F\u80FD\u662F\u4EC0\u4E48\uFF1F\uFF08\u8BE6\u7EC6\u63CF\u8FF0\uFF09
|
|
1408
|
+
- \u7528\u6237\u53EF\u4EE5\u505A\u4EC0\u4E48\u64CD\u4F5C\uFF1F
|
|
1409
|
+
- \u4E1A\u52A1\u6D41\u7A0B\u662F\u4EC0\u4E48\uFF1F
|
|
1410
|
+
- \u6570\u636E\u8F93\u5165\u8F93\u51FA\u662F\u4EC0\u4E48\uFF1F
|
|
1209
1411
|
|
|
1210
|
-
\
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
1412
|
+
### 2. UI/UX \u7ED3\u6784\u5206\u6790
|
|
1413
|
+
- \u9875\u9762\u5E03\u5C40\u7ED3\u6784
|
|
1414
|
+
- \u4E3B\u8981\u7EC4\u4EF6\u6709\u54EA\u4E9B\uFF1F
|
|
1415
|
+
- \u7EC4\u4EF6\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
1416
|
+
- \u4EA4\u4E92\u65B9\u5F0F\uFF08\u70B9\u51FB\u3001\u8F93\u5165\u3001\u62D6\u62FD\u7B49\uFF09
|
|
1216
1417
|
|
|
1217
|
-
\
|
|
1418
|
+
### 3. \u6570\u636E\u6A21\u578B\u5206\u6790
|
|
1419
|
+
- \u9700\u8981\u54EA\u4E9B\u6570\u636E\uFF1F
|
|
1420
|
+
- \u6570\u636E\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
1421
|
+
- \u6570\u636E\u6765\u6E90\uFF08\u7528\u6237\u8F93\u5165/\u8BA1\u7B97/API\uFF09
|
|
1422
|
+
|
|
1423
|
+
### 4. \u529F\u80FD\u62C6\u5206\u5EFA\u8BAE
|
|
1424
|
+
\u8BF7\u5C06\u529F\u80FD\u62C6\u5206\u4E3A\u53EF\u72EC\u7ACB\u5F00\u53D1\u7684\u4EFB\u52A1\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5305\u542B\uFF1A
|
|
1425
|
+
- \u4EFB\u52A1\u540D\u79F0
|
|
1426
|
+
- \u4EFB\u52A1\u63CF\u8FF0
|
|
1427
|
+
- \u6280\u672F\u8981\u70B9
|
|
1428
|
+
- \u4F9D\u8D56\u5173\u7CFB
|
|
1429
|
+
|
|
1430
|
+
### 5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
1431
|
+
- \u63A8\u8350\u7684\u6280\u672F\u65B9\u6848
|
|
1432
|
+
- \u9700\u8981\u6CE8\u610F\u7684\u6280\u672F\u96BE\u70B9
|
|
1433
|
+
- \u6027\u80FD\u4F18\u5316\u5EFA\u8BAE
|
|
1434
|
+
|
|
1435
|
+
\u8BF7\u4EE5 Markdown \u683C\u5F0F\u8F93\u51FA\uFF0C\u91CD\u70B9\u7A81\u51FA\u4E1A\u52A1\u903B\u8F91\u548C\u529F\u80FD\u5B9E\u73B0\u7EC6\u8282\u3002
|
|
1218
1436
|
`;
|
|
1437
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
|
|
1438
|
+
loader.start();
|
|
1219
1439
|
try {
|
|
1220
1440
|
const response = await ctx.modelService.sendMessage([
|
|
1221
1441
|
{ role: "user", content: prompt2 }
|
|
1222
|
-
], {
|
|
1442
|
+
], {
|
|
1443
|
+
temperature: 0.3,
|
|
1444
|
+
maxTokens: 4e3
|
|
1445
|
+
});
|
|
1446
|
+
loader.stop(chalk9.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
|
|
1223
1447
|
return response.content;
|
|
1224
|
-
} catch {
|
|
1225
|
-
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
loader.stop();
|
|
1450
|
+
throw error;
|
|
1226
1451
|
}
|
|
1227
1452
|
}
|
|
1228
1453
|
function extractBasicInfo(content, type) {
|
|
@@ -1263,10 +1488,43 @@ function getActiveSession() {
|
|
|
1263
1488
|
function clearActiveSession() {
|
|
1264
1489
|
activeSession = null;
|
|
1265
1490
|
}
|
|
1266
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
1491
|
+
var LoadingIndicator, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
1267
1492
|
var init_new = __esm({
|
|
1268
1493
|
"src/commands/new.ts"() {
|
|
1269
1494
|
init_esm_shims();
|
|
1495
|
+
LoadingIndicator = class {
|
|
1496
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1497
|
+
frameIndex = 0;
|
|
1498
|
+
interval = null;
|
|
1499
|
+
message;
|
|
1500
|
+
constructor(message) {
|
|
1501
|
+
this.message = message;
|
|
1502
|
+
}
|
|
1503
|
+
start() {
|
|
1504
|
+
process.stdout.write("\x1B[?25l");
|
|
1505
|
+
this.interval = setInterval(() => {
|
|
1506
|
+
const frame = this.frames[this.frameIndex];
|
|
1507
|
+
process.stdout.write(`\r${chalk9.cyan(frame)} ${this.message}...`);
|
|
1508
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
1509
|
+
}, 80);
|
|
1510
|
+
}
|
|
1511
|
+
update(message) {
|
|
1512
|
+
this.message = message;
|
|
1513
|
+
}
|
|
1514
|
+
stop(finalMessage) {
|
|
1515
|
+
if (this.interval) {
|
|
1516
|
+
clearInterval(this.interval);
|
|
1517
|
+
this.interval = null;
|
|
1518
|
+
}
|
|
1519
|
+
process.stdout.write("\x1B[?25h");
|
|
1520
|
+
if (finalMessage) {
|
|
1521
|
+
process.stdout.write(`\r${finalMessage}
|
|
1522
|
+
`);
|
|
1523
|
+
} else {
|
|
1524
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1270
1528
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
1271
1529
|
COMPLEXITY_THRESHOLD = 6;
|
|
1272
1530
|
CLARITY_THRESHOLD = 0.6;
|