@nick848/sf-cli 1.0.19 → 1.0.21
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 +219 -89
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +219 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +219 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1584,23 +1584,38 @@ ${resource.analysis}`;
|
|
|
1584
1584
|
lines.push("");
|
|
1585
1585
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
1586
1586
|
lines.push("");
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
activeSession.
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1587
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
1588
|
+
loader.start();
|
|
1589
|
+
try {
|
|
1590
|
+
activeSession.specItems = await generateSpecItemsWithAI(
|
|
1591
|
+
activeSession.refinedRequirement,
|
|
1592
|
+
activeSession.context,
|
|
1593
|
+
activeSession.bddScenarios,
|
|
1594
|
+
activeSession.clarificationQuestions,
|
|
1595
|
+
activeSession.referenceResources,
|
|
1596
|
+
ctx
|
|
1597
|
+
);
|
|
1598
|
+
loader.stop();
|
|
1599
|
+
} catch {
|
|
1600
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u89C4\u683C\u62C6\u5206"));
|
|
1601
|
+
activeSession.specItems = generateSpecItems(
|
|
1602
|
+
activeSession.refinedRequirement,
|
|
1603
|
+
activeSession.context,
|
|
1604
|
+
activeSession.bddScenarios,
|
|
1605
|
+
activeSession.clarificationQuestions,
|
|
1606
|
+
activeSession.referenceResources
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1594
1609
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
1595
1610
|
lines.push(chalk9__default.default.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
1596
1611
|
lines.push(chalk9__default.default.gray(` \u8DEF\u5F84: ${specPath}`));
|
|
1597
1612
|
lines.push("");
|
|
1598
1613
|
lines.push(chalk9__default.default.cyan(" \u4EFB\u52A1\u6982\u89C8:"));
|
|
1599
|
-
for (const item of activeSession.specItems.slice(0,
|
|
1614
|
+
for (const item of activeSession.specItems.slice(0, 8)) {
|
|
1600
1615
|
const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
1601
1616
|
lines.push(chalk9__default.default.gray(` ${icon} [${item.id}] ${item.title}`));
|
|
1602
1617
|
}
|
|
1603
|
-
if (activeSession.specItems.length >
|
|
1618
|
+
if (activeSession.specItems.length > 8) {
|
|
1604
1619
|
lines.push(chalk9__default.default.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
|
|
1605
1620
|
}
|
|
1606
1621
|
lines.push("");
|
|
@@ -1747,13 +1762,15 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
1747
1762
|
activeSession.bddScenarios = generateBDDScenarios(
|
|
1748
1763
|
activeSession.refinedRequirement,
|
|
1749
1764
|
activeSession.context,
|
|
1750
|
-
activeSession.clarificationQuestions
|
|
1765
|
+
activeSession.clarificationQuestions,
|
|
1766
|
+
activeSession.referenceResources
|
|
1751
1767
|
);
|
|
1752
1768
|
activeSession.specItems = generateSpecItems(
|
|
1753
1769
|
activeSession.refinedRequirement,
|
|
1754
1770
|
activeSession.context,
|
|
1755
1771
|
activeSession.bddScenarios,
|
|
1756
|
-
activeSession.clarificationQuestions
|
|
1772
|
+
activeSession.clarificationQuestions,
|
|
1773
|
+
activeSession.referenceResources
|
|
1757
1774
|
);
|
|
1758
1775
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
1759
1776
|
return {
|
|
@@ -1912,107 +1929,115 @@ function getCategoryLabel(category) {
|
|
|
1912
1929
|
async function executeDevelopment(ctx, session) {
|
|
1913
1930
|
const workingDir = ctx.options.workingDirectory;
|
|
1914
1931
|
const files = [];
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
const
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1932
|
+
console.log("");
|
|
1933
|
+
for (let i = 0; i < session.specItems.length; i++) {
|
|
1934
|
+
const item = session.specItems[i];
|
|
1935
|
+
const prefix = `[${i + 1}/${session.specItems.length}]`;
|
|
1936
|
+
if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
const loader = new LoadingIndicator(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
|
|
1940
|
+
loader.start();
|
|
1941
|
+
try {
|
|
1942
|
+
const taskPrompt = buildTaskPrompt(session, item, i);
|
|
1943
|
+
const messages = [
|
|
1944
|
+
{
|
|
1945
|
+
role: "system",
|
|
1946
|
+
content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u4EFB\u52A1\u63CF\u8FF0\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002
|
|
1923
1947
|
|
|
1924
1948
|
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
1925
|
-
1. \
|
|
1926
|
-
2. \
|
|
1927
|
-
3. \
|
|
1928
|
-
|
|
1929
|
-
\u4EE3\u7801\u8981\u6C42\uFF1A
|
|
1930
|
-
1. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
1931
|
-
2. \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u4EE3\u7801\u98CE\u683C\u548C\u89C4\u8303
|
|
1932
|
-
3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808
|
|
1933
|
-
4. \u4EE3\u7801\u8981\u6709\u9002\u5F53\u7684\u6CE8\u91CA
|
|
1934
|
-
5. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
1949
|
+
1. \u53EA\u751F\u6210\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u4EE3\u7801\uFF0C\u4E0D\u8981\u751F\u6210\u5176\u4ED6\u4EFB\u52A1\u7684\u4EE3\u7801
|
|
1950
|
+
2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
|
|
1951
|
+
3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
1952
|
+
4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
1935
1953
|
|
|
1936
1954
|
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
1937
1955
|
- \u540D\u79F0: ${session.context?.name}
|
|
1938
1956
|
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
1939
1957
|
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
1940
1958
|
|
|
1941
|
-
${session.context?.devStandards ? `\u3010\
|
|
1942
|
-
${session.context.devStandards.slice(0,
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1959
|
+
${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
|
|
1960
|
+
${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
1961
|
+
},
|
|
1962
|
+
{
|
|
1963
|
+
role: "user",
|
|
1964
|
+
content: taskPrompt
|
|
1965
|
+
}
|
|
1966
|
+
];
|
|
1967
|
+
const response = await ctx.modelService.sendMessage(messages, {
|
|
1968
|
+
temperature: 0.3,
|
|
1969
|
+
maxTokens: 4e3,
|
|
1970
|
+
// 单个任务减少 token
|
|
1971
|
+
agent: "frontend-dev",
|
|
1972
|
+
timeout: 12e4
|
|
1973
|
+
// 2分钟超时
|
|
1974
|
+
});
|
|
1975
|
+
const codeBlocks = parseCodeBlocks(response.content);
|
|
1976
|
+
if (codeBlocks.length > 0) {
|
|
1977
|
+
for (const block of codeBlocks) {
|
|
1978
|
+
const filePath = path5__namespace.join(workingDir, block.filename);
|
|
1979
|
+
const dir = path5__namespace.dirname(filePath);
|
|
1980
|
+
await fs5__namespace.mkdir(dir, { recursive: true });
|
|
1981
|
+
await fs5__namespace.writeFile(filePath, block.code, "utf-8");
|
|
1982
|
+
files.push(block.filename);
|
|
1983
|
+
}
|
|
1984
|
+
loader.stop(chalk9__default.default.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
|
|
1985
|
+
} else {
|
|
1986
|
+
const implDir = path5__namespace.join(workingDir, "src");
|
|
1987
|
+
await fs5__namespace.mkdir(implDir, { recursive: true });
|
|
1988
|
+
const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
|
|
1989
|
+
const filePath = path5__namespace.join(implDir, fileName);
|
|
1990
|
+
await fs5__namespace.writeFile(filePath, `// TODO: ${item.title}
|
|
1991
|
+
// ${item.description}
|
|
1992
|
+
`, "utf-8");
|
|
1993
|
+
files.push(`src/${fileName}`);
|
|
1994
|
+
loader.stop(chalk9__default.default.yellow(`${prefix} \u26A0 \u751F\u6210\u57FA\u7840\u6A21\u677F: ${item.title.slice(0, 20)}`));
|
|
1995
|
+
}
|
|
1996
|
+
if (i < session.specItems.length - 1) {
|
|
1997
|
+
await new Promise((resolve5) => setTimeout(resolve5, 500));
|
|
1947
1998
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
const response = await ctx.modelService.sendMessage(messages, {
|
|
1951
|
-
temperature: 0.3,
|
|
1952
|
-
maxTokens: 8e3,
|
|
1953
|
-
agent: "frontend-dev",
|
|
1954
|
-
timeout: 18e4
|
|
1955
|
-
// 3 分钟超时
|
|
1956
|
-
});
|
|
1957
|
-
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
1958
|
-
const codeBlocks = parseCodeBlocks(response.content);
|
|
1959
|
-
for (const block of codeBlocks) {
|
|
1960
|
-
const filePath = path5__namespace.join(workingDir, block.filename);
|
|
1961
|
-
const dir = path5__namespace.dirname(filePath);
|
|
1962
|
-
await fs5__namespace.mkdir(dir, { recursive: true });
|
|
1963
|
-
await fs5__namespace.writeFile(filePath, block.code, "utf-8");
|
|
1964
|
-
files.push(block.filename);
|
|
1965
|
-
}
|
|
1966
|
-
if (files.length === 0) {
|
|
1967
|
-
const implDir = path5__namespace.join(workingDir, "src", "features");
|
|
1968
|
-
await fs5__namespace.mkdir(implDir, { recursive: true });
|
|
1969
|
-
const featureName = session.specItems[0]?.title || "feature";
|
|
1970
|
-
const fileName = `${featureName.replace(/[^a-zA-Z0-9]/g, "_")}.ts`;
|
|
1971
|
-
const filePath = path5__namespace.join(implDir, fileName);
|
|
1972
|
-
const stubCode = `/**
|
|
1973
|
-
* ${session.requirement}
|
|
1974
|
-
*
|
|
1975
|
-
* TODO: \u6B64\u6587\u4EF6\u7531 AI \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u6839\u636E\u9700\u6C42\u5B8C\u5584\u5B9E\u73B0
|
|
1976
|
-
*/
|
|
1977
|
-
|
|
1978
|
-
export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
1979
|
-
// TODO: \u5B9E\u73B0\u529F\u80FD
|
|
1980
|
-
console.log('${featureName} - \u5F85\u5B9E\u73B0');
|
|
1981
|
-
}
|
|
1982
|
-
`;
|
|
1983
|
-
await fs5__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
1984
|
-
files.push(`src/features/${fileName}`);
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
loader.stop(chalk9__default.default.red(`${prefix} \u2717 \u5931\u8D25: ${error.message.slice(0, 40)}`));
|
|
1985
2001
|
}
|
|
1986
|
-
|
|
2002
|
+
}
|
|
2003
|
+
if (files.length > 0) {
|
|
1987
2004
|
return { success: true, files };
|
|
1988
|
-
}
|
|
1989
|
-
loader.stop();
|
|
2005
|
+
} else {
|
|
1990
2006
|
return {
|
|
1991
2007
|
success: false,
|
|
1992
2008
|
files: [],
|
|
1993
|
-
error:
|
|
2009
|
+
error: "\u6240\u6709\u4EFB\u52A1\u4EE3\u7801\u751F\u6210\u5931\u8D25"
|
|
1994
2010
|
};
|
|
1995
2011
|
}
|
|
1996
2012
|
}
|
|
1997
|
-
function
|
|
2013
|
+
function buildTaskPrompt(session, item, index) {
|
|
1998
2014
|
const lines = [];
|
|
1999
|
-
lines.push(
|
|
2000
|
-
lines.push(
|
|
2001
|
-
lines.push(
|
|
2002
|
-
lines.push(
|
|
2003
|
-
|
|
2004
|
-
lines.push(
|
|
2005
|
-
for (const
|
|
2006
|
-
lines.push(`- ${
|
|
2015
|
+
lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
|
|
2016
|
+
lines.push(`**\u6807\u9898**: ${item.title}`);
|
|
2017
|
+
lines.push(`**\u63CF\u8FF0**: ${item.description}`);
|
|
2018
|
+
lines.push(`**\u4F18\u5148\u7EA7**: ${item.priority}`);
|
|
2019
|
+
if (item.tests && item.tests.length > 0) {
|
|
2020
|
+
lines.push(`**\u9A8C\u6536\u6807\u51C6**:`);
|
|
2021
|
+
for (const t of item.tests) {
|
|
2022
|
+
lines.push(`- ${t}`);
|
|
2007
2023
|
}
|
|
2008
2024
|
}
|
|
2009
2025
|
lines.push("");
|
|
2010
|
-
lines.push(
|
|
2011
|
-
|
|
2012
|
-
|
|
2026
|
+
lines.push(`## \u6574\u4F53\u9700\u6C42\u80CC\u666F`);
|
|
2027
|
+
lines.push(session.requirement);
|
|
2028
|
+
const relatedScenario = session.bddScenarios.find(
|
|
2029
|
+
(s) => item.title.includes(s.feature) || s.feature.includes(item.title)
|
|
2030
|
+
);
|
|
2031
|
+
if (relatedScenario) {
|
|
2032
|
+
lines.push("");
|
|
2033
|
+
lines.push(`## \u76F8\u5173 BDD \u573A\u666F`);
|
|
2034
|
+
lines.push(`Feature: ${relatedScenario.feature}`);
|
|
2035
|
+
for (const s of relatedScenario.scenarios.slice(0, 2)) {
|
|
2036
|
+
lines.push(`- ${s.name}`);
|
|
2037
|
+
}
|
|
2013
2038
|
}
|
|
2014
2039
|
lines.push("");
|
|
2015
|
-
lines.push("\u8BF7\
|
|
2040
|
+
lines.push("\u8BF7\u751F\u6210\u5B9E\u73B0\u6B64\u4EFB\u52A1\u7684\u4EE3\u7801\u3002\u53EA\u751F\u6210\u5F53\u524D\u4EFB\u52A1\u9700\u8981\u7684\u6587\u4EF6\u3002");
|
|
2016
2041
|
return lines.join("\n");
|
|
2017
2042
|
}
|
|
2018
2043
|
function parseCodeBlocks(content) {
|
|
@@ -2479,6 +2504,111 @@ function generateSpecItems(requirement, context, bddScenarios, questions, refere
|
|
|
2479
2504
|
});
|
|
2480
2505
|
return items;
|
|
2481
2506
|
}
|
|
2507
|
+
async function generateSpecItemsWithAI(requirement, context, bddScenarios, questions, references, ctx) {
|
|
2508
|
+
const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u9879\u76EE\u7ECF\u7406\u548C\u6280\u672F\u67B6\u6784\u5E08\u3002\u8BF7\u5C06\u4EE5\u4E0B\u9700\u6C42\u62C6\u5206\u4E3A\u7CBE\u7EC6\u5316\u7684\u5F00\u53D1\u4EFB\u52A1\u3002
|
|
2509
|
+
|
|
2510
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
2511
|
+
${requirement}
|
|
2512
|
+
|
|
2513
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
2514
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
|
|
2515
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
2516
|
+
${context.devStandards ? `
|
|
2517
|
+
## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
|
|
2518
|
+
${context.devStandards.slice(0, 2e3)}
|
|
2519
|
+
` : ""}
|
|
2520
|
+
|
|
2521
|
+
## BDD \u573A\u666F\u53C2\u8003
|
|
2522
|
+
${bddScenarios.map((s) => `- Feature: ${s.feature} (${s.scenarios.length} \u4E2A\u573A\u666F)`).join("\n")}
|
|
2523
|
+
|
|
2524
|
+
## \u6F84\u6E05\u4FE1\u606F
|
|
2525
|
+
${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`).join("\n") || "\u65E0"}
|
|
2526
|
+
|
|
2527
|
+
## \u62C6\u5206\u8981\u6C42
|
|
2528
|
+
|
|
2529
|
+
\u8BF7\u5C06\u9700\u6C42\u62C6\u5206\u4E3A **\u7EC6\u7C92\u5EA6\u7684\u5F00\u53D1\u4EFB\u52A1**\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\uFF1A
|
|
2530
|
+
1. **\u5355\u4E00\u804C\u8D23** - \u4E00\u4E2A\u4EFB\u52A1\u53EA\u505A\u4E00\u4EF6\u4E8B
|
|
2531
|
+
2. **\u53EF\u72EC\u7ACB\u6D4B\u8BD5** - \u6709\u660E\u786E\u7684\u9A8C\u6536\u6807\u51C6
|
|
2532
|
+
3. **2-4\u5C0F\u65F6\u53EF\u5B8C\u6210** - \u5982\u679C\u4EFB\u52A1\u592A\u5927\uFF0C\u7EE7\u7EED\u62C6\u5206
|
|
2533
|
+
4. **\u6709\u660E\u786E\u7684\u8F93\u5165\u8F93\u51FA** - \u6E05\u695A\u77E5\u9053\u9700\u8981\u4EC0\u4E48\u3001\u4EA7\u51FA\u4EC0\u4E48
|
|
2534
|
+
|
|
2535
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
2536
|
+
\`\`\`json
|
|
2537
|
+
[
|
|
2538
|
+
{
|
|
2539
|
+
"id": "T001",
|
|
2540
|
+
"title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
|
|
2541
|
+
"description": "\u8BE6\u7EC6\u63CF\u8FF0\uFF1A\u8981\u505A\u4EC0\u4E48\u3001\u5982\u4F55\u505A\u3001\u9A8C\u6536\u6807\u51C6",
|
|
2542
|
+
"priority": "high",
|
|
2543
|
+
"estimatedHours": 2,
|
|
2544
|
+
"dependencies": [],
|
|
2545
|
+
"acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
|
|
2546
|
+
}
|
|
2547
|
+
]
|
|
2548
|
+
\`\`\`
|
|
2549
|
+
|
|
2550
|
+
## \u62C6\u5206\u5EFA\u8BAE
|
|
2551
|
+
\u5BF9\u4E8E\u590D\u6742\u529F\u80FD\uFF08\u5982\u7B97\u6CD5\u7C7B\uFF09\uFF0C\u5E94\u8BE5\u62C6\u5206\u4E3A\uFF1A
|
|
2552
|
+
- \u6570\u636E\u7ED3\u6784/\u6A21\u578B\u5B9A\u4E49
|
|
2553
|
+
- \u6838\u5FC3\u7B97\u6CD5\u5206\u6B65\u5B9E\u73B0\uFF08\u6BCF\u4E2A\u8BA1\u7B97\u6B65\u9AA4\u4E00\u4E2A\u4EFB\u52A1\uFF09
|
|
2554
|
+
- \u8F93\u5165\u9A8C\u8BC1
|
|
2555
|
+
- \u7ED3\u679C\u683C\u5F0F\u5316
|
|
2556
|
+
- UI \u5C55\u793A\u7EC4\u4EF6
|
|
2557
|
+
- \u96C6\u6210\u6D4B\u8BD5
|
|
2558
|
+
|
|
2559
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
|
|
2560
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
2561
|
+
loader.start();
|
|
2562
|
+
try {
|
|
2563
|
+
const response = await ctx.modelService.sendMessage([
|
|
2564
|
+
{ role: "user", content: prompt2 }
|
|
2565
|
+
], {
|
|
2566
|
+
temperature: 0.3,
|
|
2567
|
+
maxTokens: 4e3,
|
|
2568
|
+
timeout: 18e4
|
|
2569
|
+
// 增加到3分钟
|
|
2570
|
+
});
|
|
2571
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
2572
|
+
if (jsonMatch) {
|
|
2573
|
+
try {
|
|
2574
|
+
const parsed = JSON.parse(jsonMatch[1].trim());
|
|
2575
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
|
|
2576
|
+
return parsed.map((item, index) => ({
|
|
2577
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
2578
|
+
title: item.title,
|
|
2579
|
+
description: item.description,
|
|
2580
|
+
priority: item.priority || "medium",
|
|
2581
|
+
files: [],
|
|
2582
|
+
tests: item.acceptanceCriteria || []
|
|
2583
|
+
}));
|
|
2584
|
+
} catch (parseError) {
|
|
2585
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 JSON \u89E3\u6790\u5931\u8D25: ${parseError.message.slice(0, 50)}`));
|
|
2586
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
try {
|
|
2590
|
+
const parsed = JSON.parse(response.content);
|
|
2591
|
+
if (Array.isArray(parsed)) {
|
|
2592
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
|
|
2593
|
+
return parsed.map((item, index) => ({
|
|
2594
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
2595
|
+
title: item.title,
|
|
2596
|
+
description: item.description,
|
|
2597
|
+
priority: item.priority || "medium",
|
|
2598
|
+
files: [],
|
|
2599
|
+
tests: item.acceptanceCriteria || []
|
|
2600
|
+
}));
|
|
2601
|
+
}
|
|
2602
|
+
} catch {
|
|
2603
|
+
}
|
|
2604
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u672A\u80FD\u89E3\u6790 AI \u54CD\u5E94\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
|
|
2605
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2606
|
+
} catch (error) {
|
|
2607
|
+
const errMsg = error.message.slice(0, 80);
|
|
2608
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 AI \u8C03\u7528\u5931\u8D25: ${errMsg}`));
|
|
2609
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2482
2612
|
async function saveSpecFile(workingDir, session) {
|
|
2483
2613
|
const specDir = path5__namespace.join(workingDir, "openspec", "changes");
|
|
2484
2614
|
await fs5__namespace.mkdir(specDir, { recursive: true });
|