@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/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
- activeSession.bddScenarios = generateBDDScenarios(
223
- activeSession.refinedRequirement,
224
- activeSession.context,
225
- activeSession.clarificationQuestions,
226
- activeSession.referenceResources
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.toLowerCase();
919
- if (analysis.includes("\u8F93\u5165") || analysis.includes("\u8868\u5355")) {
920
- features.push({
921
- title: "\u8F93\u5165\u8868\u5355",
922
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
923
- hasInput: true
924
- });
925
- }
926
- if (analysis.includes("\u6309\u94AE") || analysis.includes("\u64CD\u4F5C")) {
927
- features.push({
928
- title: "\u4EA4\u4E92\u6309\u94AE",
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
- if (analysis.includes("\u8868\u683C") || analysis.includes("\u5217\u8868")) {
934
- features.push({
935
- title: "\u6570\u636E\u5217\u8868",
936
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
937
- hasInput: false
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 (analysis.includes("\u56FE\u8868") || analysis.includes("\u53EF\u89C6\u5316")) {
941
- features.push({
942
- title: "\u56FE\u8868\u5C55\u793A",
943
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
944
- hasInput: false
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
- for (const scenario of session.bddScenarios) {
1114
- const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
1115
- const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
1116
- const content = generateTestFile(scenario);
1117
- await fs4__namespace.writeFile(testPath, content, "utf-8");
1118
- testFiles.push(`tests/${testName}.test.ts`);
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 generateTestFile(scenario) {
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\u7684 URL\uFF0C\u63D0\u53D6\u5BF9\u5F00\u53D1\u6709\u7528\u7684\u4FE1\u606F\uFF1A
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
- URL: ${url}
1228
- \u7C7B\u578B: ${type}
1427
+ ## \u5206\u6790\u8981\u6C42
1229
1428
 
1230
- \u5185\u5BB9\u6458\u8981:
1231
- ${content.slice(0, 5e3)}
1429
+ \u8BF7\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u8FDB\u884C\u8BE6\u7EC6\u5206\u6790\uFF1A
1232
1430
 
1233
- ${typePrompts[type]}
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
- \u8BF7\u63D0\u53D6\uFF1A
1236
- 1. \u4E3B\u8981\u529F\u80FD\u70B9
1237
- 2. UI\u7EC4\u4EF6\u7ED3\u6784
1238
- 3. \u4EA4\u4E92\u65B9\u5F0F
1239
- 4. \u6570\u636E\u7ED3\u6784\uFF08\u5982\u679C\u6709\uFF09
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
- \u4EE5\u7B80\u6D01\u7684\u8981\u70B9\u5F62\u5F0F\u8F93\u51FA\u3002
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
- ], { temperature: 0.3, maxTokens: 2e3 });
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
- return extractBasicInfo(content, type);
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;