@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/cli/index.js +272 -35
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +271 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +271 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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.
|
|
408
|
-
|
|
409
|
-
activeSession.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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:
|
|
423
|
-
|
|
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
|
|
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:
|
|
618
|
-
//
|
|
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:
|
|
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
|
|
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:
|
|
1214
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ||
|
|
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 {
|