@nick848/sf-cli 1.0.20 → 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 +122 -92
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +121 -91
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -91
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1929,107 +1929,115 @@ function getCategoryLabel(category) {
|
|
|
1929
1929
|
async function executeDevelopment(ctx, session) {
|
|
1930
1930
|
const workingDir = ctx.options.workingDirectory;
|
|
1931
1931
|
const files = [];
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
const
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
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
|
|
1940
1947
|
|
|
1941
1948
|
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
1942
|
-
1. \
|
|
1943
|
-
2. \
|
|
1944
|
-
3. \
|
|
1945
|
-
|
|
1946
|
-
\u4EE3\u7801\u8981\u6C42\uFF1A
|
|
1947
|
-
1. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
1948
|
-
2. \u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u4EE3\u7801\u98CE\u683C\u548C\u89C4\u8303
|
|
1949
|
-
3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808
|
|
1950
|
-
4. \u4EE3\u7801\u8981\u6709\u9002\u5F53\u7684\u6CE8\u91CA
|
|
1951
|
-
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
|
|
1952
1953
|
|
|
1953
1954
|
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
1954
1955
|
- \u540D\u79F0: ${session.context?.name}
|
|
1955
1956
|
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
1956
1957
|
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
1957
1958
|
|
|
1958
|
-
${session.context?.devStandards ? `\u3010\
|
|
1959
|
-
${session.context.devStandards.slice(0,
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
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));
|
|
1964
1998
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
const response = await ctx.modelService.sendMessage(messages, {
|
|
1968
|
-
temperature: 0.3,
|
|
1969
|
-
maxTokens: 8e3,
|
|
1970
|
-
agent: "frontend-dev",
|
|
1971
|
-
timeout: 18e4
|
|
1972
|
-
// 3 分钟超时
|
|
1973
|
-
});
|
|
1974
|
-
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
1975
|
-
const codeBlocks = parseCodeBlocks(response.content);
|
|
1976
|
-
for (const block of codeBlocks) {
|
|
1977
|
-
const filePath = path5__namespace.join(workingDir, block.filename);
|
|
1978
|
-
const dir = path5__namespace.dirname(filePath);
|
|
1979
|
-
await fs5__namespace.mkdir(dir, { recursive: true });
|
|
1980
|
-
await fs5__namespace.writeFile(filePath, block.code, "utf-8");
|
|
1981
|
-
files.push(block.filename);
|
|
1982
|
-
}
|
|
1983
|
-
if (files.length === 0) {
|
|
1984
|
-
const implDir = path5__namespace.join(workingDir, "src", "features");
|
|
1985
|
-
await fs5__namespace.mkdir(implDir, { recursive: true });
|
|
1986
|
-
const featureName = session.specItems[0]?.title || "feature";
|
|
1987
|
-
const fileName = `${featureName.replace(/[^a-zA-Z0-9]/g, "_")}.ts`;
|
|
1988
|
-
const filePath = path5__namespace.join(implDir, fileName);
|
|
1989
|
-
const stubCode = `/**
|
|
1990
|
-
* ${session.requirement}
|
|
1991
|
-
*
|
|
1992
|
-
* TODO: \u6B64\u6587\u4EF6\u7531 AI \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u6839\u636E\u9700\u6C42\u5B8C\u5584\u5B9E\u73B0
|
|
1993
|
-
*/
|
|
1994
|
-
|
|
1995
|
-
export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
1996
|
-
// TODO: \u5B9E\u73B0\u529F\u80FD
|
|
1997
|
-
console.log('${featureName} - \u5F85\u5B9E\u73B0');
|
|
1998
|
-
}
|
|
1999
|
-
`;
|
|
2000
|
-
await fs5__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
2001
|
-
files.push(`src/features/${fileName}`);
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
loader.stop(chalk9__default.default.red(`${prefix} \u2717 \u5931\u8D25: ${error.message.slice(0, 40)}`));
|
|
2002
2001
|
}
|
|
2003
|
-
|
|
2002
|
+
}
|
|
2003
|
+
if (files.length > 0) {
|
|
2004
2004
|
return { success: true, files };
|
|
2005
|
-
}
|
|
2006
|
-
loader.stop();
|
|
2005
|
+
} else {
|
|
2007
2006
|
return {
|
|
2008
2007
|
success: false,
|
|
2009
2008
|
files: [],
|
|
2010
|
-
error:
|
|
2009
|
+
error: "\u6240\u6709\u4EFB\u52A1\u4EE3\u7801\u751F\u6210\u5931\u8D25"
|
|
2011
2010
|
};
|
|
2012
2011
|
}
|
|
2013
2012
|
}
|
|
2014
|
-
function
|
|
2013
|
+
function buildTaskPrompt(session, item, index) {
|
|
2015
2014
|
const lines = [];
|
|
2016
|
-
lines.push(
|
|
2017
|
-
lines.push(
|
|
2018
|
-
lines.push(
|
|
2019
|
-
lines.push(
|
|
2020
|
-
|
|
2021
|
-
lines.push(
|
|
2022
|
-
for (const
|
|
2023
|
-
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}`);
|
|
2024
2023
|
}
|
|
2025
2024
|
}
|
|
2026
2025
|
lines.push("");
|
|
2027
|
-
lines.push(
|
|
2028
|
-
|
|
2029
|
-
|
|
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
|
+
}
|
|
2030
2038
|
}
|
|
2031
2039
|
lines.push("");
|
|
2032
|
-
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");
|
|
2033
2041
|
return lines.join("\n");
|
|
2034
2042
|
}
|
|
2035
2043
|
function parseCodeBlocks(content) {
|
|
@@ -2557,25 +2565,47 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
2557
2565
|
], {
|
|
2558
2566
|
temperature: 0.3,
|
|
2559
2567
|
maxTokens: 4e3,
|
|
2560
|
-
timeout:
|
|
2568
|
+
timeout: 18e4
|
|
2569
|
+
// 增加到3分钟
|
|
2561
2570
|
});
|
|
2562
2571
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
2563
2572
|
if (jsonMatch) {
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
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"));
|
|
2576
2605
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2577
2606
|
} catch (error) {
|
|
2578
|
-
|
|
2607
|
+
const errMsg = error.message.slice(0, 80);
|
|
2608
|
+
loader.stop(chalk9__default.default.yellow(` \u26A0 AI \u8C03\u7528\u5931\u8D25: ${errMsg}`));
|
|
2579
2609
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
2580
2610
|
}
|
|
2581
2611
|
}
|