@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.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
|
|
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
|
|
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.
|
|
433
|
-
|
|
434
|
-
activeSession.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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:
|
|
448
|
-
|
|
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
|
|
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:
|
|
643
|
-
//
|
|
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:
|
|
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
|
|
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:
|
|
1239
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ||
|
|
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 {
|