@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.js CHANGED
@@ -129,7 +129,10 @@ async function executeWorkflow(ctx) {
129
129
  if (activeSession.phase === "context") {
130
130
  lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/9: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
131
131
  lines.push("");
132
+ const loader = new LoadingIndicator2("\u8BFB\u53D6\u9879\u76EE\u914D\u7F6E");
133
+ loader.start();
132
134
  activeSession.context = await readProjectContext(ctx.options.workingDirectory);
135
+ loader.stop();
133
136
  lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${activeSession.context.name}`));
134
137
  lines.push(chalk9__default.default.gray(` \u7C7B\u578B: ${activeSession.context.type}`));
135
138
  lines.push(chalk9__default.default.gray(` \u6846\u67B6: ${activeSession.context.framework || "\u672A\u8BC6\u522B"}`));
@@ -219,7 +222,7 @@ ${resource.analysis}`;
219
222
  lines.push("");
220
223
  lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
221
224
  lines.push("");
222
- const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
225
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
223
226
  loader.start();
224
227
  try {
225
228
  activeSession.bddScenarios = await generateBDDScenariosWithAI(
@@ -254,7 +257,7 @@ ${resource.analysis}`;
254
257
  lines.push("");
255
258
  lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
256
259
  lines.push("");
257
- const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
260
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
258
261
  loader.start();
259
262
  try {
260
263
  activeSession.specItems = await generateSpecItemsWithAI(
@@ -423,31 +426,85 @@ async function handleWorkflowInput(input, ctx) {
423
426
  activeSession.phase = "analysis";
424
427
  return executeWorkflow(ctx);
425
428
  }
426
- if (activeSession.phase === "spec") {
429
+ if (activeSession.phase === "spec" || activeSession.specFeedbackState === "waiting_confirm") {
427
430
  if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
431
+ activeSession.specFeedbackState = void 0;
428
432
  activeSession.phase = "tdd";
429
433
  return executeWorkflow(ctx);
430
434
  }
431
- if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
432
- activeSession.bddScenarios = generateBDDScenarios(
433
- activeSession.refinedRequirement,
434
- activeSession.context,
435
- activeSession.clarificationQuestions,
436
- activeSession.referenceResources
437
- );
438
- activeSession.specItems = generateSpecItems(
439
- activeSession.refinedRequirement,
440
- activeSession.context,
441
- activeSession.bddScenarios,
442
- activeSession.clarificationQuestions,
443
- activeSession.referenceResources
444
- );
435
+ if (trimmed === "n" || trimmed === "no" || trimmed === "\u4E0D\u6EE1\u610F" || trimmed === "\u91CD\u65B0") {
436
+ activeSession.specFeedbackState = "collecting_feedback";
437
+ if (!activeSession.specFeedbacks) {
438
+ activeSession.specFeedbacks = [];
439
+ }
440
+ return {
441
+ output: chalk9__default.default.yellow("\n\u{1F4DD} \u8BF7\u8F93\u5165\u60A8\u5BF9\u89C4\u683C\u4E0D\u6EE1\u610F\u7684\u5730\u65B9:") + chalk9__default.default.gray("\n - \u9057\u6F0F\u7684\u529F\u80FD\u70B9") + chalk9__default.default.gray("\n - \u4E0D\u5408\u7406\u7684\u62C6\u5206") + chalk9__default.default.gray("\n - \u9700\u8981\u8865\u5145\u7684\u7EC6\u8282") + chalk9__default.default.gray("\n - \u5176\u4ED6\u6539\u8FDB\u5EFA\u8BAE") + chalk9__default.default.cyan('\n\n\u8F93\u5165\u5B8C\u6210\u540E\uFF0C\u8F93\u5165\u7A7A\u884C\u6216 "done" \u7ED3\u675F\u8F93\u5165')
442
+ };
443
+ }
444
+ }
445
+ if (activeSession.specFeedbackState === "collecting_feedback") {
446
+ if (trimmed === "" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
447
+ if (!activeSession.specFeedbacks || activeSession.specFeedbacks.length === 0) {
448
+ return {
449
+ output: chalk9__default.default.yellow('\u26A0\uFE0F \u8BF7\u81F3\u5C11\u8F93\u5165\u4E00\u6761\u53CD\u9988\u610F\u89C1\uFF0C\u6216\u8F93\u5165 "cancel" \u53D6\u6D88')
450
+ };
451
+ }
452
+ activeSession.specFeedbackState = "feedback_received";
453
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210\u89C4\u683C");
454
+ loader.start();
455
+ try {
456
+ activeSession.specItems = await generateSpecItemsWithFeedback(
457
+ activeSession.refinedRequirement,
458
+ activeSession.context,
459
+ activeSession.bddScenarios,
460
+ activeSession.clarificationQuestions,
461
+ activeSession.referenceResources,
462
+ activeSession.specFeedbacks,
463
+ ctx
464
+ );
465
+ loader.stop(chalk9__default.default.green(" \u2713 \u89C4\u683C\u5DF2\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210"));
466
+ } catch (error) {
467
+ loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u65B9\u6CD5\u91CD\u65B0\u751F\u6210"));
468
+ activeSession.specItems = generateSpecItems(
469
+ activeSession.refinedRequirement,
470
+ activeSession.context,
471
+ activeSession.bddScenarios,
472
+ activeSession.clarificationQuestions,
473
+ activeSession.referenceResources
474
+ );
475
+ }
445
476
  const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
477
+ activeSession.specFeedbackState = "waiting_confirm";
478
+ const lines = [];
479
+ lines.push(chalk9__default.default.cyan("\n\u2501\u2501\u2501 \u66F4\u65B0\u540E\u7684\u4EFB\u52A1\u6982\u89C8 \u2501\u2501\u2501"));
480
+ for (const item of activeSession.specItems.slice(0, 8)) {
481
+ const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
482
+ lines.push(chalk9__default.default.gray(` ${icon} [${item.id}] ${item.title}`));
483
+ }
484
+ if (activeSession.specItems.length > 8) {
485
+ lines.push(chalk9__default.default.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
486
+ }
446
487
  return {
447
- output: chalk9__default.default.cyan("\u{1F504} \u89C4\u683C\u5DF2\u91CD\u65B0\u751F\u6210") + chalk9__default.default.gray(`
448
- \u8DEF\u5F84: ${specPath}`) + chalk9__default.default.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9__default.default.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9__default.default.red("\n n - \u518D\u6B21\u91CD\u65B0\u751F\u6210")
488
+ output: lines.join("\n") + chalk9__default.default.green(`
489
+
490
+ \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u66F4\u65B0`) + chalk9__default.default.gray(`
491
+ \u8DEF\u5F84: ${specPath}`) + chalk9__default.default.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9__default.default.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9__default.default.red("\n n - \u4ECD\u6709\u95EE\u9898\uFF0C\u7EE7\u7EED\u53CD\u9988")
449
492
  };
450
493
  }
494
+ if (trimmed === "cancel" || trimmed === "\u53D6\u6D88") {
495
+ activeSession.specFeedbackState = "waiting_confirm";
496
+ activeSession.specFeedbacks = [];
497
+ return {
498
+ output: chalk9__default.default.gray("\u5DF2\u53D6\u6D88\u53CD\u9988\uFF0C\u8FD4\u56DE\u89C4\u683C\u786E\u8BA4") + chalk9__default.default.yellow("\n\n\u8BF7\u786E\u8BA4:") + chalk9__default.default.green("\n y - \u786E\u8BA4\u89C4\u683C") + chalk9__default.default.red("\n n - \u4E0D\u6EE1\u610F\uFF0C\u91CD\u65B0\u751F\u6210")
499
+ };
500
+ }
501
+ if (!activeSession.specFeedbacks) {
502
+ activeSession.specFeedbacks = [];
503
+ }
504
+ activeSession.specFeedbacks.push(trimmed);
505
+ return {
506
+ output: chalk9__default.default.gray(`\u5DF2\u8BB0\u5F55\u53CD\u9988 #${activeSession.specFeedbacks.length}: `) + chalk9__default.default.white(trimmed.slice(0, 50)) + chalk9__default.default.gray('\n\u7EE7\u7EED\u8F93\u5165\uFF0C\u6216\u8F93\u5165 "done" \u5B8C\u6210\u53CD\u9988')
507
+ };
451
508
  }
452
509
  if (activeSession.phase === "develop") {
453
510
  if (trimmed === "continue" || trimmed === "\u7EE7\u7EED" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
@@ -606,7 +663,7 @@ async function executeDevelopment(ctx, session) {
606
663
  if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
607
664
  continue;
608
665
  }
609
- const loader = new LoadingIndicator(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
666
+ const loader = new LoadingIndicator2(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
610
667
  loader.start();
611
668
  try {
612
669
  const taskPrompt = buildTaskPrompt(session, item, i);
@@ -639,8 +696,8 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
639
696
  maxTokens: 4e3,
640
697
  // 单个任务减少 token
641
698
  agent: "frontend-dev",
642
- timeout: 12e4
643
- // 2分钟超时
699
+ timeout: 3e5
700
+ // 5分钟超时,确保复杂代码有足够时间
644
701
  });
645
702
  const codeBlocks = parseCodeBlocks(response.content);
646
703
  if (codeBlocks.length > 0) {
@@ -728,6 +785,8 @@ async function executeReview(ctx, session) {
728
785
  const workingDir = ctx.options.workingDirectory;
729
786
  const issues = [];
730
787
  const suggestions = [];
788
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u5BA1\u6838\u4EE3\u7801");
789
+ loader.start();
731
790
  try {
732
791
  const codeContents = [];
733
792
  for (const file of session.implFiles) {
@@ -790,7 +849,9 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
790
849
  const response = await ctx.modelService.sendMessage(messages, {
791
850
  temperature: 0.2,
792
851
  maxTokens: 2e3,
793
- agent: "code-reviewer"
852
+ agent: "code-reviewer",
853
+ timeout: 18e4
854
+ // 3分钟超时
794
855
  });
795
856
  const result = response.content;
796
857
  const passed = result.includes("\u5BA1\u6838\u901A\u8FC7") || result.includes("\u901A\u8FC7") || !result.includes("\u4E0D\u901A\u8FC7");
@@ -812,8 +873,10 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
812
873
  const lines = result.split("\n").filter((l) => l.includes("\u5EFA\u8BAE") || l.includes("\u6539\u8FDB") || l.includes("\u4F18\u5316"));
813
874
  suggestions.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
814
875
  }
876
+ loader.stop(passed ? chalk9__default.default.green(" \u2713 \u5BA1\u6838\u901A\u8FC7") : chalk9__default.default.yellow(" \u26A0 \u53D1\u73B0\u95EE\u9898"));
815
877
  return { passed, issues, suggestions };
816
878
  } catch (error) {
879
+ loader.stop(chalk9__default.default.red(" \u2717 \u5BA1\u6838\u51FA\u9519"));
817
880
  suggestions.push(`\u5BA1\u6838\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
818
881
  return { passed: true, issues, suggestions };
819
882
  }
@@ -1019,7 +1082,8 @@ ${r.analysis}`).join("\n\n") : "\u65E0"}
1019
1082
  ], {
1020
1083
  temperature: 0.3,
1021
1084
  maxTokens: 4e3,
1022
- timeout: 12e4
1085
+ timeout: 3e5
1086
+ // 5分钟超时
1023
1087
  });
1024
1088
  try {
1025
1089
  const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
@@ -1227,7 +1291,7 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1227
1291
  - \u96C6\u6210\u6D4B\u8BD5
1228
1292
 
1229
1293
  \u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
1230
- const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
1294
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
1231
1295
  loader.start();
1232
1296
  try {
1233
1297
  const response = await ctx.modelService.sendMessage([
@@ -1235,8 +1299,8 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1235
1299
  ], {
1236
1300
  temperature: 0.3,
1237
1301
  maxTokens: 4e3,
1238
- timeout: 18e4
1239
- // 增加到3分钟
1302
+ timeout: 3e5
1303
+ // 5分钟超时
1240
1304
  });
1241
1305
  const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
1242
1306
  if (jsonMatch) {
@@ -1279,6 +1343,90 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
1279
1343
  return generateSpecItems(requirement, context, bddScenarios, questions, references);
1280
1344
  }
1281
1345
  }
1346
+ async function generateSpecItemsWithFeedback(requirement, context, bddScenarios, questions, references, feedbacks, ctx) {
1347
+ 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
1348
+
1349
+ ## \u9700\u6C42\u63CF\u8FF0
1350
+ ${requirement}
1351
+
1352
+ ## \u9879\u76EE\u4E0A\u4E0B\u6587
1353
+ - \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
1354
+ - \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
1355
+ ${context.devStandards ? `
1356
+ ## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
1357
+ ${context.devStandards.slice(0, 2e3)}
1358
+ ` : ""}
1359
+
1360
+ ## \u4E4B\u524D\u7684 BDD \u573A\u666F
1361
+ ${bddScenarios.map((s) => `- Feature: ${s.feature}`).join("\n")}
1362
+
1363
+ ## \u7528\u6237\u53CD\u9988\uFF08\u5FC5\u987B\u89E3\u51B3\u8FD9\u4E9B\u95EE\u9898\uFF09
1364
+ ${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
1365
+
1366
+ ## \u8981\u6C42
1367
+ 1. **\u5FC5\u987B\u89E3\u51B3\u7528\u6237\u53CD\u9988\u4E2D\u7684\u6240\u6709\u95EE\u9898**
1368
+ 2. \u5982\u679C\u7528\u6237\u6307\u51FA\u9057\u6F0F\u7684\u529F\u80FD\u70B9\uFF0C\u8BF7\u8865\u5145\u76F8\u5173\u4EFB\u52A1
1369
+ 3. \u5982\u679C\u7528\u6237\u6307\u51FA\u62C6\u5206\u4E0D\u5408\u7406\uFF0C\u8BF7\u91CD\u65B0\u8C03\u6574\u7C92\u5EA6
1370
+ 4. \u5982\u679C\u7528\u6237\u9700\u8981\u66F4\u591A\u7EC6\u8282\uFF0C\u8BF7\u62C6\u5206\u5F97\u66F4\u7EC6\u81F4
1371
+ 5. \u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\u5355\u4E00\u804C\u8D23\u30012-4\u5C0F\u65F6\u53EF\u5B8C\u6210
1372
+
1373
+ ## \u8F93\u51FA\u683C\u5F0F (JSON)
1374
+ \`\`\`json
1375
+ [
1376
+ {
1377
+ "id": "T001",
1378
+ "title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
1379
+ "description": "\u8BE6\u7EC6\u63CF\u8FF0",
1380
+ "priority": "high",
1381
+ "acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
1382
+ }
1383
+ ]
1384
+ \`\`\`
1385
+
1386
+ \u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u786E\u4FDD\u89E3\u51B3\u4E86\u7528\u6237\u7684\u6240\u6709\u53CD\u9988\u3002`;
1387
+ try {
1388
+ const response = await ctx.modelService.sendMessage([
1389
+ { role: "user", content: prompt2 }
1390
+ ], {
1391
+ temperature: 0.3,
1392
+ maxTokens: 4e3,
1393
+ timeout: 3e5
1394
+ // 5分钟超时
1395
+ });
1396
+ const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
1397
+ if (jsonMatch) {
1398
+ try {
1399
+ const parsed = JSON.parse(jsonMatch[1].trim());
1400
+ return parsed.map((item, index) => ({
1401
+ id: item.id || `T${String(index + 1).padStart(3, "0")}`,
1402
+ title: item.title,
1403
+ description: item.description,
1404
+ priority: item.priority || "medium",
1405
+ files: [],
1406
+ tests: item.acceptanceCriteria || []
1407
+ }));
1408
+ } catch {
1409
+ }
1410
+ }
1411
+ try {
1412
+ const parsed = JSON.parse(response.content);
1413
+ if (Array.isArray(parsed)) {
1414
+ return parsed.map((item, index) => ({
1415
+ id: item.id || `T${String(index + 1).padStart(3, "0")}`,
1416
+ title: item.title,
1417
+ description: item.description,
1418
+ priority: item.priority || "medium",
1419
+ files: [],
1420
+ tests: item.acceptanceCriteria || []
1421
+ }));
1422
+ }
1423
+ } catch {
1424
+ }
1425
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1426
+ } catch {
1427
+ return generateSpecItems(requirement, context, bddScenarios, questions, references);
1428
+ }
1429
+ }
1282
1430
  async function saveSpecFile(workingDir, session) {
1283
1431
  const specDir = path4__namespace.join(workingDir, "openspec", "changes");
1284
1432
  await fs4__namespace.mkdir(specDir, { recursive: true });
@@ -1345,6 +1493,16 @@ function formatSpecFile(session) {
1345
1493
  lines.push("");
1346
1494
  }
1347
1495
  }
1496
+ if (session.specFeedbacks && session.specFeedbacks.length > 0) {
1497
+ lines.push("## \u89C4\u683C\u8FED\u4EE3\u53CD\u9988");
1498
+ lines.push("");
1499
+ for (let i = 0; i < session.specFeedbacks.length; i++) {
1500
+ lines.push(`${i + 1}. ${session.specFeedbacks[i]}`);
1501
+ }
1502
+ lines.push("");
1503
+ lines.push("---");
1504
+ lines.push("");
1505
+ }
1348
1506
  lines.push("## \u4EFB\u52A1\u5217\u8868");
1349
1507
  lines.push("");
1350
1508
  for (const item of session.specItems) {
@@ -1365,7 +1523,7 @@ async function generateTests(workingDir, session, ctx) {
1365
1523
  for (const scenario of session.bddScenarios) {
1366
1524
  const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
1367
1525
  const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
1368
- const loader = new LoadingIndicator(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
1526
+ const loader = new LoadingIndicator2(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
1369
1527
  loader.start();
1370
1528
  try {
1371
1529
  const content = await generateTestFileWithAI(scenario, session, ctx);
@@ -1420,7 +1578,9 @@ ${scenario.scenarios.map((s) => `
1420
1578
  { role: "user", content: prompt2 }
1421
1579
  ], {
1422
1580
  temperature: 0.3,
1423
- maxTokens: 4e3
1581
+ maxTokens: 4e3,
1582
+ timeout: 18e4
1583
+ // 3分钟超时
1424
1584
  });
1425
1585
  const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
1426
1586
  if (codeMatch) {
@@ -1519,7 +1679,10 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
1519
1679
  const type = detectResourceType(url);
1520
1680
  let content = "";
1521
1681
  let analysis = "";
1682
+ const loader = new LoadingIndicator2(`\u83B7\u53D6 ${url.slice(0, 40)}...`);
1683
+ loader.start();
1522
1684
  try {
1685
+ loader.update("\u6B63\u5728\u83B7\u53D6\u7F51\u9875\u5185\u5BB9");
1523
1686
  const response = await fetch(url, {
1524
1687
  headers: {
1525
1688
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
@@ -1530,11 +1693,14 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
1530
1693
  }
1531
1694
  content = await response.text();
1532
1695
  if (ctx.modelService.getCurrentModel()) {
1696
+ loader.update("\u6B63\u5728\u5206\u6790\u5185\u5BB9");
1533
1697
  analysis = await analyzeReferenceContent(url, content, type, ctx, projectContext);
1534
1698
  } else {
1535
1699
  analysis = extractBasicInfo(content, type);
1536
1700
  }
1701
+ loader.stop();
1537
1702
  } catch (error) {
1703
+ loader.stop();
1538
1704
  throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u53C2\u8003\u8D44\u6E90: ${error.message}`);
1539
1705
  }
1540
1706
  return { url, type, content: content.slice(0, 1e4), analysis };
@@ -1603,14 +1769,16 @@ ${content.slice(0, 8e3)}
1603
1769
  \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
1604
1770
  \u6280\u672F\u5B9E\u73B0\u65B9\u6848\u7531\u9879\u76EE\u89C4\u8303\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u6D89\u53CA\u3002
1605
1771
  `;
1606
- const loader = new LoadingIndicator("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
1772
+ const loader = new LoadingIndicator2("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
1607
1773
  loader.start();
1608
1774
  try {
1609
1775
  const response = await ctx.modelService.sendMessage([
1610
1776
  { role: "user", content: prompt2 }
1611
1777
  ], {
1612
1778
  temperature: 0.3,
1613
- maxTokens: 4e3
1779
+ maxTokens: 4e3,
1780
+ timeout: 18e4
1781
+ // 3分钟超时
1614
1782
  });
1615
1783
  loader.stop(chalk9__default.default.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
1616
1784
  return response.content;
@@ -1657,11 +1825,11 @@ function getActiveSession() {
1657
1825
  function clearActiveSession() {
1658
1826
  activeSession = null;
1659
1827
  }
1660
- var LoadingIndicator, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
1828
+ var LoadingIndicator2, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
1661
1829
  var init_new = __esm({
1662
1830
  "src/commands/new.ts"() {
1663
1831
  init_cjs_shims();
1664
- LoadingIndicator = class {
1832
+ LoadingIndicator2 = class {
1665
1833
  frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1666
1834
  frameIndex = 0;
1667
1835
  interval = null;
@@ -2026,9 +2194,10 @@ var BaseAdapter = class {
2026
2194
  }
2027
2195
  /**
2028
2196
  * 获取超时时间
2197
+ * 默认 5 分钟,对于复杂的代码生成任务足够
2029
2198
  */
2030
2199
  getTimeout() {
2031
- return this.config?.timeout || 6e4;
2200
+ return this.config?.timeout || 3e5;
2032
2201
  }
2033
2202
  /**
2034
2203
  * 获取重试次数
@@ -8218,6 +8387,36 @@ ${chalk9__default.default.yellow("\u793A\u4F8B:")}
8218
8387
 
8219
8388
  // src/commands/model.ts
8220
8389
  init_cjs_shims();
8390
+ var LoadingIndicator = class {
8391
+ frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8392
+ frameIndex = 0;
8393
+ interval = null;
8394
+ message;
8395
+ constructor(message) {
8396
+ this.message = message;
8397
+ }
8398
+ start() {
8399
+ process.stdout.write("\x1B[?25l");
8400
+ this.interval = setInterval(() => {
8401
+ const frame = this.frames[this.frameIndex];
8402
+ process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
8403
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
8404
+ }, 80);
8405
+ }
8406
+ stop(finalMessage) {
8407
+ if (this.interval) {
8408
+ clearInterval(this.interval);
8409
+ this.interval = null;
8410
+ }
8411
+ process.stdout.write("\x1B[?25h");
8412
+ if (finalMessage) {
8413
+ process.stdout.write(`\r${finalMessage}
8414
+ `);
8415
+ } else {
8416
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
8417
+ }
8418
+ }
8419
+ };
8221
8420
  async function handleModel(args, ctx) {
8222
8421
  const subCommand = args[0];
8223
8422
  const configManager = ctx.configManager;
@@ -8317,9 +8516,12 @@ async function verifyCurrentModel(configManager, modelService) {
8317
8516
  output: chalk9__default.default.red(`\u2717 \u672A\u77E5\u6A21\u578B: ${currentModel}`)
8318
8517
  };
8319
8518
  }
8519
+ const loader = new LoadingIndicator(`\u9A8C\u8BC1 ${modelInfo.name} API Key`);
8520
+ loader.start();
8320
8521
  try {
8321
8522
  const adapter = createAdapter(modelInfo.provider);
8322
8523
  const isValid = await adapter.validateApiKey(apiKey);
8524
+ loader.stop();
8323
8525
  if (isValid) {
8324
8526
  return {
8325
8527
  output: chalk9__default.default.green(`\u2713 API Key \u9A8C\u8BC1\u6210\u529F
@@ -8331,6 +8533,7 @@ async function verifyCurrentModel(configManager, modelService) {
8331
8533
  };
8332
8534
  }
8333
8535
  } catch (error) {
8536
+ loader.stop();
8334
8537
  return {
8335
8538
  output: chalk9__default.default.red(`\u2717 \u9A8C\u8BC1\u5931\u8D25: ${error.message}`)
8336
8539
  };
@@ -9542,6 +9745,36 @@ async function executeShell(command, ctx) {
9542
9745
  // src/commands/natural.ts
9543
9746
  init_cjs_shims();
9544
9747
  init_new();
9748
+ var LoadingIndicator3 = class {
9749
+ frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9750
+ frameIndex = 0;
9751
+ interval = null;
9752
+ message;
9753
+ constructor(message) {
9754
+ this.message = message;
9755
+ }
9756
+ start() {
9757
+ process.stdout.write("\x1B[?25l");
9758
+ this.interval = setInterval(() => {
9759
+ const frame = this.frames[this.frameIndex];
9760
+ process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
9761
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
9762
+ }, 80);
9763
+ }
9764
+ stop(finalMessage) {
9765
+ if (this.interval) {
9766
+ clearInterval(this.interval);
9767
+ this.interval = null;
9768
+ }
9769
+ process.stdout.write("\x1B[?25h");
9770
+ if (finalMessage) {
9771
+ process.stdout.write(`\r${finalMessage}
9772
+ `);
9773
+ } else {
9774
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
9775
+ }
9776
+ }
9777
+ };
9545
9778
  async function handleNaturalLanguage(input, ctx) {
9546
9779
  const trimmedInput = input.trim();
9547
9780
  const session = getActiveSession();
@@ -9561,6 +9794,8 @@ async function handleNaturalLanguage(input, ctx) {
9561
9794
  contextUsed: 0
9562
9795
  };
9563
9796
  }
9797
+ const loader = new LoadingIndicator3("AI \u601D\u8003\u4E2D");
9798
+ loader.start();
9564
9799
  try {
9565
9800
  const response = await ctx.modelService.sendMessage(
9566
9801
  [
@@ -9578,6 +9813,7 @@ async function handleNaturalLanguage(input, ctx) {
9578
9813
  maxTokens: 2e3
9579
9814
  }
9580
9815
  );
9816
+ loader.stop();
9581
9817
  ctx.contextManager.addMessage({
9582
9818
  role: "user",
9583
9819
  content: trimmedInput
@@ -9591,6 +9827,7 @@ async function handleNaturalLanguage(input, ctx) {
9591
9827
  contextUsed: response.usage?.totalTokens || 0
9592
9828
  };
9593
9829
  } catch (error) {
9830
+ loader.stop();
9594
9831
  const errorMessage = error.message;
9595
9832
  if (errorMessage.includes("\u672A\u914D\u7F6E") || errorMessage.includes("\u672A\u521D\u59CB\u5316")) {
9596
9833
  return {