@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.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
- activeSession.bddScenarios = generateBDDScenarios(
198
- activeSession.refinedRequirement,
199
- activeSession.context,
200
- activeSession.clarificationQuestions,
201
- activeSession.referenceResources
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.toLowerCase();
894
- if (analysis.includes("\u8F93\u5165") || analysis.includes("\u8868\u5355")) {
895
- features.push({
896
- title: "\u8F93\u5165\u8868\u5355",
897
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
898
- hasInput: true
899
- });
900
- }
901
- if (analysis.includes("\u6309\u94AE") || analysis.includes("\u64CD\u4F5C")) {
902
- features.push({
903
- title: "\u4EA4\u4E92\u6309\u94AE",
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
- if (analysis.includes("\u8868\u683C") || analysis.includes("\u5217\u8868")) {
909
- features.push({
910
- title: "\u6570\u636E\u5217\u8868",
911
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
912
- hasInput: false
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 (analysis.includes("\u56FE\u8868") || analysis.includes("\u53EF\u89C6\u5316")) {
916
- features.push({
917
- title: "\u56FE\u8868\u5C55\u793A",
918
- description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
919
- hasInput: false
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
- for (const scenario of session.bddScenarios) {
1089
- const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
1090
- const testPath = path5.join(testDir, `${testName}.test.ts`);
1091
- const content = generateTestFile(scenario);
1092
- await fs4.writeFile(testPath, content, "utf-8");
1093
- testFiles.push(`tests/${testName}.test.ts`);
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 generateTestFile(scenario) {
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\u7684 URL\uFF0C\u63D0\u53D6\u5BF9\u5F00\u53D1\u6709\u7528\u7684\u4FE1\u606F\uFF1A
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
- URL: ${url}
1203
- \u7C7B\u578B: ${type}
1402
+ ## \u5206\u6790\u8981\u6C42
1204
1403
 
1205
- \u5185\u5BB9\u6458\u8981:
1206
- ${content.slice(0, 5e3)}
1404
+ \u8BF7\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u8FDB\u884C\u8BE6\u7EC6\u5206\u6790\uFF1A
1207
1405
 
1208
- ${typePrompts[type]}
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
- \u8BF7\u63D0\u53D6\uFF1A
1211
- 1. \u4E3B\u8981\u529F\u80FD\u70B9
1212
- 2. UI\u7EC4\u4EF6\u7ED3\u6784
1213
- 3. \u4EA4\u4E92\u65B9\u5F0F
1214
- 4. \u6570\u636E\u7ED3\u6784\uFF08\u5982\u679C\u6709\uFF09
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
- \u4EE5\u7B80\u6D01\u7684\u8981\u70B9\u5F62\u5F0F\u8F93\u51FA\u3002
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
- ], { temperature: 0.3, maxTokens: 2e3 });
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
- return extractBasicInfo(content, type);
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;