@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 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
- const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210\u4EE3\u7801");
1933
- loader.start();
1934
- try {
1935
- const systemPrompt = buildDevelopmentPrompt(session);
1936
- const messages = [
1937
- {
1938
- role: "system",
1939
- content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u9700\u6C42\u89C4\u683C\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002
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. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
1943
- 2. \u53C2\u8003\u8D44\u6E90\uFF08\u5982\u679C\u6709\uFF09\u4EC5\u7528\u4E8E\u7406\u89E3\u4E1A\u52A1\u529F\u80FD\uFF0C\u4E0D\u8981\u590D\u5236\u5176\u6280\u672F\u5B9E\u73B0
1944
- 3. \u4F7F\u7528\u9879\u76EE\u6307\u5B9A\u7684\u6280\u672F\u6808\u548C\u6846\u67B6
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\u5FC5\u987B\u9075\u5FAA\u7684\u5F00\u53D1\u89C4\u8303\u3011
1959
- ${session.context.devStandards.slice(0, 2500)}` : ""}`
1960
- },
1961
- {
1962
- role: "user",
1963
- content: systemPrompt
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
- loader.update("\u6B63\u5728\u8C03\u7528 AI \u6A21\u578B");
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
- loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u751F\u6210 ${files.length} \u4E2A\u6587\u4EF6`));
2002
+ }
2003
+ if (files.length > 0) {
2004
2004
  return { success: true, files };
2005
- } catch (error) {
2006
- loader.stop();
2005
+ } else {
2007
2006
  return {
2008
2007
  success: false,
2009
2008
  files: [],
2010
- error: error.message
2009
+ error: "\u6240\u6709\u4EFB\u52A1\u4EE3\u7801\u751F\u6210\u5931\u8D25"
2011
2010
  };
2012
2011
  }
2013
2012
  }
2014
- function buildDevelopmentPrompt(session) {
2013
+ function buildTaskPrompt(session, item, index) {
2015
2014
  const lines = [];
2016
- lines.push("## \u9700\u6C42\u63CF\u8FF0");
2017
- lines.push(session.refinedRequirement);
2018
- lines.push("");
2019
- lines.push("## BDD \u573A\u666F");
2020
- for (const scenario of session.bddScenarios) {
2021
- lines.push(`### ${scenario.feature}`);
2022
- for (const s of scenario.scenarios) {
2023
- lines.push(`- ${s.name}`);
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("## \u4EFB\u52A1\u5217\u8868");
2028
- for (const item of session.specItems) {
2029
- lines.push(`- [${item.id}] ${item.title}: ${item.description}`);
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\u6839\u636E\u4EE5\u4E0A\u9700\u6C42\u89C4\u683C\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002");
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: 12e4
2568
+ timeout: 18e4
2569
+ // 增加到3分钟
2561
2570
  });
2562
2571
  const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
2563
2572
  if (jsonMatch) {
2564
- const parsed = JSON.parse(jsonMatch[1].trim());
2565
- loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u62C6\u5206 ${parsed.length} \u4E2A\u4EFB\u52A1`));
2566
- return parsed.map((item) => ({
2567
- id: item.id || `T${String(parsed.indexOf(item) + 1).padStart(3, "0")}`,
2568
- title: item.title,
2569
- description: item.description,
2570
- priority: item.priority || "medium",
2571
- files: [],
2572
- tests: item.acceptanceCriteria || []
2573
- }));
2574
- }
2575
- loader.stop(chalk9__default.default.yellow(" \u26A0 \u89E3\u6790\u5931\u8D25\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
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
- loader.stop(chalk9__default.default.yellow(" \u26A0 AI \u62C6\u5206\u5931\u8D25\uFF0C\u4F7F\u7528\u57FA\u7840\u62C6\u5206"));
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
  }