@nick848/sf-cli 1.0.17 → 1.0.18
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 +330 -72
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +330 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +330 -72
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1549,12 +1549,26 @@ ${resource.analysis}`;
|
|
|
1549
1549
|
lines.push("");
|
|
1550
1550
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
1551
1551
|
lines.push("");
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
activeSession.
|
|
1556
|
-
|
|
1557
|
-
|
|
1552
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
|
|
1553
|
+
loader.start();
|
|
1554
|
+
try {
|
|
1555
|
+
activeSession.bddScenarios = await generateBDDScenariosWithAI(
|
|
1556
|
+
activeSession.refinedRequirement,
|
|
1557
|
+
activeSession.context,
|
|
1558
|
+
activeSession.clarificationQuestions,
|
|
1559
|
+
activeSession.referenceResources,
|
|
1560
|
+
ctx
|
|
1561
|
+
);
|
|
1562
|
+
loader.stop(chalk9__default.default.green(" \u2713 BDD \u573A\u666F\u5DF2\u751F\u6210"));
|
|
1563
|
+
} catch {
|
|
1564
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840 BDD \u751F\u6210"));
|
|
1565
|
+
activeSession.bddScenarios = generateBDDScenarios(
|
|
1566
|
+
activeSession.refinedRequirement,
|
|
1567
|
+
activeSession.context,
|
|
1568
|
+
activeSession.clarificationQuestions,
|
|
1569
|
+
activeSession.referenceResources
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1558
1572
|
for (const scenario of activeSession.bddScenarios) {
|
|
1559
1573
|
lines.push(chalk9__default.default.white(` Feature: ${scenario.feature}`));
|
|
1560
1574
|
for (const s of scenario.scenarios.slice(0, 3)) {
|
|
@@ -1601,7 +1615,7 @@ ${resource.analysis}`;
|
|
|
1601
1615
|
lines.push("");
|
|
1602
1616
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/9: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
1603
1617
|
lines.push("");
|
|
1604
|
-
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
1618
|
+
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession, ctx);
|
|
1605
1619
|
lines.push(chalk9__default.default.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
1606
1620
|
for (const file of activeSession.testFiles) {
|
|
1607
1621
|
lines.push(chalk9__default.default.gray(` - ${file}`));
|
|
@@ -1898,6 +1912,8 @@ function getCategoryLabel(category) {
|
|
|
1898
1912
|
async function executeDevelopment(ctx, session) {
|
|
1899
1913
|
const workingDir = ctx.options.workingDirectory;
|
|
1900
1914
|
const files = [];
|
|
1915
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u751F\u6210\u4EE3\u7801");
|
|
1916
|
+
loader.start();
|
|
1901
1917
|
try {
|
|
1902
1918
|
const systemPrompt = buildDevelopmentPrompt(session);
|
|
1903
1919
|
const messages = [
|
|
@@ -1925,11 +1941,15 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
1925
1941
|
content: systemPrompt
|
|
1926
1942
|
}
|
|
1927
1943
|
];
|
|
1944
|
+
loader.update("\u6B63\u5728\u8C03\u7528 AI \u6A21\u578B");
|
|
1928
1945
|
const response = await ctx.modelService.sendMessage(messages, {
|
|
1929
1946
|
temperature: 0.3,
|
|
1930
1947
|
maxTokens: 8e3,
|
|
1931
|
-
agent: "frontend-dev"
|
|
1948
|
+
agent: "frontend-dev",
|
|
1949
|
+
timeout: 18e4
|
|
1950
|
+
// 3 分钟超时
|
|
1932
1951
|
});
|
|
1952
|
+
loader.update("\u6B63\u5728\u89E3\u6790\u4EE3\u7801");
|
|
1933
1953
|
const codeBlocks = parseCodeBlocks(response.content);
|
|
1934
1954
|
for (const block of codeBlocks) {
|
|
1935
1955
|
const filePath = path5__namespace.join(workingDir, block.filename);
|
|
@@ -1958,8 +1978,10 @@ export function ${featureName.replace(/[^a-zA-Z0-9]/g, "")}() {
|
|
|
1958
1978
|
await fs5__namespace.writeFile(filePath, stubCode, "utf-8");
|
|
1959
1979
|
files.push(`src/features/${fileName}`);
|
|
1960
1980
|
}
|
|
1981
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u5DF2\u751F\u6210 ${files.length} \u4E2A\u6587\u4EF6`));
|
|
1961
1982
|
return { success: true, files };
|
|
1962
1983
|
} catch (error) {
|
|
1984
|
+
loader.stop();
|
|
1963
1985
|
return {
|
|
1964
1986
|
success: false,
|
|
1965
1987
|
files: [],
|
|
@@ -2243,36 +2265,125 @@ function generateBDDScenarios(requirement, context, questions, references = [])
|
|
|
2243
2265
|
}
|
|
2244
2266
|
return scenarios;
|
|
2245
2267
|
}
|
|
2268
|
+
async function generateBDDScenariosWithAI(requirement, context, questions, references, ctx) {
|
|
2269
|
+
const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\u548C\u4E1A\u52A1\u5206\u6790\u5E08\u3002\u8BF7\u6839\u636E\u4EE5\u4E0B\u9700\u6C42\u751F\u6210\u8BE6\u7EC6\u7684 BDD (Behavior Driven Development) \u573A\u666F\u3002
|
|
2270
|
+
|
|
2271
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
2272
|
+
${requirement}
|
|
2273
|
+
|
|
2274
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
2275
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "\u672A\u6307\u5B9A"}
|
|
2276
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
2277
|
+
|
|
2278
|
+
## \u6F84\u6E05\u95EE\u7B54
|
|
2279
|
+
${questions.filter((q) => q.answered).map((q) => `- Q: ${q.question}
|
|
2280
|
+
A: ${q.answer}`).join("\n")}
|
|
2281
|
+
|
|
2282
|
+
## \u53C2\u8003\u8D44\u6E90\u5206\u6790
|
|
2283
|
+
${references.map((r) => `### ${r.url}
|
|
2284
|
+
${r.analysis}`).join("\n\n")}
|
|
2285
|
+
|
|
2286
|
+
## \u8981\u6C42
|
|
2287
|
+
1. \u6BCF\u4E2A\u529F\u80FD\u6A21\u5757\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684 Feature
|
|
2288
|
+
2. \u6BCF\u4E2A Feature \u5305\u542B\u591A\u4E2A\u5177\u4F53\u7684 Scenario
|
|
2289
|
+
3. \u4F7F\u7528 Given-When-Then \u683C\u5F0F
|
|
2290
|
+
4. \u573A\u666F\u8981\u8986\u76D6: \u6B63\u5E38\u6D41\u7A0B\u3001\u8FB9\u754C\u60C5\u51B5\u3001\u5F02\u5E38\u5904\u7406
|
|
2291
|
+
5. \u573A\u666F\u8981\u5177\u4F53\u53EF\u6D4B\u8BD5\uFF0C\u4E0D\u8981\u6CDB\u6CDB\u800C\u8C08
|
|
2292
|
+
|
|
2293
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
2294
|
+
\`\`\`json
|
|
2295
|
+
[
|
|
2296
|
+
{
|
|
2297
|
+
"feature": "\u529F\u80FD\u540D\u79F0",
|
|
2298
|
+
"description": "\u529F\u80FD\u63CF\u8FF0",
|
|
2299
|
+
"scenarios": [
|
|
2300
|
+
{
|
|
2301
|
+
"name": "\u573A\u666F\u540D\u79F0",
|
|
2302
|
+
"given": ["\u524D\u7F6E\u6761\u4EF61", "\u524D\u7F6E\u6761\u4EF62"],
|
|
2303
|
+
"when": ["\u64CD\u4F5C1", "\u64CD\u4F5C2"],
|
|
2304
|
+
"then": ["\u9884\u671F\u7ED3\u679C1", "\u9884\u671F\u7ED3\u679C2"]
|
|
2305
|
+
}
|
|
2306
|
+
]
|
|
2307
|
+
}
|
|
2308
|
+
]
|
|
2309
|
+
\`\`\`
|
|
2310
|
+
|
|
2311
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u6709\u5176\u4ED6\u5185\u5BB9\u3002`;
|
|
2312
|
+
const response = await ctx.modelService.sendMessage([
|
|
2313
|
+
{ role: "user", content: prompt2 }
|
|
2314
|
+
], {
|
|
2315
|
+
temperature: 0.3,
|
|
2316
|
+
maxTokens: 4e3,
|
|
2317
|
+
timeout: 12e4
|
|
2318
|
+
});
|
|
2319
|
+
try {
|
|
2320
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
2321
|
+
if (jsonMatch) {
|
|
2322
|
+
return JSON.parse(jsonMatch[1].trim());
|
|
2323
|
+
}
|
|
2324
|
+
return JSON.parse(response.content);
|
|
2325
|
+
} catch {
|
|
2326
|
+
return generateBDDScenarios(requirement, context, questions, references);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2246
2329
|
function extractFeaturesFromReference(ref) {
|
|
2247
2330
|
const features = [];
|
|
2248
|
-
const analysis = ref.analysis
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
2260
|
-
hasInput: false
|
|
2261
|
-
});
|
|
2331
|
+
const analysis = ref.analysis;
|
|
2332
|
+
const featureSection = analysis.match(/###?\s*4\.\s*功能拆分建议[\s\S]*?(?=###?\s*\d|$)/i);
|
|
2333
|
+
if (featureSection) {
|
|
2334
|
+
const taskMatches = featureSection[0].matchAll(/[-*]\s*\*\*([^*]+)\*\*[::]?\s*([^\n]+)/g);
|
|
2335
|
+
for (const match of taskMatches) {
|
|
2336
|
+
features.push({
|
|
2337
|
+
title: match[1].trim(),
|
|
2338
|
+
description: match[2].trim(),
|
|
2339
|
+
hasInput: match[2].includes("\u8F93\u5165") || match[2].includes("\u8868\u5355") || match[2].includes("\u7528\u6237")
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2262
2342
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2343
|
+
const bizSection = analysis.match(/###?\s*1\.\s*业务功能分析[\s\S]*?(?=###?\s*\d|$)/i);
|
|
2344
|
+
if (bizSection && features.length === 0) {
|
|
2345
|
+
const lines = bizSection[0].split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*"));
|
|
2346
|
+
for (const line of lines.slice(0, 5)) {
|
|
2347
|
+
const content = line.replace(/^[-*]\s*/, "").trim();
|
|
2348
|
+
if (content.length > 5) {
|
|
2349
|
+
features.push({
|
|
2350
|
+
title: content.slice(0, 20),
|
|
2351
|
+
description: content,
|
|
2352
|
+
hasInput: content.includes("\u8F93\u5165") || content.includes("\u586B\u5199")
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2269
2356
|
}
|
|
2270
|
-
if (
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2357
|
+
if (features.length === 0) {
|
|
2358
|
+
const lowerAnalysis = analysis.toLowerCase();
|
|
2359
|
+
if (lowerAnalysis.includes("\u8F93\u5165") || lowerAnalysis.includes("\u8868\u5355")) {
|
|
2360
|
+
features.push({
|
|
2361
|
+
title: "\u8F93\u5165\u8868\u5355",
|
|
2362
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
|
|
2363
|
+
hasInput: true
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2366
|
+
if (lowerAnalysis.includes("\u6309\u94AE") || lowerAnalysis.includes("\u64CD\u4F5C")) {
|
|
2367
|
+
features.push({
|
|
2368
|
+
title: "\u4EA4\u4E92\u6309\u94AE",
|
|
2369
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
2370
|
+
hasInput: false
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
if (lowerAnalysis.includes("\u8868\u683C") || lowerAnalysis.includes("\u5217\u8868")) {
|
|
2374
|
+
features.push({
|
|
2375
|
+
title: "\u6570\u636E\u5217\u8868",
|
|
2376
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
|
|
2377
|
+
hasInput: false
|
|
2378
|
+
});
|
|
2379
|
+
}
|
|
2380
|
+
if (lowerAnalysis.includes("\u56FE\u8868") || lowerAnalysis.includes("\u53EF\u89C6\u5316")) {
|
|
2381
|
+
features.push({
|
|
2382
|
+
title: "\u56FE\u8868\u5C55\u793A",
|
|
2383
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
|
|
2384
|
+
hasInput: false
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2276
2387
|
}
|
|
2277
2388
|
if (features.length === 0) {
|
|
2278
2389
|
features.push({
|
|
@@ -2436,33 +2547,119 @@ function formatSpecFile(session) {
|
|
|
2436
2547
|
lines.push("**\u786E\u8BA4\u72B6\u6001**: \u23F3 \u7B49\u5F85\u786E\u8BA4");
|
|
2437
2548
|
return lines.join("\n");
|
|
2438
2549
|
}
|
|
2439
|
-
async function generateTests(workingDir, session) {
|
|
2550
|
+
async function generateTests(workingDir, session, ctx) {
|
|
2440
2551
|
const testDir = path5__namespace.join(workingDir, "tests");
|
|
2441
2552
|
await fs5__namespace.mkdir(testDir, { recursive: true });
|
|
2442
2553
|
const testFiles = [];
|
|
2443
|
-
|
|
2444
|
-
const
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2554
|
+
if (ctx?.modelService) {
|
|
2555
|
+
for (const scenario of session.bddScenarios) {
|
|
2556
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
2557
|
+
const testPath = path5__namespace.join(testDir, `${testName}.test.ts`);
|
|
2558
|
+
const loader = new LoadingIndicator(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
|
|
2559
|
+
loader.start();
|
|
2560
|
+
try {
|
|
2561
|
+
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
2562
|
+
await fs5__namespace.writeFile(testPath, content, "utf-8");
|
|
2563
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
2564
|
+
loader.stop(chalk9__default.default.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
|
|
2565
|
+
} catch {
|
|
2566
|
+
const content = generateTestFile(scenario, session);
|
|
2567
|
+
await fs5__namespace.writeFile(testPath, content, "utf-8");
|
|
2568
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
2569
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
} else {
|
|
2573
|
+
for (const scenario of session.bddScenarios) {
|
|
2574
|
+
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
2575
|
+
const testPath = path5__namespace.join(testDir, `${testName}.test.ts`);
|
|
2576
|
+
const content = generateTestFile(scenario, session);
|
|
2577
|
+
await fs5__namespace.writeFile(testPath, content, "utf-8");
|
|
2578
|
+
testFiles.push(`tests/${testName}.test.ts`);
|
|
2579
|
+
}
|
|
2449
2580
|
}
|
|
2450
2581
|
return testFiles;
|
|
2451
2582
|
}
|
|
2452
|
-
function
|
|
2583
|
+
async function generateTestFileWithAI(scenario, session, ctx) {
|
|
2584
|
+
const prompt2 = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u4EE5\u4E0B BDD \u573A\u666F\u751F\u6210\u5B8C\u6574\u7684 Vitest \u6D4B\u8BD5\u4EE3\u7801\u3002
|
|
2585
|
+
|
|
2586
|
+
## \u529F\u80FD\u540D\u79F0
|
|
2587
|
+
${scenario.feature}
|
|
2588
|
+
|
|
2589
|
+
## BDD \u573A\u666F
|
|
2590
|
+
${scenario.scenarios.map((s) => `
|
|
2591
|
+
### ${s.name}
|
|
2592
|
+
- Given: ${s.given.join(", ")}
|
|
2593
|
+
- When: ${s.when.join(", ")}
|
|
2594
|
+
- Then: ${s.then.join(", ")}
|
|
2595
|
+
`).join("\n")}
|
|
2596
|
+
|
|
2597
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
2598
|
+
- \u6280\u672F\u6808: ${session.context?.techStack?.join(", ") || "TypeScript"}
|
|
2599
|
+
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
2600
|
+
|
|
2601
|
+
## \u8981\u6C42
|
|
2602
|
+
1. \u4F7F\u7528 vitest \u6D4B\u8BD5\u6846\u67B6 (describe, it, expect, beforeEach \u7B49)
|
|
2603
|
+
2. \u6BCF\u4E2A\u573A\u666F\u751F\u6210\u4E00\u4E2A\u72EC\u7ACB\u7684\u6D4B\u8BD5\u7528\u4F8B
|
|
2604
|
+
3. \u6D4B\u8BD5\u4EE3\u7801\u8981\u5B8C\u6574\u53EF\u8FD0\u884C\uFF0C\u5305\u542B\u5FC5\u8981\u7684 mock \u548C setup
|
|
2605
|
+
4. \u4F7F\u7528\u4E2D\u6587\u6CE8\u91CA\u8BF4\u660E\u6D4B\u8BD5\u610F\u56FE
|
|
2606
|
+
5. \u6D4B\u8BD5\u8981\u8986\u76D6\u6B63\u5E38\u6D41\u7A0B\u548C\u8FB9\u754C\u60C5\u51B5
|
|
2607
|
+
|
|
2608
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801\uFF0C\u4E0D\u9700\u8981\u89E3\u91CA\u3002`;
|
|
2609
|
+
const response = await ctx.modelService.sendMessage([
|
|
2610
|
+
{ role: "user", content: prompt2 }
|
|
2611
|
+
], {
|
|
2612
|
+
temperature: 0.3,
|
|
2613
|
+
maxTokens: 4e3
|
|
2614
|
+
});
|
|
2615
|
+
const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
|
|
2616
|
+
if (codeMatch) {
|
|
2617
|
+
return codeMatch[1].trim();
|
|
2618
|
+
}
|
|
2619
|
+
return response.content;
|
|
2620
|
+
}
|
|
2621
|
+
function generateTestFile(scenario, session) {
|
|
2453
2622
|
const lines = [];
|
|
2454
|
-
lines.push(`import { describe, it, expect } from 'vitest';`);
|
|
2623
|
+
lines.push(`import { describe, it, expect, beforeEach } from 'vitest';`);
|
|
2455
2624
|
lines.push("");
|
|
2625
|
+
lines.push(`/**`);
|
|
2626
|
+
lines.push(` * ${scenario.feature} \u529F\u80FD\u6D4B\u8BD5`);
|
|
2627
|
+
lines.push(` * `);
|
|
2628
|
+
lines.push(` * BDD \u573A\u666F\u6570\u91CF: ${scenario.scenarios.length}`);
|
|
2629
|
+
if (session?.context?.techStack) {
|
|
2630
|
+
lines.push(` * \u6280\u672F\u6808: ${session.context.techStack.join(", ")}`);
|
|
2631
|
+
}
|
|
2632
|
+
lines.push(` */`);
|
|
2456
2633
|
lines.push(`describe('${scenario.feature}', () => {`);
|
|
2457
2634
|
for (const s of scenario.scenarios) {
|
|
2458
|
-
lines.push(` it('${s.name}', () => {`);
|
|
2459
|
-
lines.push(` // Given: ${s.given.join(", ")}`);
|
|
2460
|
-
lines.push(` // When: ${s.when.join(", ")}`);
|
|
2461
|
-
lines.push(` // Then: ${s.then.join(", ")}`);
|
|
2462
|
-
lines.push(` expect(true).toBe(true); // TODO: \u5B9E\u73B0\u6D4B\u8BD5`);
|
|
2463
|
-
lines.push(` });`);
|
|
2464
2635
|
lines.push("");
|
|
2636
|
+
lines.push(` /**`);
|
|
2637
|
+
lines.push(` * \u573A\u666F: ${s.name}`);
|
|
2638
|
+
lines.push(` * Given: ${s.given.join(", ")}`);
|
|
2639
|
+
lines.push(` * When: ${s.when.join(", ")}`);
|
|
2640
|
+
lines.push(` * Then: ${s.then.join(", ")}`);
|
|
2641
|
+
lines.push(` */`);
|
|
2642
|
+
lines.push(` it('${s.name}', async () => {`);
|
|
2643
|
+
lines.push(` // Arrange (Given)`);
|
|
2644
|
+
for (const g of s.given) {
|
|
2645
|
+
lines.push(` // ${g}`);
|
|
2646
|
+
}
|
|
2647
|
+
lines.push(` const input = {}; // TODO: \u8BBE\u7F6E\u521D\u59CB\u72B6\u6001`);
|
|
2648
|
+
lines.push("");
|
|
2649
|
+
lines.push(` // Act (When)`);
|
|
2650
|
+
for (const w of s.when) {
|
|
2651
|
+
lines.push(` // ${w}`);
|
|
2652
|
+
}
|
|
2653
|
+
lines.push(` const result = {}; // TODO: \u6267\u884C\u64CD\u4F5C`);
|
|
2654
|
+
lines.push("");
|
|
2655
|
+
lines.push(` // Assert (Then)`);
|
|
2656
|
+
for (const t of s.then) {
|
|
2657
|
+
lines.push(` // ${t}`);
|
|
2658
|
+
}
|
|
2659
|
+
lines.push(` expect(result).toBeDefined(); // TODO: \u5B8C\u5584\u65AD\u8A00`);
|
|
2660
|
+
lines.push(` });`);
|
|
2465
2661
|
}
|
|
2662
|
+
lines.push("");
|
|
2466
2663
|
lines.push(`});`);
|
|
2467
2664
|
return lines.join("\n");
|
|
2468
2665
|
}
|
|
@@ -2545,39 +2742,67 @@ function detectResourceType(url) {
|
|
|
2545
2742
|
return "webpage";
|
|
2546
2743
|
}
|
|
2547
2744
|
async function analyzeReferenceContent(url, content, type, ctx) {
|
|
2548
|
-
const typePrompts = {
|
|
2549
|
-
webpage: "\u5206\u6790\u8FD9\u4E2A\u7F51\u9875\u7684\u529F\u80FD\u3001UI\u7EC4\u4EF6\u548C\u4EA4\u4E92\u65B9\u5F0F",
|
|
2550
|
-
design: "\u5206\u6790\u8FD9\u4E2A\u8BBE\u8BA1\u7A3F\u7684\u5E03\u5C40\u3001\u7EC4\u4EF6\u548C\u6837\u5F0F",
|
|
2551
|
-
image: "\u63CF\u8FF0\u8FD9\u4E2A\u56FE\u7247\u7684\u5185\u5BB9\u548C\u8BBE\u8BA1\u5143\u7D20",
|
|
2552
|
-
api: "\u5206\u6790\u8FD9\u4E2AAPI\u7684\u7ED3\u6784\u548C\u53C2\u6570"
|
|
2553
|
-
};
|
|
2554
2745
|
const prompt2 = `
|
|
2555
|
-
\u8BF7\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\
|
|
2746
|
+
\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u4EA7\u54C1\u7ECF\u7406\u548C\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6DF1\u5165\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\uFF0C\u63D0\u53D6\u4E1A\u52A1\u529F\u80FD\u548C\u6280\u672F\u5B9E\u73B0\u7EC6\u8282\u3002
|
|
2747
|
+
|
|
2748
|
+
## \u53C2\u8003\u8D44\u6E90\u4FE1\u606F
|
|
2749
|
+
- URL: ${url}
|
|
2750
|
+
- \u7C7B\u578B: ${type}
|
|
2751
|
+
|
|
2752
|
+
## \u7F51\u9875\u5185\u5BB9
|
|
2753
|
+
\`\`\`html
|
|
2754
|
+
${content.slice(0, 8e3)}
|
|
2755
|
+
\`\`\`
|
|
2756
|
+
|
|
2757
|
+
## \u5206\u6790\u8981\u6C42
|
|
2556
2758
|
|
|
2557
|
-
|
|
2558
|
-
\u7C7B\u578B: ${type}
|
|
2759
|
+
\u8BF7\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u8FDB\u884C\u8BE6\u7EC6\u5206\u6790\uFF1A
|
|
2559
2760
|
|
|
2560
|
-
\
|
|
2561
|
-
|
|
2761
|
+
### 1. \u4E1A\u52A1\u529F\u80FD\u5206\u6790
|
|
2762
|
+
- \u6838\u5FC3\u4E1A\u52A1\u529F\u80FD\u662F\u4EC0\u4E48\uFF1F\uFF08\u8BE6\u7EC6\u63CF\u8FF0\uFF09
|
|
2763
|
+
- \u7528\u6237\u53EF\u4EE5\u505A\u4EC0\u4E48\u64CD\u4F5C\uFF1F
|
|
2764
|
+
- \u4E1A\u52A1\u6D41\u7A0B\u662F\u4EC0\u4E48\uFF1F
|
|
2765
|
+
- \u6570\u636E\u8F93\u5165\u8F93\u51FA\u662F\u4EC0\u4E48\uFF1F
|
|
2562
2766
|
|
|
2563
|
-
|
|
2767
|
+
### 2. UI/UX \u7ED3\u6784\u5206\u6790
|
|
2768
|
+
- \u9875\u9762\u5E03\u5C40\u7ED3\u6784
|
|
2769
|
+
- \u4E3B\u8981\u7EC4\u4EF6\u6709\u54EA\u4E9B\uFF1F
|
|
2770
|
+
- \u7EC4\u4EF6\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
2771
|
+
- \u4EA4\u4E92\u65B9\u5F0F\uFF08\u70B9\u51FB\u3001\u8F93\u5165\u3001\u62D6\u62FD\u7B49\uFF09
|
|
2564
2772
|
|
|
2565
|
-
\
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
4. \u6570\u636E\u7ED3\u6784\uFF08\u5982\u679C\u6709\uFF09
|
|
2570
|
-
5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
2773
|
+
### 3. \u6570\u636E\u6A21\u578B\u5206\u6790
|
|
2774
|
+
- \u9700\u8981\u54EA\u4E9B\u6570\u636E\uFF1F
|
|
2775
|
+
- \u6570\u636E\u4E4B\u95F4\u7684\u5173\u7CFB
|
|
2776
|
+
- \u6570\u636E\u6765\u6E90\uFF08\u7528\u6237\u8F93\u5165/\u8BA1\u7B97/API\uFF09
|
|
2571
2777
|
|
|
2572
|
-
\
|
|
2778
|
+
### 4. \u529F\u80FD\u62C6\u5206\u5EFA\u8BAE
|
|
2779
|
+
\u8BF7\u5C06\u529F\u80FD\u62C6\u5206\u4E3A\u53EF\u72EC\u7ACB\u5F00\u53D1\u7684\u4EFB\u52A1\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u5305\u542B\uFF1A
|
|
2780
|
+
- \u4EFB\u52A1\u540D\u79F0
|
|
2781
|
+
- \u4EFB\u52A1\u63CF\u8FF0
|
|
2782
|
+
- \u6280\u672F\u8981\u70B9
|
|
2783
|
+
- \u4F9D\u8D56\u5173\u7CFB
|
|
2784
|
+
|
|
2785
|
+
### 5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
2786
|
+
- \u63A8\u8350\u7684\u6280\u672F\u65B9\u6848
|
|
2787
|
+
- \u9700\u8981\u6CE8\u610F\u7684\u6280\u672F\u96BE\u70B9
|
|
2788
|
+
- \u6027\u80FD\u4F18\u5316\u5EFA\u8BAE
|
|
2789
|
+
|
|
2790
|
+
\u8BF7\u4EE5 Markdown \u683C\u5F0F\u8F93\u51FA\uFF0C\u91CD\u70B9\u7A81\u51FA\u4E1A\u52A1\u903B\u8F91\u548C\u529F\u80FD\u5B9E\u73B0\u7EC6\u8282\u3002
|
|
2573
2791
|
`;
|
|
2792
|
+
const loader = new LoadingIndicator("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
|
|
2793
|
+
loader.start();
|
|
2574
2794
|
try {
|
|
2575
2795
|
const response = await ctx.modelService.sendMessage([
|
|
2576
2796
|
{ role: "user", content: prompt2 }
|
|
2577
|
-
], {
|
|
2797
|
+
], {
|
|
2798
|
+
temperature: 0.3,
|
|
2799
|
+
maxTokens: 4e3
|
|
2800
|
+
});
|
|
2801
|
+
loader.stop(chalk9__default.default.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
|
|
2578
2802
|
return response.content;
|
|
2579
|
-
} catch {
|
|
2580
|
-
|
|
2803
|
+
} catch (error) {
|
|
2804
|
+
loader.stop();
|
|
2805
|
+
throw error;
|
|
2581
2806
|
}
|
|
2582
2807
|
}
|
|
2583
2808
|
function extractBasicInfo(content, type) {
|
|
@@ -2618,10 +2843,43 @@ function getActiveSession() {
|
|
|
2618
2843
|
function clearActiveSession() {
|
|
2619
2844
|
activeSession = null;
|
|
2620
2845
|
}
|
|
2621
|
-
var MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
2846
|
+
var LoadingIndicator, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
2622
2847
|
var init_new = __esm({
|
|
2623
2848
|
"src/commands/new.ts"() {
|
|
2624
2849
|
init_cjs_shims();
|
|
2850
|
+
LoadingIndicator = class {
|
|
2851
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2852
|
+
frameIndex = 0;
|
|
2853
|
+
interval = null;
|
|
2854
|
+
message;
|
|
2855
|
+
constructor(message) {
|
|
2856
|
+
this.message = message;
|
|
2857
|
+
}
|
|
2858
|
+
start() {
|
|
2859
|
+
process.stdout.write("\x1B[?25l");
|
|
2860
|
+
this.interval = setInterval(() => {
|
|
2861
|
+
const frame = this.frames[this.frameIndex];
|
|
2862
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
2863
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
2864
|
+
}, 80);
|
|
2865
|
+
}
|
|
2866
|
+
update(message) {
|
|
2867
|
+
this.message = message;
|
|
2868
|
+
}
|
|
2869
|
+
stop(finalMessage) {
|
|
2870
|
+
if (this.interval) {
|
|
2871
|
+
clearInterval(this.interval);
|
|
2872
|
+
this.interval = null;
|
|
2873
|
+
}
|
|
2874
|
+
process.stdout.write("\x1B[?25h");
|
|
2875
|
+
if (finalMessage) {
|
|
2876
|
+
process.stdout.write(`\r${finalMessage}
|
|
2877
|
+
`);
|
|
2878
|
+
} else {
|
|
2879
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
};
|
|
2625
2883
|
MAX_FILE_SIZE2 = 1024 * 1024;
|
|
2626
2884
|
COMPLEXITY_THRESHOLD = 6;
|
|
2627
2885
|
CLARITY_THRESHOLD = 0.6;
|