@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/cli/index.js
CHANGED
|
@@ -244,9 +244,10 @@ var init_base = __esm({
|
|
|
244
244
|
}
|
|
245
245
|
/**
|
|
246
246
|
* 获取超时时间
|
|
247
|
+
* 默认 5 分钟,对于复杂的代码生成任务足够
|
|
247
248
|
*/
|
|
248
249
|
getTimeout() {
|
|
249
|
-
return this.config?.timeout ||
|
|
250
|
+
return this.config?.timeout || 3e5;
|
|
250
251
|
}
|
|
251
252
|
/**
|
|
252
253
|
* 获取重试次数
|
|
@@ -1057,9 +1058,12 @@ async function verifyCurrentModel(configManager, modelService) {
|
|
|
1057
1058
|
output: chalk9__default.default.red(`\u2717 \u672A\u77E5\u6A21\u578B: ${currentModel}`)
|
|
1058
1059
|
};
|
|
1059
1060
|
}
|
|
1061
|
+
const loader = new LoadingIndicator(`\u9A8C\u8BC1 ${modelInfo.name} API Key`);
|
|
1062
|
+
loader.start();
|
|
1060
1063
|
try {
|
|
1061
1064
|
const adapter = createAdapter(modelInfo.provider);
|
|
1062
1065
|
const isValid = await adapter.validateApiKey(apiKey);
|
|
1066
|
+
loader.stop();
|
|
1063
1067
|
if (isValid) {
|
|
1064
1068
|
return {
|
|
1065
1069
|
output: chalk9__default.default.green(`\u2713 API Key \u9A8C\u8BC1\u6210\u529F
|
|
@@ -1071,6 +1075,7 @@ async function verifyCurrentModel(configManager, modelService) {
|
|
|
1071
1075
|
};
|
|
1072
1076
|
}
|
|
1073
1077
|
} catch (error) {
|
|
1078
|
+
loader.stop();
|
|
1074
1079
|
return {
|
|
1075
1080
|
output: chalk9__default.default.red(`\u2717 \u9A8C\u8BC1\u5931\u8D25: ${error.message}`)
|
|
1076
1081
|
};
|
|
@@ -1192,12 +1197,42 @@ function createSpinner(message) {
|
|
|
1192
1197
|
stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
|
|
1193
1198
|
};
|
|
1194
1199
|
}
|
|
1195
|
-
var model_default;
|
|
1200
|
+
var LoadingIndicator, model_default;
|
|
1196
1201
|
var init_model2 = __esm({
|
|
1197
1202
|
"src/commands/model.ts"() {
|
|
1198
1203
|
init_cjs_shims();
|
|
1199
1204
|
init_adapters();
|
|
1200
1205
|
init_model();
|
|
1206
|
+
LoadingIndicator = class {
|
|
1207
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1208
|
+
frameIndex = 0;
|
|
1209
|
+
interval = null;
|
|
1210
|
+
message;
|
|
1211
|
+
constructor(message) {
|
|
1212
|
+
this.message = message;
|
|
1213
|
+
}
|
|
1214
|
+
start() {
|
|
1215
|
+
process.stdout.write("\x1B[?25l");
|
|
1216
|
+
this.interval = setInterval(() => {
|
|
1217
|
+
const frame = this.frames[this.frameIndex];
|
|
1218
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
1219
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
1220
|
+
}, 80);
|
|
1221
|
+
}
|
|
1222
|
+
stop(finalMessage) {
|
|
1223
|
+
if (this.interval) {
|
|
1224
|
+
clearInterval(this.interval);
|
|
1225
|
+
this.interval = null;
|
|
1226
|
+
}
|
|
1227
|
+
process.stdout.write("\x1B[?25h");
|
|
1228
|
+
if (finalMessage) {
|
|
1229
|
+
process.stdout.write(`\r${finalMessage}
|
|
1230
|
+
`);
|
|
1231
|
+
} else {
|
|
1232
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1201
1236
|
model_default = selectModel;
|
|
1202
1237
|
}
|
|
1203
1238
|
});
|
|
@@ -1459,7 +1494,10 @@ async function executeWorkflow(ctx) {
|
|
|
1459
1494
|
if (activeSession.phase === "context") {
|
|
1460
1495
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/9: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
|
|
1461
1496
|
lines.push("");
|
|
1497
|
+
const loader = new LoadingIndicator2("\u8BFB\u53D6\u9879\u76EE\u914D\u7F6E");
|
|
1498
|
+
loader.start();
|
|
1462
1499
|
activeSession.context = await readProjectContext(ctx.options.workingDirectory);
|
|
1500
|
+
loader.stop();
|
|
1463
1501
|
lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${activeSession.context.name}`));
|
|
1464
1502
|
lines.push(chalk9__default.default.gray(` \u7C7B\u578B: ${activeSession.context.type}`));
|
|
1465
1503
|
lines.push(chalk9__default.default.gray(` \u6846\u67B6: ${activeSession.context.framework || "\u672A\u8BC6\u522B"}`));
|
|
@@ -1549,7 +1587,7 @@ ${resource.analysis}`;
|
|
|
1549
1587
|
lines.push("");
|
|
1550
1588
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
1551
1589
|
lines.push("");
|
|
1552
|
-
const loader = new
|
|
1590
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
|
|
1553
1591
|
loader.start();
|
|
1554
1592
|
try {
|
|
1555
1593
|
activeSession.bddScenarios = await generateBDDScenariosWithAI(
|
|
@@ -1584,7 +1622,7 @@ ${resource.analysis}`;
|
|
|
1584
1622
|
lines.push("");
|
|
1585
1623
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
1586
1624
|
lines.push("");
|
|
1587
|
-
const loader = new
|
|
1625
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
1588
1626
|
loader.start();
|
|
1589
1627
|
try {
|
|
1590
1628
|
activeSession.specItems = await generateSpecItemsWithAI(
|
|
@@ -1753,31 +1791,85 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
1753
1791
|
activeSession.phase = "analysis";
|
|
1754
1792
|
return executeWorkflow(ctx);
|
|
1755
1793
|
}
|
|
1756
|
-
if (activeSession.phase === "spec") {
|
|
1794
|
+
if (activeSession.phase === "spec" || activeSession.specFeedbackState === "waiting_confirm") {
|
|
1757
1795
|
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
|
|
1796
|
+
activeSession.specFeedbackState = void 0;
|
|
1758
1797
|
activeSession.phase = "tdd";
|
|
1759
1798
|
return executeWorkflow(ctx);
|
|
1760
1799
|
}
|
|
1761
|
-
if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
|
|
1762
|
-
activeSession.
|
|
1763
|
-
|
|
1764
|
-
activeSession.
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1800
|
+
if (trimmed === "n" || trimmed === "no" || trimmed === "\u4E0D\u6EE1\u610F" || trimmed === "\u91CD\u65B0") {
|
|
1801
|
+
activeSession.specFeedbackState = "collecting_feedback";
|
|
1802
|
+
if (!activeSession.specFeedbacks) {
|
|
1803
|
+
activeSession.specFeedbacks = [];
|
|
1804
|
+
}
|
|
1805
|
+
return {
|
|
1806
|
+
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')
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
if (activeSession.specFeedbackState === "collecting_feedback") {
|
|
1811
|
+
if (trimmed === "" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
|
|
1812
|
+
if (!activeSession.specFeedbacks || activeSession.specFeedbacks.length === 0) {
|
|
1813
|
+
return {
|
|
1814
|
+
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')
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
activeSession.specFeedbackState = "feedback_received";
|
|
1818
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210\u89C4\u683C");
|
|
1819
|
+
loader.start();
|
|
1820
|
+
try {
|
|
1821
|
+
activeSession.specItems = await generateSpecItemsWithFeedback(
|
|
1822
|
+
activeSession.refinedRequirement,
|
|
1823
|
+
activeSession.context,
|
|
1824
|
+
activeSession.bddScenarios,
|
|
1825
|
+
activeSession.clarificationQuestions,
|
|
1826
|
+
activeSession.referenceResources,
|
|
1827
|
+
activeSession.specFeedbacks,
|
|
1828
|
+
ctx
|
|
1829
|
+
);
|
|
1830
|
+
loader.stop(chalk9__default.default.green(" \u2713 \u89C4\u683C\u5DF2\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210"));
|
|
1831
|
+
} catch (error) {
|
|
1832
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u65B9\u6CD5\u91CD\u65B0\u751F\u6210"));
|
|
1833
|
+
activeSession.specItems = generateSpecItems(
|
|
1834
|
+
activeSession.refinedRequirement,
|
|
1835
|
+
activeSession.context,
|
|
1836
|
+
activeSession.bddScenarios,
|
|
1837
|
+
activeSession.clarificationQuestions,
|
|
1838
|
+
activeSession.referenceResources
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1775
1841
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
1842
|
+
activeSession.specFeedbackState = "waiting_confirm";
|
|
1843
|
+
const lines = [];
|
|
1844
|
+
lines.push(chalk9__default.default.cyan("\n\u2501\u2501\u2501 \u66F4\u65B0\u540E\u7684\u4EFB\u52A1\u6982\u89C8 \u2501\u2501\u2501"));
|
|
1845
|
+
for (const item of activeSession.specItems.slice(0, 8)) {
|
|
1846
|
+
const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
1847
|
+
lines.push(chalk9__default.default.gray(` ${icon} [${item.id}] ${item.title}`));
|
|
1848
|
+
}
|
|
1849
|
+
if (activeSession.specItems.length > 8) {
|
|
1850
|
+
lines.push(chalk9__default.default.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
|
|
1851
|
+
}
|
|
1776
1852
|
return {
|
|
1777
|
-
output:
|
|
1778
|
-
|
|
1853
|
+
output: lines.join("\n") + chalk9__default.default.green(`
|
|
1854
|
+
|
|
1855
|
+
\u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u66F4\u65B0`) + chalk9__default.default.gray(`
|
|
1856
|
+
\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")
|
|
1779
1857
|
};
|
|
1780
1858
|
}
|
|
1859
|
+
if (trimmed === "cancel" || trimmed === "\u53D6\u6D88") {
|
|
1860
|
+
activeSession.specFeedbackState = "waiting_confirm";
|
|
1861
|
+
activeSession.specFeedbacks = [];
|
|
1862
|
+
return {
|
|
1863
|
+
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")
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
if (!activeSession.specFeedbacks) {
|
|
1867
|
+
activeSession.specFeedbacks = [];
|
|
1868
|
+
}
|
|
1869
|
+
activeSession.specFeedbacks.push(trimmed);
|
|
1870
|
+
return {
|
|
1871
|
+
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')
|
|
1872
|
+
};
|
|
1781
1873
|
}
|
|
1782
1874
|
if (activeSession.phase === "develop") {
|
|
1783
1875
|
if (trimmed === "continue" || trimmed === "\u7EE7\u7EED" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
|
|
@@ -1936,7 +2028,7 @@ async function executeDevelopment(ctx, session) {
|
|
|
1936
2028
|
if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
|
|
1937
2029
|
continue;
|
|
1938
2030
|
}
|
|
1939
|
-
const loader = new
|
|
2031
|
+
const loader = new LoadingIndicator2(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
|
|
1940
2032
|
loader.start();
|
|
1941
2033
|
try {
|
|
1942
2034
|
const taskPrompt = buildTaskPrompt(session, item, i);
|
|
@@ -1969,8 +2061,8 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
1969
2061
|
maxTokens: 4e3,
|
|
1970
2062
|
// 单个任务减少 token
|
|
1971
2063
|
agent: "frontend-dev",
|
|
1972
|
-
timeout:
|
|
1973
|
-
//
|
|
2064
|
+
timeout: 3e5
|
|
2065
|
+
// 5分钟超时,确保复杂代码有足够时间
|
|
1974
2066
|
});
|
|
1975
2067
|
const codeBlocks = parseCodeBlocks(response.content);
|
|
1976
2068
|
if (codeBlocks.length > 0) {
|
|
@@ -2058,6 +2150,8 @@ async function executeReview(ctx, session) {
|
|
|
2058
2150
|
const workingDir = ctx.options.workingDirectory;
|
|
2059
2151
|
const issues = [];
|
|
2060
2152
|
const suggestions = [];
|
|
2153
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u5BA1\u6838\u4EE3\u7801");
|
|
2154
|
+
loader.start();
|
|
2061
2155
|
try {
|
|
2062
2156
|
const codeContents = [];
|
|
2063
2157
|
for (const file of session.implFiles) {
|
|
@@ -2120,7 +2214,9 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
|
|
|
2120
2214
|
const response = await ctx.modelService.sendMessage(messages, {
|
|
2121
2215
|
temperature: 0.2,
|
|
2122
2216
|
maxTokens: 2e3,
|
|
2123
|
-
agent: "code-reviewer"
|
|
2217
|
+
agent: "code-reviewer",
|
|
2218
|
+
timeout: 18e4
|
|
2219
|
+
// 3分钟超时
|
|
2124
2220
|
});
|
|
2125
2221
|
const result = response.content;
|
|
2126
2222
|
const passed = result.includes("\u5BA1\u6838\u901A\u8FC7") || result.includes("\u901A\u8FC7") || !result.includes("\u4E0D\u901A\u8FC7");
|
|
@@ -2142,8 +2238,10 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
|
|
|
2142
2238
|
const lines = result.split("\n").filter((l) => l.includes("\u5EFA\u8BAE") || l.includes("\u6539\u8FDB") || l.includes("\u4F18\u5316"));
|
|
2143
2239
|
suggestions.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
|
|
2144
2240
|
}
|
|
2241
|
+
loader.stop(passed ? chalk9__default.default.green(" \u2713 \u5BA1\u6838\u901A\u8FC7") : chalk9__default.default.yellow(" \u26A0 \u53D1\u73B0\u95EE\u9898"));
|
|
2145
2242
|
return { passed, issues, suggestions };
|
|
2146
2243
|
} catch (error) {
|
|
2244
|
+
loader.stop(chalk9__default.default.red(" \u2717 \u5BA1\u6838\u51FA\u9519"));
|
|
2147
2245
|
suggestions.push(`\u5BA1\u6838\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
|
|
2148
2246
|
return { passed: true, issues, suggestions };
|
|
2149
2247
|
}
|
|
@@ -2349,7 +2447,8 @@ ${r.analysis}`).join("\n\n") : "\u65E0"}
|
|
|
2349
2447
|
], {
|
|
2350
2448
|
temperature: 0.3,
|
|
2351
2449
|
maxTokens: 4e3,
|
|
2352
|
-
timeout:
|
|
2450
|
+
timeout: 3e5
|
|
2451
|
+
// 5分钟超时
|
|
2353
2452
|
});
|
|
2354
2453
|
try {
|
|
2355
2454
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
@@ -2557,7 +2656,7 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
2557
2656
|
- \u96C6\u6210\u6D4B\u8BD5
|
|
2558
2657
|
|
|
2559
2658
|
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
|
|
2560
|
-
const loader = new
|
|
2659
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
2561
2660
|
loader.start();
|
|
2562
2661
|
try {
|
|
2563
2662
|
const response = await ctx.modelService.sendMessage([
|
|
@@ -2565,8 +2664,8 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
2565
2664
|
], {
|
|
2566
2665
|
temperature: 0.3,
|
|
2567
2666
|
maxTokens: 4e3,
|
|
2568
|
-
timeout:
|
|
2569
|
-
//
|
|
2667
|
+
timeout: 3e5
|
|
2668
|
+
// 5分钟超时
|
|
2570
2669
|
});
|
|
2571
2670
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
2572
2671
|
if (jsonMatch) {
|
|
@@ -2609,6 +2708,90 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
2609
2708
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2610
2709
|
}
|
|
2611
2710
|
}
|
|
2711
|
+
async function generateSpecItemsWithFeedback(requirement, context, bddScenarios, questions, references, feedbacks, ctx) {
|
|
2712
|
+
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
|
|
2713
|
+
|
|
2714
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
2715
|
+
${requirement}
|
|
2716
|
+
|
|
2717
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
2718
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
|
|
2719
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
2720
|
+
${context.devStandards ? `
|
|
2721
|
+
## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
|
|
2722
|
+
${context.devStandards.slice(0, 2e3)}
|
|
2723
|
+
` : ""}
|
|
2724
|
+
|
|
2725
|
+
## \u4E4B\u524D\u7684 BDD \u573A\u666F
|
|
2726
|
+
${bddScenarios.map((s) => `- Feature: ${s.feature}`).join("\n")}
|
|
2727
|
+
|
|
2728
|
+
## \u7528\u6237\u53CD\u9988\uFF08\u5FC5\u987B\u89E3\u51B3\u8FD9\u4E9B\u95EE\u9898\uFF09
|
|
2729
|
+
${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
|
|
2730
|
+
|
|
2731
|
+
## \u8981\u6C42
|
|
2732
|
+
1. **\u5FC5\u987B\u89E3\u51B3\u7528\u6237\u53CD\u9988\u4E2D\u7684\u6240\u6709\u95EE\u9898**
|
|
2733
|
+
2. \u5982\u679C\u7528\u6237\u6307\u51FA\u9057\u6F0F\u7684\u529F\u80FD\u70B9\uFF0C\u8BF7\u8865\u5145\u76F8\u5173\u4EFB\u52A1
|
|
2734
|
+
3. \u5982\u679C\u7528\u6237\u6307\u51FA\u62C6\u5206\u4E0D\u5408\u7406\uFF0C\u8BF7\u91CD\u65B0\u8C03\u6574\u7C92\u5EA6
|
|
2735
|
+
4. \u5982\u679C\u7528\u6237\u9700\u8981\u66F4\u591A\u7EC6\u8282\uFF0C\u8BF7\u62C6\u5206\u5F97\u66F4\u7EC6\u81F4
|
|
2736
|
+
5. \u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\u5355\u4E00\u804C\u8D23\u30012-4\u5C0F\u65F6\u53EF\u5B8C\u6210
|
|
2737
|
+
|
|
2738
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
2739
|
+
\`\`\`json
|
|
2740
|
+
[
|
|
2741
|
+
{
|
|
2742
|
+
"id": "T001",
|
|
2743
|
+
"title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
|
|
2744
|
+
"description": "\u8BE6\u7EC6\u63CF\u8FF0",
|
|
2745
|
+
"priority": "high",
|
|
2746
|
+
"acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
|
|
2747
|
+
}
|
|
2748
|
+
]
|
|
2749
|
+
\`\`\`
|
|
2750
|
+
|
|
2751
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u786E\u4FDD\u89E3\u51B3\u4E86\u7528\u6237\u7684\u6240\u6709\u53CD\u9988\u3002`;
|
|
2752
|
+
try {
|
|
2753
|
+
const response = await ctx.modelService.sendMessage([
|
|
2754
|
+
{ role: "user", content: prompt2 }
|
|
2755
|
+
], {
|
|
2756
|
+
temperature: 0.3,
|
|
2757
|
+
maxTokens: 4e3,
|
|
2758
|
+
timeout: 3e5
|
|
2759
|
+
// 5分钟超时
|
|
2760
|
+
});
|
|
2761
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
2762
|
+
if (jsonMatch) {
|
|
2763
|
+
try {
|
|
2764
|
+
const parsed = JSON.parse(jsonMatch[1].trim());
|
|
2765
|
+
return parsed.map((item, index) => ({
|
|
2766
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
2767
|
+
title: item.title,
|
|
2768
|
+
description: item.description,
|
|
2769
|
+
priority: item.priority || "medium",
|
|
2770
|
+
files: [],
|
|
2771
|
+
tests: item.acceptanceCriteria || []
|
|
2772
|
+
}));
|
|
2773
|
+
} catch {
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
try {
|
|
2777
|
+
const parsed = JSON.parse(response.content);
|
|
2778
|
+
if (Array.isArray(parsed)) {
|
|
2779
|
+
return parsed.map((item, index) => ({
|
|
2780
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
2781
|
+
title: item.title,
|
|
2782
|
+
description: item.description,
|
|
2783
|
+
priority: item.priority || "medium",
|
|
2784
|
+
files: [],
|
|
2785
|
+
tests: item.acceptanceCriteria || []
|
|
2786
|
+
}));
|
|
2787
|
+
}
|
|
2788
|
+
} catch {
|
|
2789
|
+
}
|
|
2790
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2791
|
+
} catch {
|
|
2792
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2612
2795
|
async function saveSpecFile(workingDir, session) {
|
|
2613
2796
|
const specDir = path5__namespace.join(workingDir, "openspec", "changes");
|
|
2614
2797
|
await fs5__namespace.mkdir(specDir, { recursive: true });
|
|
@@ -2675,6 +2858,16 @@ function formatSpecFile(session) {
|
|
|
2675
2858
|
lines.push("");
|
|
2676
2859
|
}
|
|
2677
2860
|
}
|
|
2861
|
+
if (session.specFeedbacks && session.specFeedbacks.length > 0) {
|
|
2862
|
+
lines.push("## \u89C4\u683C\u8FED\u4EE3\u53CD\u9988");
|
|
2863
|
+
lines.push("");
|
|
2864
|
+
for (let i = 0; i < session.specFeedbacks.length; i++) {
|
|
2865
|
+
lines.push(`${i + 1}. ${session.specFeedbacks[i]}`);
|
|
2866
|
+
}
|
|
2867
|
+
lines.push("");
|
|
2868
|
+
lines.push("---");
|
|
2869
|
+
lines.push("");
|
|
2870
|
+
}
|
|
2678
2871
|
lines.push("## \u4EFB\u52A1\u5217\u8868");
|
|
2679
2872
|
lines.push("");
|
|
2680
2873
|
for (const item of session.specItems) {
|
|
@@ -2695,7 +2888,7 @@ async function generateTests(workingDir, session, ctx) {
|
|
|
2695
2888
|
for (const scenario of session.bddScenarios) {
|
|
2696
2889
|
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
2697
2890
|
const testPath = path5__namespace.join(testDir, `${testName}.test.ts`);
|
|
2698
|
-
const loader = new
|
|
2891
|
+
const loader = new LoadingIndicator2(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
|
|
2699
2892
|
loader.start();
|
|
2700
2893
|
try {
|
|
2701
2894
|
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
@@ -2750,7 +2943,9 @@ ${scenario.scenarios.map((s) => `
|
|
|
2750
2943
|
{ role: "user", content: prompt2 }
|
|
2751
2944
|
], {
|
|
2752
2945
|
temperature: 0.3,
|
|
2753
|
-
maxTokens: 4e3
|
|
2946
|
+
maxTokens: 4e3,
|
|
2947
|
+
timeout: 18e4
|
|
2948
|
+
// 3分钟超时
|
|
2754
2949
|
});
|
|
2755
2950
|
const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
|
|
2756
2951
|
if (codeMatch) {
|
|
@@ -2849,7 +3044,10 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
|
|
|
2849
3044
|
const type = detectResourceType(url);
|
|
2850
3045
|
let content = "";
|
|
2851
3046
|
let analysis = "";
|
|
3047
|
+
const loader = new LoadingIndicator2(`\u83B7\u53D6 ${url.slice(0, 40)}...`);
|
|
3048
|
+
loader.start();
|
|
2852
3049
|
try {
|
|
3050
|
+
loader.update("\u6B63\u5728\u83B7\u53D6\u7F51\u9875\u5185\u5BB9");
|
|
2853
3051
|
const response = await fetch(url, {
|
|
2854
3052
|
headers: {
|
|
2855
3053
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
@@ -2860,11 +3058,14 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
|
|
|
2860
3058
|
}
|
|
2861
3059
|
content = await response.text();
|
|
2862
3060
|
if (ctx.modelService.getCurrentModel()) {
|
|
3061
|
+
loader.update("\u6B63\u5728\u5206\u6790\u5185\u5BB9");
|
|
2863
3062
|
analysis = await analyzeReferenceContent(url, content, type, ctx, projectContext);
|
|
2864
3063
|
} else {
|
|
2865
3064
|
analysis = extractBasicInfo(content, type);
|
|
2866
3065
|
}
|
|
3066
|
+
loader.stop();
|
|
2867
3067
|
} catch (error) {
|
|
3068
|
+
loader.stop();
|
|
2868
3069
|
throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u53C2\u8003\u8D44\u6E90: ${error.message}`);
|
|
2869
3070
|
}
|
|
2870
3071
|
return { url, type, content: content.slice(0, 1e4), analysis };
|
|
@@ -2933,14 +3134,16 @@ ${content.slice(0, 8e3)}
|
|
|
2933
3134
|
\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
|
|
2934
3135
|
\u6280\u672F\u5B9E\u73B0\u65B9\u6848\u7531\u9879\u76EE\u89C4\u8303\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u6D89\u53CA\u3002
|
|
2935
3136
|
`;
|
|
2936
|
-
const loader = new
|
|
3137
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
|
|
2937
3138
|
loader.start();
|
|
2938
3139
|
try {
|
|
2939
3140
|
const response = await ctx.modelService.sendMessage([
|
|
2940
3141
|
{ role: "user", content: prompt2 }
|
|
2941
3142
|
], {
|
|
2942
3143
|
temperature: 0.3,
|
|
2943
|
-
maxTokens: 4e3
|
|
3144
|
+
maxTokens: 4e3,
|
|
3145
|
+
timeout: 18e4
|
|
3146
|
+
// 3分钟超时
|
|
2944
3147
|
});
|
|
2945
3148
|
loader.stop(chalk9__default.default.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
|
|
2946
3149
|
return response.content;
|
|
@@ -2987,11 +3190,11 @@ function getActiveSession() {
|
|
|
2987
3190
|
function clearActiveSession() {
|
|
2988
3191
|
activeSession = null;
|
|
2989
3192
|
}
|
|
2990
|
-
var
|
|
3193
|
+
var LoadingIndicator2, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
2991
3194
|
var init_new = __esm({
|
|
2992
3195
|
"src/commands/new.ts"() {
|
|
2993
3196
|
init_cjs_shims();
|
|
2994
|
-
|
|
3197
|
+
LoadingIndicator2 = class {
|
|
2995
3198
|
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2996
3199
|
frameIndex = 0;
|
|
2997
3200
|
interval = null;
|
|
@@ -7161,6 +7364,36 @@ async function executeShell(command, ctx) {
|
|
|
7161
7364
|
// src/commands/natural.ts
|
|
7162
7365
|
init_cjs_shims();
|
|
7163
7366
|
init_new();
|
|
7367
|
+
var LoadingIndicator3 = class {
|
|
7368
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7369
|
+
frameIndex = 0;
|
|
7370
|
+
interval = null;
|
|
7371
|
+
message;
|
|
7372
|
+
constructor(message) {
|
|
7373
|
+
this.message = message;
|
|
7374
|
+
}
|
|
7375
|
+
start() {
|
|
7376
|
+
process.stdout.write("\x1B[?25l");
|
|
7377
|
+
this.interval = setInterval(() => {
|
|
7378
|
+
const frame = this.frames[this.frameIndex];
|
|
7379
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
7380
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
7381
|
+
}, 80);
|
|
7382
|
+
}
|
|
7383
|
+
stop(finalMessage) {
|
|
7384
|
+
if (this.interval) {
|
|
7385
|
+
clearInterval(this.interval);
|
|
7386
|
+
this.interval = null;
|
|
7387
|
+
}
|
|
7388
|
+
process.stdout.write("\x1B[?25h");
|
|
7389
|
+
if (finalMessage) {
|
|
7390
|
+
process.stdout.write(`\r${finalMessage}
|
|
7391
|
+
`);
|
|
7392
|
+
} else {
|
|
7393
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
7394
|
+
}
|
|
7395
|
+
}
|
|
7396
|
+
};
|
|
7164
7397
|
async function handleNaturalLanguage(input, ctx) {
|
|
7165
7398
|
const trimmedInput = input.trim();
|
|
7166
7399
|
const session = getActiveSession();
|
|
@@ -7180,6 +7413,8 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
7180
7413
|
contextUsed: 0
|
|
7181
7414
|
};
|
|
7182
7415
|
}
|
|
7416
|
+
const loader = new LoadingIndicator3("AI \u601D\u8003\u4E2D");
|
|
7417
|
+
loader.start();
|
|
7183
7418
|
try {
|
|
7184
7419
|
const response = await ctx.modelService.sendMessage(
|
|
7185
7420
|
[
|
|
@@ -7197,6 +7432,7 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
7197
7432
|
maxTokens: 2e3
|
|
7198
7433
|
}
|
|
7199
7434
|
);
|
|
7435
|
+
loader.stop();
|
|
7200
7436
|
ctx.contextManager.addMessage({
|
|
7201
7437
|
role: "user",
|
|
7202
7438
|
content: trimmedInput
|
|
@@ -7210,6 +7446,7 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
7210
7446
|
contextUsed: response.usage?.totalTokens || 0
|
|
7211
7447
|
};
|
|
7212
7448
|
} catch (error) {
|
|
7449
|
+
loader.stop();
|
|
7213
7450
|
const errorMessage = error.message;
|
|
7214
7451
|
if (errorMessage.includes("\u672A\u914D\u7F6E") || errorMessage.includes("\u672A\u521D\u59CB\u5316")) {
|
|
7215
7452
|
return {
|