@nick848/sf-cli 1.0.21 → 1.0.22

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
@@ -104,7 +104,10 @@ async function executeWorkflow(ctx) {
104
104
  if (activeSession.phase === "context") {
105
105
  lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/9: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
106
106
  lines.push("");
107
+ const loader = new LoadingIndicator2("\u8BFB\u53D6\u9879\u76EE\u914D\u7F6E");
108
+ loader.start();
107
109
  activeSession.context = await readProjectContext(ctx.options.workingDirectory);
110
+ loader.stop();
108
111
  lines.push(chalk9.gray(` \u9879\u76EE: ${activeSession.context.name}`));
109
112
  lines.push(chalk9.gray(` \u7C7B\u578B: ${activeSession.context.type}`));
110
113
  lines.push(chalk9.gray(` \u6846\u67B6: ${activeSession.context.framework || "\u672A\u8BC6\u522B"}`));
@@ -194,7 +197,7 @@ ${resource.analysis}`;
194
197
  lines.push("");
195
198
  lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
196
199
  lines.push("");
197
- const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
200
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
198
201
  loader.start();
199
202
  try {
200
203
  activeSession.bddScenarios = await generateBDDScenariosWithAI(
@@ -229,7 +232,7 @@ ${resource.analysis}`;
229
232
  lines.push("");
230
233
  lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
231
234
  lines.push("");
232
- const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
235
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
233
236
  loader.start();
234
237
  try {
235
238
  activeSession.specItems = await generateSpecItemsWithAI(
@@ -398,31 +401,85 @@ async function handleWorkflowInput(input, ctx) {
398
401
  activeSession.phase = "analysis";
399
402
  return executeWorkflow(ctx);
400
403
  }
401
- if (activeSession.phase === "spec") {
404
+ if (activeSession.phase === "spec" || activeSession.specFeedbackState === "waiting_confirm") {
402
405
  if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
406
+ activeSession.specFeedbackState = void 0;
403
407
  activeSession.phase = "tdd";
404
408
  return executeWorkflow(ctx);
405
409
  }
406
- if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
407
- activeSession.bddScenarios = generateBDDScenarios(
408
- activeSession.refinedRequirement,
409
- activeSession.context,
410
- activeSession.clarificationQuestions,
411
- activeSession.referenceResources
412
- );
413
- activeSession.specItems = generateSpecItems(
414
- activeSession.refinedRequirement,
415
- activeSession.context,
416
- activeSession.bddScenarios,
417
- activeSession.clarificationQuestions,
418
- activeSession.referenceResources
419
- );
410
+ if (trimmed === "n" || trimmed === "no" || trimmed === "\u4E0D\u6EE1\u610F" || trimmed === "\u91CD\u65B0") {
411
+ activeSession.specFeedbackState = "collecting_feedback";
412
+ if (!activeSession.specFeedbacks) {
413
+ activeSession.specFeedbacks = [];
414
+ }
415
+ return {
416
+ output: chalk9.yellow("\n\u{1F4DD} \u8BF7\u8F93\u5165\u60A8\u5BF9\u89C4\u683C\u4E0D\u6EE1\u610F\u7684\u5730\u65B9:") + chalk9.gray("\n - \u9057\u6F0F\u7684\u529F\u80FD\u70B9") + chalk9.gray("\n - \u4E0D\u5408\u7406\u7684\u62C6\u5206") + chalk9.gray("\n - \u9700\u8981\u8865\u5145\u7684\u7EC6\u8282") + chalk9.gray("\n - \u5176\u4ED6\u6539\u8FDB\u5EFA\u8BAE") + chalk9.cyan('\n\n\u8F93\u5165\u5B8C\u6210\u540E\uFF0C\u8F93\u5165\u7A7A\u884C\u6216 "done" \u7ED3\u675F\u8F93\u5165')
417
+ };
418
+ }
419
+ }
420
+ if (activeSession.specFeedbackState === "collecting_feedback") {
421
+ if (trimmed === "" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
422
+ if (!activeSession.specFeedbacks || activeSession.specFeedbacks.length === 0) {
423
+ return {
424
+ output: chalk9.yellow('\u26A0\uFE0F \u8BF7\u81F3\u5C11\u8F93\u5165\u4E00\u6761\u53CD\u9988\u610F\u89C1\uFF0C\u6216\u8F93\u5165 "cancel" \u53D6\u6D88')
425
+ };
426
+ }
427
+ activeSession.specFeedbackState = "feedback_received";
428
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210\u89C4\u683C");
429
+ loader.start();
430
+ try {
431
+ activeSession.specItems = await generateSpecItemsWithFeedback(
432
+ activeSession.refinedRequirement,
433
+ activeSession.context,
434
+ activeSession.bddScenarios,
435
+ activeSession.clarificationQuestions,
436
+ activeSession.referenceResources,
437
+ activeSession.specFeedbacks,
438
+ ctx
439
+ );
440
+ loader.stop(chalk9.green(" \u2713 \u89C4\u683C\u5DF2\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210"));
441
+ } catch (error) {
442
+ loader.stop(chalk9.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u65B9\u6CD5\u91CD\u65B0\u751F\u6210"));
443
+ activeSession.specItems = generateSpecItems(
444
+ activeSession.refinedRequirement,
445
+ activeSession.context,
446
+ activeSession.bddScenarios,
447
+ activeSession.clarificationQuestions,
448
+ activeSession.referenceResources
449
+ );
450
+ }
420
451
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
452
+ activeSession.specFeedbackState = "waiting_confirm";
453
+ const lines = [];
454
+ lines.push(chalk9.cyan("\n\u2501\u2501\u2501 \u66F4\u65B0\u540E\u7684\u4EFB\u52A1\u6982\u89C8 \u2501\u2501\u2501"));
455
+ for (const item of activeSession.specItems.slice(0, 8)) {
456
+ const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
457
+ lines.push(chalk9.gray(` ${icon} [${item.id}] ${item.title}`));
458
+ }
459
+ if (activeSession.specItems.length > 8) {
460
+ lines.push(chalk9.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
461
+ }
421
462
  return {
422
- output: chalk9.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9.gray(`
423
- \u8DEF\u5F84: ${specPath}`) + chalk9.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9.red("\n n - \u518D\u6B21\u91CD\u65B0\u751F\u6210")
463
+ output: lines.join("\n") + chalk9.green(`
464
+
465
+ \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u66F4\u65B0`) + chalk9.gray(`
466
+ \u8DEF\u5F84: ${specPath}`) + chalk9.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9.red("\n n - \u4ECD\u6709\u95EE\u9898\uFF0C\u7EE7\u7EED\u53CD\u9988")
424
467
  };
425
468
  }
469
+ if (trimmed === "cancel" || trimmed === "\u53D6\u6D88") {
470
+ activeSession.specFeedbackState = "waiting_confirm";
471
+ activeSession.specFeedbacks = [];
472
+ return {
473
+ output: chalk9.gray("\u5DF2\u53D6\u6D88\u53CD\u9988\uFF0C\u8FD4\u56DE\u89C4\u683C\u786E\u8BA4") + chalk9.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9.red("\n n - \u4E0D\u6EE1\u610F\uFF0C\u91CD\u65B0\u751F\u6210")
474
+ };
475
+ }
476
+ if (!activeSession.specFeedbacks) {
477
+ activeSession.specFeedbacks = [];
478
+ }
479
+ activeSession.specFeedbacks.push(trimmed);
480
+ return {
481
+ output: chalk9.gray(`\u5DF2\u8BB0\u5F55\u53CD\u9988 #${activeSession.specFeedbacks.length}: `) + chalk9.white(trimmed.slice(0, 50)) + chalk9.gray('\n\u7EE7\u7EED\u8F93\u5165\uFF0C\u6216\u8F93\u5165 "done" \u5B8C\u6210\u53CD\u9988')
482
+ };
426
483
  }
427
484
  if (activeSession.phase === "develop") {
428
485
  if (trimmed === "continue" || trimmed === "\u7EE7\u7EED" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
@@ -581,7 +638,7 @@ async function executeDevelopment(ctx, session) {
581
638
  if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
582
639
  continue;
583
640
  }
584
- const loader = new LoadingIndicator(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
641
+ const loader = new LoadingIndicator2(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
585
642
  loader.start();
586
643
  try {
587
644
  const taskPrompt = buildTaskPrompt(session, item, i);
@@ -614,8 +671,8 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
614
671
  maxTokens: 4e3,
615
672
  // 单个任务减少 token
616
673
  agent: "frontend-dev",
617
- timeout: 12e4
618
- // 2分钟超时
674
+ timeout: 3e5
675
+ // 5分钟超时,确保复杂代码有足够时间
619
676
  });
620
677
  const codeBlocks = parseCodeBlocks(response.content);
621
678
  if (codeBlocks.length > 0) {
@@ -703,6 +760,8 @@ async function executeReview(ctx, session) {
703
760
  const workingDir = ctx.options.workingDirectory;
704
761
  const issues = [];
705
762
  const suggestions = [];
763
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u5BA1\u6838\u4EE3\u7801");
764
+ loader.start();
706
765
  try {
707
766
  const codeContents = [];
708
767
  for (const file of session.implFiles) {
@@ -765,7 +824,9 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
765
824
  const response = await ctx.modelService.sendMessage(messages, {
766
825
  temperature: 0.2,
767
826
  maxTokens: 2e3,
768
- agent: "code-reviewer"
827
+ agent: "code-reviewer",
828
+ timeout: 18e4
829
+ // 3分钟超时
769
830
  });
770
831
  const result = response.content;
771
832
  const passed = result.includes("\u5BA1\u6838\u901A\u8FC7") || result.includes("\u901A\u8FC7") || !result.includes("\u4E0D\u901A\u8FC7");
@@ -787,8 +848,10 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
787
848
  const lines = result.split("\n").filter((l) => l.includes("\u5EFA\u8BAE") || l.includes("\u6539\u8FDB") || l.includes("\u4F18\u5316"));
788
849
  suggestions.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
789
850
  }
851
+ loader.stop(passed ? chalk9.green(" \u2713 \u5BA1\u6838\u901A\u8FC7") : chalk9.yellow(" \u26A0 \u53D1\u73B0\u95EE\u9898"));
790
852
  return { passed, issues, suggestions };
791
853
  } catch (error) {
854
+ loader.stop(chalk9.red(" \u2717 \u5BA1\u6838\u51FA\u9519"));
792
855
  suggestions.push(`\u5BA1\u6838\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
793
856
  return { passed: true, issues, suggestions };
794
857
  }
@@ -994,7 +1057,8 @@ ${r.analysis}`).join("\n\n") : "\u65E0"}
994
1057
  ], {
995
1058
  temperature: 0.3,
996
1059
  maxTokens: 4e3,
997
- timeout: 12e4
1060
+ timeout: 3e5
1061
+ // 5分钟超时
998
1062
  });
999
1063
  try {
1000
1064
  const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
@@ -1202,7 +1266,7 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1202
1266
  - \u96C6\u6210\u6D4B\u8BD5
1203
1267
 
1204
1268
  \u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
1205
- const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
1269
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
1206
1270
  loader.start();
1207
1271
  try {
1208
1272
  const response = await ctx.modelService.sendMessage([
@@ -1210,8 +1274,8 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1210
1274
  ], {
1211
1275
  temperature: 0.3,
1212
1276
  maxTokens: 4e3,
1213
- timeout: 18e4
1214
- // 增加到3分钟
1277
+ timeout: 3e5
1278
+ // 5分钟超时
1215
1279
  });
1216
1280
  const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
1217
1281
  if (jsonMatch) {
@@ -1254,6 +1318,90 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1254
1318
  return generateSpecItems(requirement, context, bddScenarios, questions, references);
1255
1319
  }
1256
1320
  }
1321
+ async function generateSpecItemsWithFeedback(requirement, context, bddScenarios, questions, references, feedbacks, ctx) {
1322
+ const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u9879\u76EE\u7ECF\u7406\u548C\u6280\u672F\u67B6\u6784\u5E08\u3002\u8BF7\u6839\u636E\u7528\u6237\u53CD\u9988\uFF0C\u91CD\u65B0\u62C6\u5206\u9700\u6C42\u4EFB\u52A1\u3002
1323
+
1324
+ ## \u9700\u6C42\u63CF\u8FF0
1325
+ ${requirement}
1326
+
1327
+ ## \u9879\u76EE\u4E0A\u4E0B\u6587
1328
+ - \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
1329
+ - \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
1330
+ ${context.devStandards ? `
1331
+ ## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
1332
+ ${context.devStandards.slice(0, 2e3)}
1333
+ ` : ""}
1334
+
1335
+ ## \u4E4B\u524D\u7684 BDD \u573A\u666F
1336
+ ${bddScenarios.map((s) => `- Feature: ${s.feature}`).join("\n")}
1337
+
1338
+ ## \u7528\u6237\u53CD\u9988\uFF08\u5FC5\u987B\u89E3\u51B3\u8FD9\u4E9B\u95EE\u9898\uFF09
1339
+ ${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
1340
+
1341
+ ## \u8981\u6C42
1342
+ 1. **\u5FC5\u987B\u89E3\u51B3\u7528\u6237\u53CD\u9988\u4E2D\u7684\u6240\u6709\u95EE\u9898**
1343
+ 2. \u5982\u679C\u7528\u6237\u6307\u51FA\u9057\u6F0F\u7684\u529F\u80FD\u70B9\uFF0C\u8BF7\u8865\u5145\u76F8\u5173\u4EFB\u52A1
1344
+ 3. \u5982\u679C\u7528\u6237\u6307\u51FA\u62C6\u5206\u4E0D\u5408\u7406\uFF0C\u8BF7\u91CD\u65B0\u8C03\u6574\u7C92\u5EA6
1345
+ 4. \u5982\u679C\u7528\u6237\u9700\u8981\u66F4\u591A\u7EC6\u8282\uFF0C\u8BF7\u62C6\u5206\u5F97\u66F4\u7EC6\u81F4
1346
+ 5. \u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\u5355\u4E00\u804C\u8D23\u30012-4\u5C0F\u65F6\u53EF\u5B8C\u6210
1347
+
1348
+ ## \u8F93\u51FA\u683C\u5F0F (JSON)
1349
+ \`\`\`json
1350
+ [
1351
+ {
1352
+ "id": "T001",
1353
+ "title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
1354
+ "description": "\u8BE6\u7EC6\u63CF\u8FF0",
1355
+ "priority": "high",
1356
+ "acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
1357
+ }
1358
+ ]
1359
+ \`\`\`
1360
+
1361
+ \u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u786E\u4FDD\u89E3\u51B3\u4E86\u7528\u6237\u7684\u6240\u6709\u53CD\u9988\u3002`;
1362
+ try {
1363
+ const response = await ctx.modelService.sendMessage([
1364
+ { role: "user", content: prompt2 }
1365
+ ], {
1366
+ temperature: 0.3,
1367
+ maxTokens: 4e3,
1368
+ timeout: 3e5
1369
+ // 5分钟超时
1370
+ });
1371
+ const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
1372
+ if (jsonMatch) {
1373
+ try {
1374
+ const parsed = JSON.parse(jsonMatch[1].trim());
1375
+ return parsed.map((item, index) => ({
1376
+ id: item.id || `T${String(index + 1).padStart(3, "0")}`,
1377
+ title: item.title,
1378
+ description: item.description,
1379
+ priority: item.priority || "medium",
1380
+ files: [],
1381
+ tests: item.acceptanceCriteria || []
1382
+ }));
1383
+ } catch {
1384
+ }
1385
+ }
1386
+ try {
1387
+ const parsed = JSON.parse(response.content);
1388
+ if (Array.isArray(parsed)) {
1389
+ return parsed.map((item, index) => ({
1390
+ id: item.id || `T${String(index + 1).padStart(3, "0")}`,
1391
+ title: item.title,
1392
+ description: item.description,
1393
+ priority: item.priority || "medium",
1394
+ files: [],
1395
+ tests: item.acceptanceCriteria || []
1396
+ }));
1397
+ }
1398
+ } catch {
1399
+ }
1400
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1401
+ } catch {
1402
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1403
+ }
1404
+ }
1257
1405
  async function saveSpecFile(workingDir, session) {
1258
1406
  const specDir = path5.join(workingDir, "openspec", "changes");
1259
1407
  await fs4.mkdir(specDir, { recursive: true });
@@ -1320,6 +1468,16 @@ function formatSpecFile(session) {
1320
1468
  lines.push("");
1321
1469
  }
1322
1470
  }
1471
+ if (session.specFeedbacks && session.specFeedbacks.length > 0) {
1472
+ lines.push("## \u89C4\u683C\u8FED\u4EE3\u53CD\u9988");
1473
+ lines.push("");
1474
+ for (let i = 0; i < session.specFeedbacks.length; i++) {
1475
+ lines.push(`${i + 1}. ${session.specFeedbacks[i]}`);
1476
+ }
1477
+ lines.push("");
1478
+ lines.push("---");
1479
+ lines.push("");
1480
+ }
1323
1481
  lines.push("## \u4EFB\u52A1\u5217\u8868");
1324
1482
  lines.push("");
1325
1483
  for (const item of session.specItems) {
@@ -1340,7 +1498,7 @@ async function generateTests(workingDir, session, ctx) {
1340
1498
  for (const scenario of session.bddScenarios) {
1341
1499
  const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
1342
1500
  const testPath = path5.join(testDir, `${testName}.test.ts`);
1343
- const loader = new LoadingIndicator(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
1501
+ const loader = new LoadingIndicator2(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
1344
1502
  loader.start();
1345
1503
  try {
1346
1504
  const content = await generateTestFileWithAI(scenario, session, ctx);
@@ -1395,7 +1553,9 @@ ${scenario.scenarios.map((s) => `
1395
1553
  { role: "user", content: prompt2 }
1396
1554
  ], {
1397
1555
  temperature: 0.3,
1398
- maxTokens: 4e3
1556
+ maxTokens: 4e3,
1557
+ timeout: 18e4
1558
+ // 3分钟超时
1399
1559
  });
1400
1560
  const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
1401
1561
  if (codeMatch) {
@@ -1494,7 +1654,10 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
1494
1654
  const type = detectResourceType(url);
1495
1655
  let content = "";
1496
1656
  let analysis = "";
1657
+ const loader = new LoadingIndicator2(`\u83B7\u53D6 ${url.slice(0, 40)}...`);
1658
+ loader.start();
1497
1659
  try {
1660
+ loader.update("\u6B63\u5728\u83B7\u53D6\u7F51\u9875\u5185\u5BB9");
1498
1661
  const response = await fetch(url, {
1499
1662
  headers: {
1500
1663
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
@@ -1505,11 +1668,14 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
1505
1668
  }
1506
1669
  content = await response.text();
1507
1670
  if (ctx.modelService.getCurrentModel()) {
1671
+ loader.update("\u6B63\u5728\u5206\u6790\u5185\u5BB9");
1508
1672
  analysis = await analyzeReferenceContent(url, content, type, ctx, projectContext);
1509
1673
  } else {
1510
1674
  analysis = extractBasicInfo(content, type);
1511
1675
  }
1676
+ loader.stop();
1512
1677
  } catch (error) {
1678
+ loader.stop();
1513
1679
  throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u53C2\u8003\u8D44\u6E90: ${error.message}`);
1514
1680
  }
1515
1681
  return { url, type, content: content.slice(0, 1e4), analysis };
@@ -1578,14 +1744,16 @@ ${content.slice(0, 8e3)}
1578
1744
  \u6CE8\u610F\uFF1A\u8BF7\u4EE5 Markdown \u683C\u5F0F\u8F93\u51FA\uFF0C\u91CD\u70B9\u7A81\u51FA**\u4E1A\u52A1\u903B\u8F91**\u548C**\u529F\u80FD\u7279\u6027**\u3002
1579
1745
  \u6280\u672F\u5B9E\u73B0\u65B9\u6848\u7531\u9879\u76EE\u89C4\u8303\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u6D89\u53CA\u3002
1580
1746
  `;
1581
- const loader = new LoadingIndicator("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
1747
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
1582
1748
  loader.start();
1583
1749
  try {
1584
1750
  const response = await ctx.modelService.sendMessage([
1585
1751
  { role: "user", content: prompt2 }
1586
1752
  ], {
1587
1753
  temperature: 0.3,
1588
- maxTokens: 4e3
1754
+ maxTokens: 4e3,
1755
+ timeout: 18e4
1756
+ // 3分钟超时
1589
1757
  });
1590
1758
  loader.stop(chalk9.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
1591
1759
  return response.content;
@@ -1632,11 +1800,11 @@ function getActiveSession() {
1632
1800
  function clearActiveSession() {
1633
1801
  activeSession = null;
1634
1802
  }
1635
- var LoadingIndicator, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
1803
+ var LoadingIndicator2, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
1636
1804
  var init_new = __esm({
1637
1805
  "src/commands/new.ts"() {
1638
1806
  init_esm_shims();
1639
- LoadingIndicator = class {
1807
+ LoadingIndicator2 = class {
1640
1808
  frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1641
1809
  frameIndex = 0;
1642
1810
  interval = null;
@@ -2001,9 +2169,10 @@ var BaseAdapter = class {
2001
2169
  }
2002
2170
  /**
2003
2171
  * 获取超时时间
2172
+ * 默认 5 分钟,对于复杂的代码生成任务足够
2004
2173
  */
2005
2174
  getTimeout() {
2006
- return this.config?.timeout || 6e4;
2175
+ return this.config?.timeout || 3e5;
2007
2176
  }
2008
2177
  /**
2009
2178
  * 获取重试次数
@@ -8193,6 +8362,36 @@ ${chalk9.yellow("\u793A\u4F8B:")}
8193
8362
 
8194
8363
  // src/commands/model.ts
8195
8364
  init_esm_shims();
8365
+ var LoadingIndicator = class {
8366
+ frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8367
+ frameIndex = 0;
8368
+ interval = null;
8369
+ message;
8370
+ constructor(message) {
8371
+ this.message = message;
8372
+ }
8373
+ start() {
8374
+ process.stdout.write("\x1B[?25l");
8375
+ this.interval = setInterval(() => {
8376
+ const frame = this.frames[this.frameIndex];
8377
+ process.stdout.write(`\r${chalk9.cyan(frame)} ${this.message}...`);
8378
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
8379
+ }, 80);
8380
+ }
8381
+ stop(finalMessage) {
8382
+ if (this.interval) {
8383
+ clearInterval(this.interval);
8384
+ this.interval = null;
8385
+ }
8386
+ process.stdout.write("\x1B[?25h");
8387
+ if (finalMessage) {
8388
+ process.stdout.write(`\r${finalMessage}
8389
+ `);
8390
+ } else {
8391
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
8392
+ }
8393
+ }
8394
+ };
8196
8395
  async function handleModel(args, ctx) {
8197
8396
  const subCommand = args[0];
8198
8397
  const configManager = ctx.configManager;
@@ -8292,9 +8491,12 @@ async function verifyCurrentModel(configManager, modelService) {
8292
8491
  output: chalk9.red(`\u2717 \u672A\u77E5\u6A21\u578B: ${currentModel}`)
8293
8492
  };
8294
8493
  }
8494
+ const loader = new LoadingIndicator(`\u9A8C\u8BC1 ${modelInfo.name} API Key`);
8495
+ loader.start();
8295
8496
  try {
8296
8497
  const adapter = createAdapter(modelInfo.provider);
8297
8498
  const isValid = await adapter.validateApiKey(apiKey);
8499
+ loader.stop();
8298
8500
  if (isValid) {
8299
8501
  return {
8300
8502
  output: chalk9.green(`\u2713 API Key \u9A8C\u8BC1\u6210\u529F
@@ -8306,6 +8508,7 @@ async function verifyCurrentModel(configManager, modelService) {
8306
8508
  };
8307
8509
  }
8308
8510
  } catch (error) {
8511
+ loader.stop();
8309
8512
  return {
8310
8513
  output: chalk9.red(`\u2717 \u9A8C\u8BC1\u5931\u8D25: ${error.message}`)
8311
8514
  };
@@ -9517,6 +9720,36 @@ async function executeShell(command, ctx) {
9517
9720
  // src/commands/natural.ts
9518
9721
  init_esm_shims();
9519
9722
  init_new();
9723
+ var LoadingIndicator3 = class {
9724
+ frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9725
+ frameIndex = 0;
9726
+ interval = null;
9727
+ message;
9728
+ constructor(message) {
9729
+ this.message = message;
9730
+ }
9731
+ start() {
9732
+ process.stdout.write("\x1B[?25l");
9733
+ this.interval = setInterval(() => {
9734
+ const frame = this.frames[this.frameIndex];
9735
+ process.stdout.write(`\r${chalk9.cyan(frame)} ${this.message}...`);
9736
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
9737
+ }, 80);
9738
+ }
9739
+ stop(finalMessage) {
9740
+ if (this.interval) {
9741
+ clearInterval(this.interval);
9742
+ this.interval = null;
9743
+ }
9744
+ process.stdout.write("\x1B[?25h");
9745
+ if (finalMessage) {
9746
+ process.stdout.write(`\r${finalMessage}
9747
+ `);
9748
+ } else {
9749
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
9750
+ }
9751
+ }
9752
+ };
9520
9753
  async function handleNaturalLanguage(input, ctx) {
9521
9754
  const trimmedInput = input.trim();
9522
9755
  const session = getActiveSession();
@@ -9536,6 +9769,8 @@ async function handleNaturalLanguage(input, ctx) {
9536
9769
  contextUsed: 0
9537
9770
  };
9538
9771
  }
9772
+ const loader = new LoadingIndicator3("AI \u601D\u8003\u4E2D");
9773
+ loader.start();
9539
9774
  try {
9540
9775
  const response = await ctx.modelService.sendMessage(
9541
9776
  [
@@ -9553,6 +9788,7 @@ async function handleNaturalLanguage(input, ctx) {
9553
9788
  maxTokens: 2e3
9554
9789
  }
9555
9790
  );
9791
+ loader.stop();
9556
9792
  ctx.contextManager.addMessage({
9557
9793
  role: "user",
9558
9794
  content: trimmedInput
@@ -9566,6 +9802,7 @@ async function handleNaturalLanguage(input, ctx) {
9566
9802
  contextUsed: response.usage?.totalTokens || 0
9567
9803
  };
9568
9804
  } catch (error) {
9805
+ loader.stop();
9569
9806
  const errorMessage = error.message;
9570
9807
  if (errorMessage.includes("\u672A\u914D\u7F6E") || errorMessage.includes("\u672A\u521D\u59CB\u5316")) {
9571
9808
  return {