@nick848/sf-cli 1.0.21 → 1.0.23
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 +613 -143
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +609 -139
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +608 -138
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chalk9 = require('chalk');
|
|
4
|
-
var
|
|
4
|
+
var fs9 = require('fs/promises');
|
|
5
5
|
var path4 = require('path');
|
|
6
6
|
var fs10 = require('fs');
|
|
7
7
|
var crypto = require('crypto');
|
|
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
|
|
37
|
-
var
|
|
37
|
+
var fs9__namespace = /*#__PURE__*/_interopNamespace(fs9);
|
|
38
38
|
var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
|
|
39
39
|
var fs10__namespace = /*#__PURE__*/_interopNamespace(fs10);
|
|
40
40
|
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
@@ -129,7 +129,10 @@ async function executeWorkflow(ctx) {
|
|
|
129
129
|
if (activeSession.phase === "context") {
|
|
130
130
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/9: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
|
|
131
131
|
lines.push("");
|
|
132
|
+
const loader = new LoadingIndicator2("\u8BFB\u53D6\u9879\u76EE\u914D\u7F6E");
|
|
133
|
+
loader.start();
|
|
132
134
|
activeSession.context = await readProjectContext(ctx.options.workingDirectory);
|
|
135
|
+
loader.stop();
|
|
133
136
|
lines.push(chalk9__default.default.gray(` \u9879\u76EE: ${activeSession.context.name}`));
|
|
134
137
|
lines.push(chalk9__default.default.gray(` \u7C7B\u578B: ${activeSession.context.type}`));
|
|
135
138
|
lines.push(chalk9__default.default.gray(` \u6846\u67B6: ${activeSession.context.framework || "\u672A\u8BC6\u522B"}`));
|
|
@@ -219,7 +222,7 @@ ${resource.analysis}`;
|
|
|
219
222
|
lines.push("");
|
|
220
223
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
221
224
|
lines.push("");
|
|
222
|
-
const loader = new
|
|
225
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u751F\u6210 BDD \u573A\u666F");
|
|
223
226
|
loader.start();
|
|
224
227
|
try {
|
|
225
228
|
activeSession.bddScenarios = await generateBDDScenariosWithAI(
|
|
@@ -254,7 +257,7 @@ ${resource.analysis}`;
|
|
|
254
257
|
lines.push("");
|
|
255
258
|
lines.push(chalk9__default.default.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
256
259
|
lines.push("");
|
|
257
|
-
const loader = new
|
|
260
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
258
261
|
loader.start();
|
|
259
262
|
try {
|
|
260
263
|
activeSession.specItems = await generateSpecItemsWithAI(
|
|
@@ -423,31 +426,85 @@ async function handleWorkflowInput(input, ctx) {
|
|
|
423
426
|
activeSession.phase = "analysis";
|
|
424
427
|
return executeWorkflow(ctx);
|
|
425
428
|
}
|
|
426
|
-
if (activeSession.phase === "spec") {
|
|
429
|
+
if (activeSession.phase === "spec" || activeSession.specFeedbackState === "waiting_confirm") {
|
|
427
430
|
if (trimmed === "y" || trimmed === "yes" || trimmed === "\u786E\u8BA4") {
|
|
431
|
+
activeSession.specFeedbackState = void 0;
|
|
428
432
|
activeSession.phase = "tdd";
|
|
429
433
|
return executeWorkflow(ctx);
|
|
430
434
|
}
|
|
431
|
-
if (trimmed === "n" || trimmed === "no" || trimmed === "\u91CD\u65B0") {
|
|
432
|
-
activeSession.
|
|
433
|
-
|
|
434
|
-
activeSession.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
435
|
+
if (trimmed === "n" || trimmed === "no" || trimmed === "\u4E0D\u6EE1\u610F" || trimmed === "\u91CD\u65B0") {
|
|
436
|
+
activeSession.specFeedbackState = "collecting_feedback";
|
|
437
|
+
if (!activeSession.specFeedbacks) {
|
|
438
|
+
activeSession.specFeedbacks = [];
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
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')
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (activeSession.specFeedbackState === "collecting_feedback") {
|
|
446
|
+
if (trimmed === "" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
|
|
447
|
+
if (!activeSession.specFeedbacks || activeSession.specFeedbacks.length === 0) {
|
|
448
|
+
return {
|
|
449
|
+
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')
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
activeSession.specFeedbackState = "feedback_received";
|
|
453
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210\u89C4\u683C");
|
|
454
|
+
loader.start();
|
|
455
|
+
try {
|
|
456
|
+
activeSession.specItems = await generateSpecItemsWithFeedback(
|
|
457
|
+
activeSession.refinedRequirement,
|
|
458
|
+
activeSession.context,
|
|
459
|
+
activeSession.bddScenarios,
|
|
460
|
+
activeSession.clarificationQuestions,
|
|
461
|
+
activeSession.referenceResources,
|
|
462
|
+
activeSession.specFeedbacks,
|
|
463
|
+
ctx
|
|
464
|
+
);
|
|
465
|
+
loader.stop(chalk9__default.default.green(" \u2713 \u89C4\u683C\u5DF2\u6839\u636E\u53CD\u9988\u91CD\u65B0\u751F\u6210"));
|
|
466
|
+
} catch (error) {
|
|
467
|
+
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u65B9\u6CD5\u91CD\u65B0\u751F\u6210"));
|
|
468
|
+
activeSession.specItems = generateSpecItems(
|
|
469
|
+
activeSession.refinedRequirement,
|
|
470
|
+
activeSession.context,
|
|
471
|
+
activeSession.bddScenarios,
|
|
472
|
+
activeSession.clarificationQuestions,
|
|
473
|
+
activeSession.referenceResources
|
|
474
|
+
);
|
|
475
|
+
}
|
|
445
476
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
477
|
+
activeSession.specFeedbackState = "waiting_confirm";
|
|
478
|
+
const lines = [];
|
|
479
|
+
lines.push(chalk9__default.default.cyan("\n\u2501\u2501\u2501 \u66F4\u65B0\u540E\u7684\u4EFB\u52A1\u6982\u89C8 \u2501\u2501\u2501"));
|
|
480
|
+
for (const item of activeSession.specItems.slice(0, 8)) {
|
|
481
|
+
const icon = item.priority === "high" ? "\u{1F534}" : item.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
482
|
+
lines.push(chalk9__default.default.gray(` ${icon} [${item.id}] ${item.title}`));
|
|
483
|
+
}
|
|
484
|
+
if (activeSession.specItems.length > 8) {
|
|
485
|
+
lines.push(chalk9__default.default.gray(` ... \u5171 ${activeSession.specItems.length} \u4E2A\u4EFB\u52A1`));
|
|
486
|
+
}
|
|
446
487
|
return {
|
|
447
|
-
output:
|
|
448
|
-
|
|
488
|
+
output: lines.join("\n") + chalk9__default.default.green(`
|
|
489
|
+
|
|
490
|
+
\u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u66F4\u65B0`) + chalk9__default.default.gray(`
|
|
491
|
+
\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")
|
|
449
492
|
};
|
|
450
493
|
}
|
|
494
|
+
if (trimmed === "cancel" || trimmed === "\u53D6\u6D88") {
|
|
495
|
+
activeSession.specFeedbackState = "waiting_confirm";
|
|
496
|
+
activeSession.specFeedbacks = [];
|
|
497
|
+
return {
|
|
498
|
+
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")
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (!activeSession.specFeedbacks) {
|
|
502
|
+
activeSession.specFeedbacks = [];
|
|
503
|
+
}
|
|
504
|
+
activeSession.specFeedbacks.push(trimmed);
|
|
505
|
+
return {
|
|
506
|
+
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')
|
|
507
|
+
};
|
|
451
508
|
}
|
|
452
509
|
if (activeSession.phase === "develop") {
|
|
453
510
|
if (trimmed === "continue" || trimmed === "\u7EE7\u7EED" || trimmed === "done" || trimmed === "\u5B8C\u6210") {
|
|
@@ -606,28 +663,17 @@ async function executeDevelopment(ctx, session) {
|
|
|
606
663
|
if (item.title.includes("\u6D4B\u8BD5") || item.title.includes("test")) {
|
|
607
664
|
continue;
|
|
608
665
|
}
|
|
609
|
-
const loader = new
|
|
666
|
+
const loader = new LoadingIndicator2(`${prefix} \u751F\u6210: ${item.title.slice(0, 20)}...`);
|
|
610
667
|
loader.start();
|
|
611
668
|
try {
|
|
612
669
|
const taskPrompt = buildTaskPrompt(session, item, i);
|
|
670
|
+
const structureInfo = session.context?.projectStructure;
|
|
671
|
+
const structureGuide = buildStructureGuide(structureInfo);
|
|
672
|
+
const systemPrompt = buildCodeGenerationSystemPrompt(session, structureGuide);
|
|
613
673
|
const messages = [
|
|
614
674
|
{
|
|
615
675
|
role: "system",
|
|
616
|
-
content:
|
|
617
|
-
|
|
618
|
-
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
619
|
-
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
|
|
620
|
-
2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
|
|
621
|
-
3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
622
|
-
4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
623
|
-
|
|
624
|
-
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
625
|
-
- \u540D\u79F0: ${session.context?.name}
|
|
626
|
-
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
627
|
-
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
628
|
-
|
|
629
|
-
${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
|
|
630
|
-
${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
676
|
+
content: systemPrompt
|
|
631
677
|
},
|
|
632
678
|
{
|
|
633
679
|
role: "user",
|
|
@@ -639,25 +685,25 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
639
685
|
maxTokens: 4e3,
|
|
640
686
|
// 单个任务减少 token
|
|
641
687
|
agent: "frontend-dev",
|
|
642
|
-
timeout:
|
|
643
|
-
//
|
|
688
|
+
timeout: 3e5
|
|
689
|
+
// 5分钟超时,确保复杂代码有足够时间
|
|
644
690
|
});
|
|
645
691
|
const codeBlocks = parseCodeBlocks(response.content);
|
|
646
692
|
if (codeBlocks.length > 0) {
|
|
647
693
|
for (const block of codeBlocks) {
|
|
648
694
|
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
649
695
|
const dir = path4__namespace.dirname(filePath);
|
|
650
|
-
await
|
|
651
|
-
await
|
|
696
|
+
await fs9__namespace.mkdir(dir, { recursive: true });
|
|
697
|
+
await fs9__namespace.writeFile(filePath, block.code, "utf-8");
|
|
652
698
|
files.push(block.filename);
|
|
653
699
|
}
|
|
654
700
|
loader.stop(chalk9__default.default.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
|
|
655
701
|
} else {
|
|
656
702
|
const implDir = path4__namespace.join(workingDir, "src");
|
|
657
|
-
await
|
|
703
|
+
await fs9__namespace.mkdir(implDir, { recursive: true });
|
|
658
704
|
const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
|
|
659
705
|
const filePath = path4__namespace.join(implDir, fileName);
|
|
660
|
-
await
|
|
706
|
+
await fs9__namespace.writeFile(filePath, `// TODO: ${item.title}
|
|
661
707
|
// ${item.description}
|
|
662
708
|
`, "utf-8");
|
|
663
709
|
files.push(`src/${fileName}`);
|
|
@@ -680,6 +726,91 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
680
726
|
};
|
|
681
727
|
}
|
|
682
728
|
}
|
|
729
|
+
function buildStructureGuide(structure) {
|
|
730
|
+
if (!structure) {
|
|
731
|
+
return `## \u9879\u76EE\u7ED3\u6784
|
|
732
|
+
- \u7EC4\u4EF6\u653E\u5728 src/components/
|
|
733
|
+
- \u9875\u9762\u653E\u5728 src/pages/
|
|
734
|
+
- \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/`;
|
|
735
|
+
}
|
|
736
|
+
const lines = ["## \u9879\u76EE\u7ED3\u6784\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09"];
|
|
737
|
+
if (structure.hasSrc) {
|
|
738
|
+
lines.push(`- \u6E90\u7801\u76EE\u5F55: ${structure.srcDir}/`);
|
|
739
|
+
}
|
|
740
|
+
if (structure.hasPages) {
|
|
741
|
+
lines.push(`- \u9875\u9762\u76EE\u5F55: ${structure.pagesDir}/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
|
|
742
|
+
} else {
|
|
743
|
+
lines.push(`- \u9875\u9762\u76EE\u5F55: src/pages/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
|
|
744
|
+
}
|
|
745
|
+
if (structure.hasComponents) {
|
|
746
|
+
lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: ${structure.componentsDir}/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
|
|
747
|
+
} else {
|
|
748
|
+
lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: src/components/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
|
|
749
|
+
}
|
|
750
|
+
if (structure.hasApi) {
|
|
751
|
+
lines.push(`- API \u76EE\u5F55: src/api/ \u6216 src/services/`);
|
|
752
|
+
}
|
|
753
|
+
if (structure.hasHooks) {
|
|
754
|
+
lines.push(`- Hooks \u76EE\u5F55: src/hooks/`);
|
|
755
|
+
}
|
|
756
|
+
if (structure.hasStore) {
|
|
757
|
+
lines.push(`- \u72B6\u6001\u7BA1\u7406\u76EE\u5F55: src/store/`);
|
|
758
|
+
}
|
|
759
|
+
if (structure.hasUtils) {
|
|
760
|
+
lines.push(`- \u5DE5\u5177\u51FD\u6570\u76EE\u5F55: src/utils/`);
|
|
761
|
+
}
|
|
762
|
+
lines.push("");
|
|
763
|
+
lines.push("\u26A0\uFE0F \u6587\u4EF6\u5FC5\u987B\u653E\u5728\u4E0A\u8FF0\u5BF9\u5E94\u76EE\u5F55\u4E2D\uFF0C\u4E0D\u8981\u968F\u610F\u521B\u5EFA\u65B0\u76EE\u5F55");
|
|
764
|
+
return lines.join("\n");
|
|
765
|
+
}
|
|
766
|
+
function buildCodeGenerationSystemPrompt(session, structureGuide) {
|
|
767
|
+
const framework = session.context?.framework || "React";
|
|
768
|
+
const techStack = session.context?.techStack?.join(", ") || "TypeScript";
|
|
769
|
+
const devStandards = session.context?.devStandards || "";
|
|
770
|
+
const standardsText = devStandards.slice(0, 6e3);
|
|
771
|
+
return `\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
|
|
772
|
+
|
|
773
|
+
## \u26A0\uFE0F \u6838\u5FC3\u89C4\u5219\uFF08\u5FC5\u987B\u9075\u5B88\uFF09
|
|
774
|
+
|
|
775
|
+
1. **\u8BED\u8A00**: \u5FC5\u987B\u4F7F\u7528 TypeScript (.tsx/.ts \u6587\u4EF6)
|
|
776
|
+
2. **\u6846\u67B6**: ${framework}
|
|
777
|
+
3. **\u53EA\u751F\u6210\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u4EE3\u7801**\uFF0C\u4E0D\u8981\u751F\u6210\u5176\u4ED6\u4EFB\u52A1\u7684\u4EE3\u7801
|
|
778
|
+
4. **\u6587\u4EF6\u8DEF\u5F84\u5FC5\u987B\u6B63\u786E**\uFF1A\u4E25\u683C\u6309\u7167\u9879\u76EE\u7ED3\u6784\u653E\u7F6E\u6587\u4EF6
|
|
779
|
+
5. **\u5FC5\u987B\u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801**\uFF0C\u4E0D\u8981\u5199 TODO \u6216\u5360\u4F4D\u7B26
|
|
780
|
+
6. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA\u9875\u9762**\uFF0C\u5FC5\u987B\u751F\u6210\u9875\u9762\u7EC4\u4EF6
|
|
781
|
+
7. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA UI**\uFF0C\u5FC5\u987B\u751F\u6210\u5BF9\u5E94\u7684\u7EC4\u4EF6\u548C\u6837\u5F0F
|
|
782
|
+
|
|
783
|
+
${structureGuide}
|
|
784
|
+
|
|
785
|
+
## \u9879\u76EE\u4FE1\u606F
|
|
786
|
+
|
|
787
|
+
- \u540D\u79F0: ${session.context?.name || "\u672A\u547D\u540D\u9879\u76EE"}
|
|
788
|
+
- \u6846\u67B6: ${framework}
|
|
789
|
+
- \u6280\u672F\u6808: ${techStack}
|
|
790
|
+
|
|
791
|
+
## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
|
|
792
|
+
|
|
793
|
+
${standardsText || `### \u9ED8\u8BA4\u89C4\u8303
|
|
794
|
+
- \u4F7F\u7528\u51FD\u6570\u5F0F\u7EC4\u4EF6
|
|
795
|
+
- \u4F7F\u7528 TypeScript \u7C7B\u578B\u5B9A\u4E49
|
|
796
|
+
- \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65
|
|
797
|
+
- \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase
|
|
798
|
+
- \u5BFC\u51FA\u4F7F\u7528 export default \u6216 export const`}
|
|
799
|
+
|
|
800
|
+
## \u8F93\u51FA\u683C\u5F0F
|
|
801
|
+
|
|
802
|
+
\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u5305\u88F9\uFF0C\u4F8B\u5982\uFF1A
|
|
803
|
+
|
|
804
|
+
\`\`\`src/pages/HomePage.tsx
|
|
805
|
+
// \u4EE3\u7801\u5185\u5BB9
|
|
806
|
+
\`\`\`
|
|
807
|
+
|
|
808
|
+
\`\`\`src/components/Button/Button.tsx
|
|
809
|
+
// \u4EE3\u7801\u5185\u5BB9
|
|
810
|
+
\`\`\`
|
|
811
|
+
|
|
812
|
+
\u73B0\u5728\u8BF7\u6839\u636E\u4EFB\u52A1\u8981\u6C42\u751F\u6210\u4EE3\u7801\u3002`;
|
|
813
|
+
}
|
|
683
814
|
function buildTaskPrompt(session, item, index) {
|
|
684
815
|
const lines = [];
|
|
685
816
|
lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
|
|
@@ -728,11 +859,13 @@ async function executeReview(ctx, session) {
|
|
|
728
859
|
const workingDir = ctx.options.workingDirectory;
|
|
729
860
|
const issues = [];
|
|
730
861
|
const suggestions = [];
|
|
862
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u5BA1\u6838\u4EE3\u7801");
|
|
863
|
+
loader.start();
|
|
731
864
|
try {
|
|
732
865
|
const codeContents = [];
|
|
733
866
|
for (const file of session.implFiles) {
|
|
734
867
|
try {
|
|
735
|
-
const content = await
|
|
868
|
+
const content = await fs9__namespace.readFile(path4__namespace.join(workingDir, file), "utf-8");
|
|
736
869
|
codeContents.push(`// ${file}
|
|
737
870
|
${content}`);
|
|
738
871
|
} catch {
|
|
@@ -741,7 +874,7 @@ ${content}`);
|
|
|
741
874
|
const testContents = [];
|
|
742
875
|
for (const file of session.testFiles) {
|
|
743
876
|
try {
|
|
744
|
-
const content = await
|
|
877
|
+
const content = await fs9__namespace.readFile(path4__namespace.join(workingDir, file), "utf-8");
|
|
745
878
|
testContents.push(`// ${file}
|
|
746
879
|
${content}`);
|
|
747
880
|
} catch {
|
|
@@ -790,7 +923,9 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
|
|
|
790
923
|
const response = await ctx.modelService.sendMessage(messages, {
|
|
791
924
|
temperature: 0.2,
|
|
792
925
|
maxTokens: 2e3,
|
|
793
|
-
agent: "code-reviewer"
|
|
926
|
+
agent: "code-reviewer",
|
|
927
|
+
timeout: 18e4
|
|
928
|
+
// 3分钟超时
|
|
794
929
|
});
|
|
795
930
|
const result = response.content;
|
|
796
931
|
const passed = result.includes("\u5BA1\u6838\u901A\u8FC7") || result.includes("\u901A\u8FC7") || !result.includes("\u4E0D\u901A\u8FC7");
|
|
@@ -812,8 +947,10 @@ ${testContents.join("\n\n") || "\uFF08\u65E0\u6D4B\u8BD5\u6587\u4EF6\uFF09"}
|
|
|
812
947
|
const lines = result.split("\n").filter((l) => l.includes("\u5EFA\u8BAE") || l.includes("\u6539\u8FDB") || l.includes("\u4F18\u5316"));
|
|
813
948
|
suggestions.push(...lines.map((l) => l.replace(/^[-*]\s*/, "").trim()).filter((l) => l));
|
|
814
949
|
}
|
|
950
|
+
loader.stop(passed ? chalk9__default.default.green(" \u2713 \u5BA1\u6838\u901A\u8FC7") : chalk9__default.default.yellow(" \u26A0 \u53D1\u73B0\u95EE\u9898"));
|
|
815
951
|
return { passed, issues, suggestions };
|
|
816
952
|
} catch (error) {
|
|
953
|
+
loader.stop(chalk9__default.default.red(" \u2717 \u5BA1\u6838\u51FA\u9519"));
|
|
817
954
|
suggestions.push(`\u5BA1\u6838\u8FC7\u7A0B\u51FA\u9519: ${error.message}`);
|
|
818
955
|
return { passed: true, issues, suggestions };
|
|
819
956
|
}
|
|
@@ -831,9 +968,9 @@ async function readProjectContext(workingDir) {
|
|
|
831
968
|
};
|
|
832
969
|
const agentsPath = path4__namespace.join(workingDir, "AGENTS.md");
|
|
833
970
|
try {
|
|
834
|
-
const stats = await
|
|
971
|
+
const stats = await fs9__namespace.stat(agentsPath);
|
|
835
972
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
836
|
-
context.agentsMd = await
|
|
973
|
+
context.agentsMd = await fs9__namespace.readFile(agentsPath, "utf-8");
|
|
837
974
|
const nameMatch = context.agentsMd.match(/\|\s*项目名称\s*\|\s*([^\s|]+)/);
|
|
838
975
|
if (nameMatch) context.name = nameMatch[1];
|
|
839
976
|
const typeMatch = context.agentsMd.match(/\|\s*项目类型\s*\|\s*([^\s|]+)/);
|
|
@@ -847,9 +984,9 @@ async function readProjectContext(workingDir) {
|
|
|
847
984
|
}
|
|
848
985
|
const configPath = path4__namespace.join(workingDir, "openspec", "config.yaml");
|
|
849
986
|
try {
|
|
850
|
-
const stats = await
|
|
987
|
+
const stats = await fs9__namespace.stat(configPath);
|
|
851
988
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
852
|
-
context.configYaml = await
|
|
989
|
+
context.configYaml = await fs9__namespace.readFile(configPath, "utf-8");
|
|
853
990
|
const nameMatch = context.configYaml.match(/name:\s*(.+)/);
|
|
854
991
|
if (nameMatch) context.name = nameMatch[1].trim();
|
|
855
992
|
const typeMatch = context.configYaml.match(/type:\s*(.+)/);
|
|
@@ -870,14 +1007,173 @@ async function readProjectContext(workingDir) {
|
|
|
870
1007
|
}
|
|
871
1008
|
const devStandardsPath = path4__namespace.join(workingDir, ".sf-cli", "norms", "devstanded.md");
|
|
872
1009
|
try {
|
|
873
|
-
const stats = await
|
|
1010
|
+
const stats = await fs9__namespace.stat(devStandardsPath);
|
|
874
1011
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
875
|
-
context.devStandards = await
|
|
1012
|
+
context.devStandards = await fs9__namespace.readFile(devStandardsPath, "utf-8");
|
|
876
1013
|
}
|
|
877
1014
|
} catch {
|
|
878
1015
|
}
|
|
1016
|
+
if (!context.framework) {
|
|
1017
|
+
const detectedFramework = await detectFramework2(workingDir);
|
|
1018
|
+
if (detectedFramework) {
|
|
1019
|
+
context.framework = detectedFramework;
|
|
1020
|
+
context.techStack = [detectedFramework, ...context.techStack.filter((t) => t !== detectedFramework)];
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (!context.devStandards) {
|
|
1024
|
+
context.devStandards = await analyzeProjectForStandards(workingDir, context);
|
|
1025
|
+
}
|
|
1026
|
+
context.projectStructure = await analyzeProjectStructure(workingDir);
|
|
879
1027
|
return context;
|
|
880
1028
|
}
|
|
1029
|
+
async function detectFramework2(workingDir) {
|
|
1030
|
+
try {
|
|
1031
|
+
const pkgPath = path4__namespace.join(workingDir, "package.json");
|
|
1032
|
+
const pkgContent = await fs9__namespace.readFile(pkgPath, "utf-8");
|
|
1033
|
+
const pkg = JSON.parse(pkgContent);
|
|
1034
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1035
|
+
if (deps["react"] || deps["next"]) return "React";
|
|
1036
|
+
if (deps["vue"] || deps["nuxt"]) return "Vue";
|
|
1037
|
+
if (deps["angular"] || deps["@angular/core"]) return "Angular";
|
|
1038
|
+
if (deps["svelte"]) return "Svelte";
|
|
1039
|
+
if (deps["solid-js"]) return "Solid";
|
|
1040
|
+
if (deps["vite"] || deps["webpack"]) return "JavaScript";
|
|
1041
|
+
if (deps["typescript"]) return "TypeScript";
|
|
1042
|
+
return null;
|
|
1043
|
+
} catch {
|
|
1044
|
+
return null;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
async function analyzeProjectForStandards(workingDir, context) {
|
|
1048
|
+
const standards = [];
|
|
1049
|
+
standards.push(`# \u9879\u76EE\u5F00\u53D1\u89C4\u8303\uFF08\u81EA\u52A8\u751F\u6210\uFF09
|
|
1050
|
+
> \u9879\u76EE\u540D\u79F0: ${context.name}
|
|
1051
|
+
> \u6846\u67B6: ${context.framework || "\u672A\u68C0\u6D4B\u5230"}
|
|
1052
|
+
> \u6280\u672F\u6808: ${context.techStack.join(", ") || "\u672A\u68C0\u6D4B\u5230"}
|
|
1053
|
+
`);
|
|
1054
|
+
try {
|
|
1055
|
+
const tsConfigPath = path4__namespace.join(workingDir, "tsconfig.json");
|
|
1056
|
+
await fs9__namespace.access(tsConfigPath);
|
|
1057
|
+
standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 TypeScript");
|
|
1058
|
+
} catch {
|
|
1059
|
+
standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 JavaScript");
|
|
1060
|
+
}
|
|
1061
|
+
try {
|
|
1062
|
+
const srcDir = path4__namespace.join(workingDir, "src");
|
|
1063
|
+
const files = await listFilesDeep(srcDir);
|
|
1064
|
+
const hasCss = files.some((f) => f.endsWith(".css"));
|
|
1065
|
+
const hasScss = files.some((f) => f.endsWith(".scss") || f.endsWith(".sass"));
|
|
1066
|
+
const hasLess = files.some((f) => f.endsWith(".less"));
|
|
1067
|
+
const hasStyled = files.some((f) => f.includes(".styled.") || f.includes("styled-components"));
|
|
1068
|
+
if (hasScss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 SCSS/Sass");
|
|
1069
|
+
else if (hasLess) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 Less");
|
|
1070
|
+
else if (hasStyled) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 styled-components");
|
|
1071
|
+
else if (hasCss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 CSS");
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
try {
|
|
1075
|
+
const srcDir = path4__namespace.join(workingDir, "src");
|
|
1076
|
+
const entries = await fs9__namespace.readdir(srcDir, { withFileTypes: true });
|
|
1077
|
+
const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1078
|
+
if (dirs.includes("components")) standards.push("\n## \u76EE\u5F55\u7ED3\u6784\n- \u7EC4\u4EF6\u653E\u5728 src/components/");
|
|
1079
|
+
if (dirs.includes("pages") || dirs.includes("views")) standards.push("- \u9875\u9762\u653E\u5728 src/pages/ \u6216 src/views/");
|
|
1080
|
+
if (dirs.includes("hooks")) standards.push("- Hooks \u653E\u5728 src/hooks/");
|
|
1081
|
+
if (dirs.includes("utils")) standards.push("- \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/");
|
|
1082
|
+
if (dirs.includes("api") || dirs.includes("services")) standards.push("- API \u8C03\u7528\u653E\u5728 src/api/ \u6216 src/services/");
|
|
1083
|
+
if (dirs.includes("store") || dirs.includes("stores")) standards.push("- \u72B6\u6001\u7BA1\u7406\u653E\u5728 src/store/");
|
|
1084
|
+
} catch {
|
|
1085
|
+
}
|
|
1086
|
+
standards.push("\n## \u4EE3\u7801\u89C4\u8303");
|
|
1087
|
+
standards.push("- \u4F7F\u7528 ES6+ \u8BED\u6CD5");
|
|
1088
|
+
standards.push("- \u7EC4\u4EF6\u4F7F\u7528\u51FD\u6570\u5F0F\u5199\u6CD5");
|
|
1089
|
+
standards.push("- \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65");
|
|
1090
|
+
standards.push("- \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase");
|
|
1091
|
+
standards.push("- \u5E38\u91CF\u4F7F\u7528 UPPER_SNAKE_CASE");
|
|
1092
|
+
return standards.join("\n");
|
|
1093
|
+
}
|
|
1094
|
+
async function listFilesDeep(dir, maxDepth = 3) {
|
|
1095
|
+
const files = [];
|
|
1096
|
+
async function scan(currentDir, depth) {
|
|
1097
|
+
if (depth > maxDepth) return;
|
|
1098
|
+
try {
|
|
1099
|
+
const entries = await fs9__namespace.readdir(currentDir, { withFileTypes: true });
|
|
1100
|
+
for (const entry of entries) {
|
|
1101
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
1102
|
+
const fullPath = path4__namespace.join(currentDir, entry.name);
|
|
1103
|
+
if (entry.isDirectory()) {
|
|
1104
|
+
await scan(fullPath, depth + 1);
|
|
1105
|
+
} else {
|
|
1106
|
+
files.push(fullPath);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
} catch {
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
await scan(dir, 0);
|
|
1113
|
+
return files;
|
|
1114
|
+
}
|
|
1115
|
+
async function analyzeProjectStructure(workingDir) {
|
|
1116
|
+
const structure = {
|
|
1117
|
+
hasSrc: false,
|
|
1118
|
+
hasPages: false,
|
|
1119
|
+
hasComponents: false,
|
|
1120
|
+
hasApi: false,
|
|
1121
|
+
hasHooks: false,
|
|
1122
|
+
hasStore: false,
|
|
1123
|
+
hasUtils: false,
|
|
1124
|
+
srcDir: "src",
|
|
1125
|
+
pagesDir: "",
|
|
1126
|
+
componentsDir: ""
|
|
1127
|
+
};
|
|
1128
|
+
try {
|
|
1129
|
+
const srcDir = path4__namespace.join(workingDir, "src");
|
|
1130
|
+
try {
|
|
1131
|
+
const srcStat = await fs9__namespace.stat(srcDir);
|
|
1132
|
+
if (srcStat.isDirectory()) {
|
|
1133
|
+
structure.hasSrc = true;
|
|
1134
|
+
structure.srcDir = "src";
|
|
1135
|
+
const srcEntries = await fs9__namespace.readdir(srcDir, { withFileTypes: true });
|
|
1136
|
+
const srcDirs = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1137
|
+
if (srcDirs.includes("pages")) {
|
|
1138
|
+
structure.hasPages = true;
|
|
1139
|
+
structure.pagesDir = "src/pages";
|
|
1140
|
+
} else if (srcDirs.includes("views")) {
|
|
1141
|
+
structure.hasPages = true;
|
|
1142
|
+
structure.pagesDir = "src/views";
|
|
1143
|
+
}
|
|
1144
|
+
if (srcDirs.includes("components")) {
|
|
1145
|
+
structure.hasComponents = true;
|
|
1146
|
+
structure.componentsDir = "src/components";
|
|
1147
|
+
}
|
|
1148
|
+
if (srcDirs.includes("api") || srcDirs.includes("services")) {
|
|
1149
|
+
structure.hasApi = true;
|
|
1150
|
+
}
|
|
1151
|
+
if (srcDirs.includes("hooks")) {
|
|
1152
|
+
structure.hasHooks = true;
|
|
1153
|
+
}
|
|
1154
|
+
if (srcDirs.includes("store") || srcDirs.includes("stores")) {
|
|
1155
|
+
structure.hasStore = true;
|
|
1156
|
+
}
|
|
1157
|
+
if (srcDirs.includes("utils")) {
|
|
1158
|
+
structure.hasUtils = true;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
} catch {
|
|
1162
|
+
const rootEntries = await fs9__namespace.readdir(workingDir, { withFileTypes: true });
|
|
1163
|
+
const rootDirs = rootEntries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1164
|
+
if (rootDirs.includes("pages")) {
|
|
1165
|
+
structure.hasPages = true;
|
|
1166
|
+
structure.pagesDir = "pages";
|
|
1167
|
+
}
|
|
1168
|
+
if (rootDirs.includes("components")) {
|
|
1169
|
+
structure.hasComponents = true;
|
|
1170
|
+
structure.componentsDir = "components";
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
} catch {
|
|
1174
|
+
}
|
|
1175
|
+
return structure;
|
|
1176
|
+
}
|
|
881
1177
|
function analyzeComplexity(requirement, context) {
|
|
882
1178
|
let score = 3;
|
|
883
1179
|
if (requirement.length > 100) score += 1;
|
|
@@ -1019,7 +1315,8 @@ ${r.analysis}`).join("\n\n") : "\u65E0"}
|
|
|
1019
1315
|
], {
|
|
1020
1316
|
temperature: 0.3,
|
|
1021
1317
|
maxTokens: 4e3,
|
|
1022
|
-
timeout:
|
|
1318
|
+
timeout: 3e5
|
|
1319
|
+
// 5分钟超时
|
|
1023
1320
|
});
|
|
1024
1321
|
try {
|
|
1025
1322
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
@@ -1227,7 +1524,7 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
1227
1524
|
- \u96C6\u6210\u6D4B\u8BD5
|
|
1228
1525
|
|
|
1229
1526
|
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\u3002`;
|
|
1230
|
-
const loader = new
|
|
1527
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u62C6\u5206\u89C4\u683C");
|
|
1231
1528
|
loader.start();
|
|
1232
1529
|
try {
|
|
1233
1530
|
const response = await ctx.modelService.sendMessage([
|
|
@@ -1235,8 +1532,8 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
1235
1532
|
], {
|
|
1236
1533
|
temperature: 0.3,
|
|
1237
1534
|
maxTokens: 4e3,
|
|
1238
|
-
timeout:
|
|
1239
|
-
//
|
|
1535
|
+
timeout: 3e5
|
|
1536
|
+
// 5分钟超时
|
|
1240
1537
|
});
|
|
1241
1538
|
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
1242
1539
|
if (jsonMatch) {
|
|
@@ -1279,12 +1576,96 @@ ${questions.filter((q) => q.answered).map((q) => `- ${q.question}: ${q.answer}`)
|
|
|
1279
1576
|
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1280
1577
|
}
|
|
1281
1578
|
}
|
|
1579
|
+
async function generateSpecItemsWithFeedback(requirement, context, bddScenarios, questions, references, feedbacks, ctx) {
|
|
1580
|
+
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
|
|
1581
|
+
|
|
1582
|
+
## \u9700\u6C42\u63CF\u8FF0
|
|
1583
|
+
${requirement}
|
|
1584
|
+
|
|
1585
|
+
## \u9879\u76EE\u4E0A\u4E0B\u6587
|
|
1586
|
+
- \u6280\u672F\u6808: ${context.techStack?.join(", ") || "TypeScript"}
|
|
1587
|
+
- \u6846\u67B6: ${context.framework || "\u672A\u6307\u5B9A"}
|
|
1588
|
+
${context.devStandards ? `
|
|
1589
|
+
## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
|
|
1590
|
+
${context.devStandards.slice(0, 2e3)}
|
|
1591
|
+
` : ""}
|
|
1592
|
+
|
|
1593
|
+
## \u4E4B\u524D\u7684 BDD \u573A\u666F
|
|
1594
|
+
${bddScenarios.map((s) => `- Feature: ${s.feature}`).join("\n")}
|
|
1595
|
+
|
|
1596
|
+
## \u7528\u6237\u53CD\u9988\uFF08\u5FC5\u987B\u89E3\u51B3\u8FD9\u4E9B\u95EE\u9898\uFF09
|
|
1597
|
+
${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
|
|
1598
|
+
|
|
1599
|
+
## \u8981\u6C42
|
|
1600
|
+
1. **\u5FC5\u987B\u89E3\u51B3\u7528\u6237\u53CD\u9988\u4E2D\u7684\u6240\u6709\u95EE\u9898**
|
|
1601
|
+
2. \u5982\u679C\u7528\u6237\u6307\u51FA\u9057\u6F0F\u7684\u529F\u80FD\u70B9\uFF0C\u8BF7\u8865\u5145\u76F8\u5173\u4EFB\u52A1
|
|
1602
|
+
3. \u5982\u679C\u7528\u6237\u6307\u51FA\u62C6\u5206\u4E0D\u5408\u7406\uFF0C\u8BF7\u91CD\u65B0\u8C03\u6574\u7C92\u5EA6
|
|
1603
|
+
4. \u5982\u679C\u7528\u6237\u9700\u8981\u66F4\u591A\u7EC6\u8282\uFF0C\u8BF7\u62C6\u5206\u5F97\u66F4\u7EC6\u81F4
|
|
1604
|
+
5. \u6BCF\u4E2A\u4EFB\u52A1\u5E94\u8BE5\u5355\u4E00\u804C\u8D23\u30012-4\u5C0F\u65F6\u53EF\u5B8C\u6210
|
|
1605
|
+
|
|
1606
|
+
## \u8F93\u51FA\u683C\u5F0F (JSON)
|
|
1607
|
+
\`\`\`json
|
|
1608
|
+
[
|
|
1609
|
+
{
|
|
1610
|
+
"id": "T001",
|
|
1611
|
+
"title": "\u4EFB\u52A1\u6807\u9898\uFF08\u7B80\u77ED\u660E\u786E\uFF09",
|
|
1612
|
+
"description": "\u8BE6\u7EC6\u63CF\u8FF0",
|
|
1613
|
+
"priority": "high",
|
|
1614
|
+
"acceptanceCriteria": ["\u9A8C\u6536\u6807\u51C61", "\u9A8C\u6536\u6807\u51C62"]
|
|
1615
|
+
}
|
|
1616
|
+
]
|
|
1617
|
+
\`\`\`
|
|
1618
|
+
|
|
1619
|
+
\u8BF7\u76F4\u63A5\u8F93\u51FA JSON \u6570\u7EC4\uFF0C\u786E\u4FDD\u89E3\u51B3\u4E86\u7528\u6237\u7684\u6240\u6709\u53CD\u9988\u3002`;
|
|
1620
|
+
try {
|
|
1621
|
+
const response = await ctx.modelService.sendMessage([
|
|
1622
|
+
{ role: "user", content: prompt2 }
|
|
1623
|
+
], {
|
|
1624
|
+
temperature: 0.3,
|
|
1625
|
+
maxTokens: 4e3,
|
|
1626
|
+
timeout: 3e5
|
|
1627
|
+
// 5分钟超时
|
|
1628
|
+
});
|
|
1629
|
+
const jsonMatch = response.content.match(/```json\s*([\s\S]*?)```/);
|
|
1630
|
+
if (jsonMatch) {
|
|
1631
|
+
try {
|
|
1632
|
+
const parsed = JSON.parse(jsonMatch[1].trim());
|
|
1633
|
+
return parsed.map((item, index) => ({
|
|
1634
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
1635
|
+
title: item.title,
|
|
1636
|
+
description: item.description,
|
|
1637
|
+
priority: item.priority || "medium",
|
|
1638
|
+
files: [],
|
|
1639
|
+
tests: item.acceptanceCriteria || []
|
|
1640
|
+
}));
|
|
1641
|
+
} catch {
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
try {
|
|
1645
|
+
const parsed = JSON.parse(response.content);
|
|
1646
|
+
if (Array.isArray(parsed)) {
|
|
1647
|
+
return parsed.map((item, index) => ({
|
|
1648
|
+
id: item.id || `T${String(index + 1).padStart(3, "0")}`,
|
|
1649
|
+
title: item.title,
|
|
1650
|
+
description: item.description,
|
|
1651
|
+
priority: item.priority || "medium",
|
|
1652
|
+
files: [],
|
|
1653
|
+
tests: item.acceptanceCriteria || []
|
|
1654
|
+
}));
|
|
1655
|
+
}
|
|
1656
|
+
} catch {
|
|
1657
|
+
}
|
|
1658
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1659
|
+
} catch {
|
|
1660
|
+
return generateSpecItems(requirement, context, bddScenarios, questions, references);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1282
1663
|
async function saveSpecFile(workingDir, session) {
|
|
1283
1664
|
const specDir = path4__namespace.join(workingDir, "openspec", "changes");
|
|
1284
|
-
await
|
|
1665
|
+
await fs9__namespace.mkdir(specDir, { recursive: true });
|
|
1285
1666
|
const specPath = path4__namespace.join(specDir, `${session.id}-spec.md`);
|
|
1286
1667
|
const content = formatSpecFile(session);
|
|
1287
|
-
await
|
|
1668
|
+
await fs9__namespace.writeFile(specPath, content, "utf-8");
|
|
1288
1669
|
return specPath;
|
|
1289
1670
|
}
|
|
1290
1671
|
function formatSpecFile(session) {
|
|
@@ -1345,6 +1726,16 @@ function formatSpecFile(session) {
|
|
|
1345
1726
|
lines.push("");
|
|
1346
1727
|
}
|
|
1347
1728
|
}
|
|
1729
|
+
if (session.specFeedbacks && session.specFeedbacks.length > 0) {
|
|
1730
|
+
lines.push("## \u89C4\u683C\u8FED\u4EE3\u53CD\u9988");
|
|
1731
|
+
lines.push("");
|
|
1732
|
+
for (let i = 0; i < session.specFeedbacks.length; i++) {
|
|
1733
|
+
lines.push(`${i + 1}. ${session.specFeedbacks[i]}`);
|
|
1734
|
+
}
|
|
1735
|
+
lines.push("");
|
|
1736
|
+
lines.push("---");
|
|
1737
|
+
lines.push("");
|
|
1738
|
+
}
|
|
1348
1739
|
lines.push("## \u4EFB\u52A1\u5217\u8868");
|
|
1349
1740
|
lines.push("");
|
|
1350
1741
|
for (const item of session.specItems) {
|
|
@@ -1359,22 +1750,22 @@ function formatSpecFile(session) {
|
|
|
1359
1750
|
}
|
|
1360
1751
|
async function generateTests(workingDir, session, ctx) {
|
|
1361
1752
|
const testDir = path4__namespace.join(workingDir, "tests");
|
|
1362
|
-
await
|
|
1753
|
+
await fs9__namespace.mkdir(testDir, { recursive: true });
|
|
1363
1754
|
const testFiles = [];
|
|
1364
1755
|
if (ctx?.modelService) {
|
|
1365
1756
|
for (const scenario of session.bddScenarios) {
|
|
1366
1757
|
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1367
1758
|
const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
|
|
1368
|
-
const loader = new
|
|
1759
|
+
const loader = new LoadingIndicator2(`\u751F\u6210\u6D4B\u8BD5: ${scenario.feature.slice(0, 20)}...`);
|
|
1369
1760
|
loader.start();
|
|
1370
1761
|
try {
|
|
1371
1762
|
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
1372
|
-
await
|
|
1763
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1373
1764
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1374
1765
|
loader.stop(chalk9__default.default.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
|
|
1375
1766
|
} catch {
|
|
1376
1767
|
const content = generateTestFile(scenario, session);
|
|
1377
|
-
await
|
|
1768
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1378
1769
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1379
1770
|
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
|
|
1380
1771
|
}
|
|
@@ -1384,7 +1775,7 @@ async function generateTests(workingDir, session, ctx) {
|
|
|
1384
1775
|
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1385
1776
|
const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
|
|
1386
1777
|
const content = generateTestFile(scenario, session);
|
|
1387
|
-
await
|
|
1778
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1388
1779
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1389
1780
|
}
|
|
1390
1781
|
}
|
|
@@ -1420,7 +1811,9 @@ ${scenario.scenarios.map((s) => `
|
|
|
1420
1811
|
{ role: "user", content: prompt2 }
|
|
1421
1812
|
], {
|
|
1422
1813
|
temperature: 0.3,
|
|
1423
|
-
maxTokens: 4e3
|
|
1814
|
+
maxTokens: 4e3,
|
|
1815
|
+
timeout: 18e4
|
|
1816
|
+
// 3分钟超时
|
|
1424
1817
|
});
|
|
1425
1818
|
const codeMatch = response.content.match(/```(?:typescript|ts|javascript|js)?\n([\s\S]*?)```/);
|
|
1426
1819
|
if (codeMatch) {
|
|
@@ -1476,7 +1869,7 @@ function generateTestFile(scenario, session) {
|
|
|
1476
1869
|
async function archiveWorkflow(workingDir) {
|
|
1477
1870
|
if (!activeSession) return;
|
|
1478
1871
|
const archiveDir = path4__namespace.join(workingDir, "openspec", "spec");
|
|
1479
|
-
await
|
|
1872
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
1480
1873
|
const archivePath = path4__namespace.join(archiveDir, `${activeSession.id}.md`);
|
|
1481
1874
|
const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
|
|
1482
1875
|
|
|
@@ -1503,7 +1896,7 @@ ${activeSession.refinedRequirement}
|
|
|
1503
1896
|
|
|
1504
1897
|
${activeSession.testFiles.map((f) => `- ${f}`).join("\n") || "\u65E0"}
|
|
1505
1898
|
`;
|
|
1506
|
-
await
|
|
1899
|
+
await fs9__namespace.writeFile(archivePath, content, "utf-8");
|
|
1507
1900
|
}
|
|
1508
1901
|
function generateSessionId() {
|
|
1509
1902
|
const timestamp = Date.now().toString(36);
|
|
@@ -1519,7 +1912,10 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
|
|
|
1519
1912
|
const type = detectResourceType(url);
|
|
1520
1913
|
let content = "";
|
|
1521
1914
|
let analysis = "";
|
|
1915
|
+
const loader = new LoadingIndicator2(`\u83B7\u53D6 ${url.slice(0, 40)}...`);
|
|
1916
|
+
loader.start();
|
|
1522
1917
|
try {
|
|
1918
|
+
loader.update("\u6B63\u5728\u83B7\u53D6\u7F51\u9875\u5185\u5BB9");
|
|
1523
1919
|
const response = await fetch(url, {
|
|
1524
1920
|
headers: {
|
|
1525
1921
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
@@ -1530,11 +1926,14 @@ async function fetchAndAnalyzeReference(url, ctx, projectContext) {
|
|
|
1530
1926
|
}
|
|
1531
1927
|
content = await response.text();
|
|
1532
1928
|
if (ctx.modelService.getCurrentModel()) {
|
|
1929
|
+
loader.update("\u6B63\u5728\u5206\u6790\u5185\u5BB9");
|
|
1533
1930
|
analysis = await analyzeReferenceContent(url, content, type, ctx, projectContext);
|
|
1534
1931
|
} else {
|
|
1535
1932
|
analysis = extractBasicInfo(content, type);
|
|
1536
1933
|
}
|
|
1934
|
+
loader.stop();
|
|
1537
1935
|
} catch (error) {
|
|
1936
|
+
loader.stop();
|
|
1538
1937
|
throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u53C2\u8003\u8D44\u6E90: ${error.message}`);
|
|
1539
1938
|
}
|
|
1540
1939
|
return { url, type, content: content.slice(0, 1e4), analysis };
|
|
@@ -1603,14 +2002,16 @@ ${content.slice(0, 8e3)}
|
|
|
1603
2002
|
\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
|
|
1604
2003
|
\u6280\u672F\u5B9E\u73B0\u65B9\u6848\u7531\u9879\u76EE\u89C4\u8303\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u6D89\u53CA\u3002
|
|
1605
2004
|
`;
|
|
1606
|
-
const loader = new
|
|
2005
|
+
const loader = new LoadingIndicator2("AI \u6B63\u5728\u5206\u6790\u53C2\u8003\u8D44\u6E90");
|
|
1607
2006
|
loader.start();
|
|
1608
2007
|
try {
|
|
1609
2008
|
const response = await ctx.modelService.sendMessage([
|
|
1610
2009
|
{ role: "user", content: prompt2 }
|
|
1611
2010
|
], {
|
|
1612
2011
|
temperature: 0.3,
|
|
1613
|
-
maxTokens: 4e3
|
|
2012
|
+
maxTokens: 4e3,
|
|
2013
|
+
timeout: 18e4
|
|
2014
|
+
// 3分钟超时
|
|
1614
2015
|
});
|
|
1615
2016
|
loader.stop(chalk9__default.default.green(" \u2713 \u5206\u6790\u5B8C\u6210"));
|
|
1616
2017
|
return response.content;
|
|
@@ -1657,11 +2058,11 @@ function getActiveSession() {
|
|
|
1657
2058
|
function clearActiveSession() {
|
|
1658
2059
|
activeSession = null;
|
|
1659
2060
|
}
|
|
1660
|
-
var
|
|
2061
|
+
var LoadingIndicator2, MAX_FILE_SIZE2, COMPLEXITY_THRESHOLD, CLARITY_THRESHOLD, activeSession, new_default;
|
|
1661
2062
|
var init_new = __esm({
|
|
1662
2063
|
"src/commands/new.ts"() {
|
|
1663
2064
|
init_cjs_shims();
|
|
1664
|
-
|
|
2065
|
+
LoadingIndicator2 = class {
|
|
1665
2066
|
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1666
2067
|
frameIndex = 0;
|
|
1667
2068
|
interval = null;
|
|
@@ -1771,7 +2172,7 @@ var ConfigManager = class {
|
|
|
1771
2172
|
this.projectPath = projectPath;
|
|
1772
2173
|
this.configPath = path4__namespace.join(projectPath, ".sf-cli", "config.json");
|
|
1773
2174
|
try {
|
|
1774
|
-
const content = await
|
|
2175
|
+
const content = await fs9__namespace.readFile(this.configPath, "utf-8");
|
|
1775
2176
|
const loaded = JSON.parse(content);
|
|
1776
2177
|
if (loaded.apiKey && loaded.apiKeyEncrypted) {
|
|
1777
2178
|
loaded.apiKey = this.decrypt(loaded.apiKey);
|
|
@@ -1790,8 +2191,8 @@ var ConfigManager = class {
|
|
|
1790
2191
|
configToSave.apiKey = encrypted;
|
|
1791
2192
|
configToSave.apiKeyEncrypted = true;
|
|
1792
2193
|
}
|
|
1793
|
-
await
|
|
1794
|
-
await
|
|
2194
|
+
await fs9__namespace.mkdir(path4__namespace.dirname(this.configPath), { recursive: true });
|
|
2195
|
+
await fs9__namespace.writeFile(
|
|
1795
2196
|
this.configPath,
|
|
1796
2197
|
JSON.stringify(configToSave, null, 2),
|
|
1797
2198
|
"utf-8"
|
|
@@ -2026,9 +2427,10 @@ var BaseAdapter = class {
|
|
|
2026
2427
|
}
|
|
2027
2428
|
/**
|
|
2028
2429
|
* 获取超时时间
|
|
2430
|
+
* 默认 5 分钟,对于复杂的代码生成任务足够
|
|
2029
2431
|
*/
|
|
2030
2432
|
getTimeout() {
|
|
2031
|
-
return this.config?.timeout ||
|
|
2433
|
+
return this.config?.timeout || 3e5;
|
|
2032
2434
|
}
|
|
2033
2435
|
/**
|
|
2034
2436
|
* 获取重试次数
|
|
@@ -2888,8 +3290,8 @@ var ModelService = class {
|
|
|
2888
3290
|
const dailyPath = path4__namespace.join(this.statsPath, "daily.json");
|
|
2889
3291
|
const totalPath = path4__namespace.join(this.statsPath, "total.json");
|
|
2890
3292
|
const [daily, total] = await Promise.all([
|
|
2891
|
-
|
|
2892
|
-
|
|
3293
|
+
fs9__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
|
|
3294
|
+
fs9__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
|
|
2893
3295
|
]);
|
|
2894
3296
|
const dailyData = JSON.parse(daily);
|
|
2895
3297
|
const totalData = JSON.parse(total);
|
|
@@ -2902,12 +3304,12 @@ var ModelService = class {
|
|
|
2902
3304
|
async saveStats() {
|
|
2903
3305
|
if (!this.statsPath) return;
|
|
2904
3306
|
try {
|
|
2905
|
-
await
|
|
3307
|
+
await fs9__namespace.mkdir(this.statsPath, { recursive: true });
|
|
2906
3308
|
const dailyPath = path4__namespace.join(this.statsPath, "daily.json");
|
|
2907
3309
|
const totalPath = path4__namespace.join(this.statsPath, "total.json");
|
|
2908
3310
|
await Promise.all([
|
|
2909
|
-
|
|
2910
|
-
|
|
3311
|
+
fs9__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
|
|
3312
|
+
fs9__namespace.writeFile(totalPath, JSON.stringify({
|
|
2911
3313
|
totalInput: this.stats.totalInput,
|
|
2912
3314
|
totalOutput: this.stats.totalOutput
|
|
2913
3315
|
}))
|
|
@@ -4616,15 +5018,15 @@ async function loadProjectContext(workingDirectory) {
|
|
|
4616
5018
|
devStandards: ""
|
|
4617
5019
|
};
|
|
4618
5020
|
try {
|
|
4619
|
-
context.agentsMd = await
|
|
5021
|
+
context.agentsMd = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
|
|
4620
5022
|
} catch {
|
|
4621
5023
|
}
|
|
4622
5024
|
try {
|
|
4623
|
-
context.configYaml = await
|
|
5025
|
+
context.configYaml = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
|
|
4624
5026
|
} catch {
|
|
4625
5027
|
}
|
|
4626
5028
|
try {
|
|
4627
|
-
context.devStandards = await
|
|
5029
|
+
context.devStandards = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
|
|
4628
5030
|
} catch {
|
|
4629
5031
|
}
|
|
4630
5032
|
return context;
|
|
@@ -5587,19 +5989,19 @@ var WorkflowEngine = class {
|
|
|
5587
5989
|
async loadProjectContext() {
|
|
5588
5990
|
const agentsMdPath = path4__namespace.join(this.projectPath, "AGENTS.md");
|
|
5589
5991
|
try {
|
|
5590
|
-
this.projectContext = await
|
|
5992
|
+
this.projectContext = await fs9__namespace.readFile(agentsMdPath, "utf-8");
|
|
5591
5993
|
} catch {
|
|
5592
5994
|
this.projectContext = "";
|
|
5593
5995
|
}
|
|
5594
5996
|
const configPath = path4__namespace.join(this.openspecPath, "config.yaml");
|
|
5595
5997
|
try {
|
|
5596
|
-
this.projectConfig = await
|
|
5998
|
+
this.projectConfig = await fs9__namespace.readFile(configPath, "utf-8");
|
|
5597
5999
|
} catch {
|
|
5598
6000
|
this.projectConfig = "";
|
|
5599
6001
|
}
|
|
5600
6002
|
const devstandedPath = path4__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
|
|
5601
6003
|
try {
|
|
5602
|
-
this.devStandards = await
|
|
6004
|
+
this.devStandards = await fs9__namespace.readFile(devstandedPath, "utf-8");
|
|
5603
6005
|
} catch {
|
|
5604
6006
|
this.devStandards = "";
|
|
5605
6007
|
}
|
|
@@ -5628,7 +6030,7 @@ var WorkflowEngine = class {
|
|
|
5628
6030
|
const specPath = this.getSpecFilePath();
|
|
5629
6031
|
if (!specPath) return false;
|
|
5630
6032
|
try {
|
|
5631
|
-
await
|
|
6033
|
+
await fs9__namespace.access(specPath);
|
|
5632
6034
|
return true;
|
|
5633
6035
|
} catch {
|
|
5634
6036
|
return false;
|
|
@@ -5862,11 +6264,11 @@ var WorkflowEngine = class {
|
|
|
5862
6264
|
const workflows = [];
|
|
5863
6265
|
const changesDir = path4__namespace.join(this.openspecPath, "changes");
|
|
5864
6266
|
try {
|
|
5865
|
-
const files = await
|
|
6267
|
+
const files = await fs9__namespace.readdir(changesDir);
|
|
5866
6268
|
for (const file of files) {
|
|
5867
6269
|
if (!file.endsWith(".md") || file.includes("-spec.md")) continue;
|
|
5868
6270
|
const filePath = path4__namespace.join(changesDir, file);
|
|
5869
|
-
const content = await
|
|
6271
|
+
const content = await fs9__namespace.readFile(filePath, "utf-8");
|
|
5870
6272
|
const state = this.parseChangeRecord(content);
|
|
5871
6273
|
if (state && state.status === "running") {
|
|
5872
6274
|
workflows.push(state);
|
|
@@ -5917,7 +6319,7 @@ var WorkflowEngine = class {
|
|
|
5917
6319
|
}
|
|
5918
6320
|
const statePath = path4__namespace.join(this.openspecPath, ".workflow-states", `${changeId}.json`);
|
|
5919
6321
|
try {
|
|
5920
|
-
const content = await
|
|
6322
|
+
const content = await fs9__namespace.readFile(statePath, "utf-8");
|
|
5921
6323
|
this.state = JSON.parse(content, (key, value) => {
|
|
5922
6324
|
if (key.endsWith("At") && typeof value === "string") {
|
|
5923
6325
|
return new Date(value);
|
|
@@ -5930,7 +6332,7 @@ var WorkflowEngine = class {
|
|
|
5930
6332
|
const changesDir = path4__namespace.join(this.openspecPath, "changes");
|
|
5931
6333
|
const changeFile = path4__namespace.join(changesDir, `${changeId}.md`);
|
|
5932
6334
|
try {
|
|
5933
|
-
const content = await
|
|
6335
|
+
const content = await fs9__namespace.readFile(changeFile, "utf-8");
|
|
5934
6336
|
const parsed = this.parseChangeRecord(content);
|
|
5935
6337
|
if (parsed && parsed.status === "running") {
|
|
5936
6338
|
this.state = parsed;
|
|
@@ -5995,8 +6397,8 @@ var WorkflowEngine = class {
|
|
|
5995
6397
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
5996
6398
|
const changeFile = path4__namespace.join(changesDir, `${changeId}.md`);
|
|
5997
6399
|
const archiveFile = path4__namespace.join(archiveDir, `${changeId}.md`);
|
|
5998
|
-
await
|
|
5999
|
-
await
|
|
6400
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
6401
|
+
await fs9__namespace.rename(changeFile, archiveFile).catch(() => {
|
|
6000
6402
|
});
|
|
6001
6403
|
this.state = null;
|
|
6002
6404
|
this.snapshots.clear();
|
|
@@ -6022,15 +6424,15 @@ var WorkflowEngine = class {
|
|
|
6022
6424
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
6023
6425
|
const specDir = path4__namespace.join(this.openspecPath, "spec");
|
|
6024
6426
|
const statesDir = path4__namespace.join(this.openspecPath, ".workflow-states");
|
|
6025
|
-
await
|
|
6026
|
-
await
|
|
6027
|
-
await
|
|
6427
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
6428
|
+
await fs9__namespace.mkdir(specDir, { recursive: true });
|
|
6429
|
+
await fs9__namespace.mkdir(statesDir, { recursive: true });
|
|
6028
6430
|
}
|
|
6029
6431
|
async restoreState() {
|
|
6030
6432
|
const activePath = path4__namespace.join(this.openspecPath, ".workflow-active.json");
|
|
6031
6433
|
let activeId = null;
|
|
6032
6434
|
try {
|
|
6033
|
-
const activeContent = await
|
|
6435
|
+
const activeContent = await fs9__namespace.readFile(activePath, "utf-8");
|
|
6034
6436
|
const activeData = JSON.parse(activeContent);
|
|
6035
6437
|
activeId = activeData.activeId;
|
|
6036
6438
|
} catch {
|
|
@@ -6038,7 +6440,7 @@ var WorkflowEngine = class {
|
|
|
6038
6440
|
if (activeId) {
|
|
6039
6441
|
const statePath = path4__namespace.join(this.openspecPath, ".workflow-states", `${activeId}.json`);
|
|
6040
6442
|
try {
|
|
6041
|
-
const content = await
|
|
6443
|
+
const content = await fs9__namespace.readFile(statePath, "utf-8");
|
|
6042
6444
|
this.state = JSON.parse(content, (key, value) => {
|
|
6043
6445
|
if (key.endsWith("At") && typeof value === "string") {
|
|
6044
6446
|
return new Date(value);
|
|
@@ -6051,7 +6453,7 @@ var WorkflowEngine = class {
|
|
|
6051
6453
|
}
|
|
6052
6454
|
const oldStatePath = path4__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
6053
6455
|
try {
|
|
6054
|
-
const content = await
|
|
6456
|
+
const content = await fs9__namespace.readFile(oldStatePath, "utf-8");
|
|
6055
6457
|
this.state = JSON.parse(content, (key, value) => {
|
|
6056
6458
|
if (key.endsWith("At") && typeof value === "string") {
|
|
6057
6459
|
return new Date(value);
|
|
@@ -6060,7 +6462,7 @@ var WorkflowEngine = class {
|
|
|
6060
6462
|
});
|
|
6061
6463
|
if (this.state) {
|
|
6062
6464
|
await this.saveState();
|
|
6063
|
-
await
|
|
6465
|
+
await fs9__namespace.unlink(oldStatePath).catch(() => {
|
|
6064
6466
|
});
|
|
6065
6467
|
}
|
|
6066
6468
|
} catch (e) {
|
|
@@ -6074,16 +6476,16 @@ var WorkflowEngine = class {
|
|
|
6074
6476
|
async saveState() {
|
|
6075
6477
|
if (!this.state) return;
|
|
6076
6478
|
const statesDir = path4__namespace.join(this.openspecPath, ".workflow-states");
|
|
6077
|
-
await
|
|
6479
|
+
await fs9__namespace.mkdir(statesDir, { recursive: true });
|
|
6078
6480
|
const statePath = path4__namespace.join(statesDir, `${this.state.id}.json`);
|
|
6079
|
-
await
|
|
6481
|
+
await fs9__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
|
|
6080
6482
|
const activePath = path4__namespace.join(this.openspecPath, ".workflow-active.json");
|
|
6081
|
-
await
|
|
6483
|
+
await fs9__namespace.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
|
|
6082
6484
|
}
|
|
6083
6485
|
async restoreSnapshots() {
|
|
6084
6486
|
const snapshotsPath = path4__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
6085
6487
|
try {
|
|
6086
|
-
const content = await
|
|
6488
|
+
const content = await fs9__namespace.readFile(snapshotsPath, "utf-8");
|
|
6087
6489
|
const data = JSON.parse(content, (key, value) => {
|
|
6088
6490
|
if (key === "timestamp" && typeof value === "string") {
|
|
6089
6491
|
return new Date(value);
|
|
@@ -6100,7 +6502,7 @@ var WorkflowEngine = class {
|
|
|
6100
6502
|
async saveSnapshots() {
|
|
6101
6503
|
const snapshotsPath = path4__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
6102
6504
|
const data = Array.from(this.snapshots.values());
|
|
6103
|
-
await
|
|
6505
|
+
await fs9__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
|
|
6104
6506
|
}
|
|
6105
6507
|
async createSnapshot() {
|
|
6106
6508
|
if (!this.state) return;
|
|
@@ -6121,7 +6523,7 @@ var WorkflowEngine = class {
|
|
|
6121
6523
|
async createChangeRecord() {
|
|
6122
6524
|
if (!this.state) return;
|
|
6123
6525
|
const changePath = path4__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
6124
|
-
await
|
|
6526
|
+
await fs9__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
6125
6527
|
}
|
|
6126
6528
|
async updateChangeRecord(status) {
|
|
6127
6529
|
if (!this.state) return;
|
|
@@ -6129,7 +6531,7 @@ var WorkflowEngine = class {
|
|
|
6129
6531
|
this.state.status = status;
|
|
6130
6532
|
}
|
|
6131
6533
|
const changePath = path4__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
6132
|
-
await
|
|
6534
|
+
await fs9__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
6133
6535
|
}
|
|
6134
6536
|
formatChangeRecord() {
|
|
6135
6537
|
if (!this.state) return "";
|
|
@@ -6193,7 +6595,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
|
|
|
6193
6595
|
|
|
6194
6596
|
${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
6195
6597
|
`;
|
|
6196
|
-
await
|
|
6598
|
+
await fs9__namespace.writeFile(specPath, content);
|
|
6197
6599
|
}
|
|
6198
6600
|
};
|
|
6199
6601
|
var ConfirmationRequiredError = class extends Error {
|
|
@@ -6242,11 +6644,11 @@ var NormsManager = class {
|
|
|
6242
6644
|
const files = await this.collectProjectFiles(projectPath);
|
|
6243
6645
|
for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
|
|
6244
6646
|
try {
|
|
6245
|
-
const stats = await
|
|
6647
|
+
const stats = await fs9__namespace.stat(filePath);
|
|
6246
6648
|
if (stats.size > MAX_FILE_SIZE) {
|
|
6247
6649
|
continue;
|
|
6248
6650
|
}
|
|
6249
|
-
const content = await
|
|
6651
|
+
const content = await fs9__namespace.readFile(filePath, "utf-8");
|
|
6250
6652
|
const patterns = await this.learnFromFile(filePath, content);
|
|
6251
6653
|
result.patternsFound += patterns.length;
|
|
6252
6654
|
result.filesScanned++;
|
|
@@ -6872,7 +7274,7 @@ ${response}`;
|
|
|
6872
7274
|
const files = [];
|
|
6873
7275
|
async function scan(dir) {
|
|
6874
7276
|
try {
|
|
6875
|
-
const entries = await
|
|
7277
|
+
const entries = await fs9__namespace.readdir(dir, { withFileTypes: true });
|
|
6876
7278
|
for (const entry of entries) {
|
|
6877
7279
|
if (entry.isDirectory()) {
|
|
6878
7280
|
if (!IGNORED_DIRS.includes(entry.name)) {
|
|
@@ -6915,8 +7317,8 @@ ${response}`;
|
|
|
6915
7317
|
* 确保规范目录存在
|
|
6916
7318
|
*/
|
|
6917
7319
|
async ensureNormsDir() {
|
|
6918
|
-
await
|
|
6919
|
-
await
|
|
7320
|
+
await fs9__namespace.mkdir(this.config.normsDir, { recursive: true });
|
|
7321
|
+
await fs9__namespace.mkdir(path4__namespace.join(this.config.normsDir, "weekly"), { recursive: true });
|
|
6920
7322
|
}
|
|
6921
7323
|
/**
|
|
6922
7324
|
* 加载已有规范
|
|
@@ -6924,7 +7326,7 @@ ${response}`;
|
|
|
6924
7326
|
async loadStandards() {
|
|
6925
7327
|
const standardsPath = path4__namespace.join(this.config.normsDir, "patterns.json");
|
|
6926
7328
|
try {
|
|
6927
|
-
const content = await
|
|
7329
|
+
const content = await fs9__namespace.readFile(standardsPath, "utf-8");
|
|
6928
7330
|
const data = JSON.parse(content);
|
|
6929
7331
|
for (const standard of data) {
|
|
6930
7332
|
this.standards.set(standard.id, {
|
|
@@ -6942,7 +7344,7 @@ ${response}`;
|
|
|
6942
7344
|
async loadWeights() {
|
|
6943
7345
|
const weightsPath = path4__namespace.join(this.config.normsDir, "weights.json");
|
|
6944
7346
|
try {
|
|
6945
|
-
const content = await
|
|
7347
|
+
const content = await fs9__namespace.readFile(weightsPath, "utf-8");
|
|
6946
7348
|
const data = JSON.parse(content);
|
|
6947
7349
|
for (const weight of data) {
|
|
6948
7350
|
this.weights.set(weight.standardId, {
|
|
@@ -6958,7 +7360,7 @@ ${response}`;
|
|
|
6958
7360
|
*/
|
|
6959
7361
|
async saveStandards() {
|
|
6960
7362
|
const standardsPath = path4__namespace.join(this.config.normsDir, "patterns.json");
|
|
6961
|
-
await
|
|
7363
|
+
await fs9__namespace.writeFile(
|
|
6962
7364
|
standardsPath,
|
|
6963
7365
|
JSON.stringify(Array.from(this.standards.values()), null, 2),
|
|
6964
7366
|
"utf-8"
|
|
@@ -6969,7 +7371,7 @@ ${response}`;
|
|
|
6969
7371
|
*/
|
|
6970
7372
|
async saveWeights() {
|
|
6971
7373
|
const weightsPath = path4__namespace.join(this.config.normsDir, "weights.json");
|
|
6972
|
-
await
|
|
7374
|
+
await fs9__namespace.writeFile(
|
|
6973
7375
|
weightsPath,
|
|
6974
7376
|
JSON.stringify(Array.from(this.weights.values()), null, 2),
|
|
6975
7377
|
"utf-8"
|
|
@@ -6997,7 +7399,7 @@ ${response}`;
|
|
|
6997
7399
|
*/
|
|
6998
7400
|
async saveWeeklyReport(weekId, report) {
|
|
6999
7401
|
const reportPath = path4__namespace.join(this.config.normsDir, "weekly", `${weekId}.json`);
|
|
7000
|
-
await
|
|
7402
|
+
await fs9__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
|
|
7001
7403
|
}
|
|
7002
7404
|
/**
|
|
7003
7405
|
* 更新 devstanded.md
|
|
@@ -7006,7 +7408,7 @@ ${response}`;
|
|
|
7006
7408
|
const standards = this.getEffectiveStandards();
|
|
7007
7409
|
const content = this.generateDevStandedMd(standards);
|
|
7008
7410
|
const mdPath = path4__namespace.join(this.config.normsDir, "devstanded.md");
|
|
7009
|
-
await
|
|
7411
|
+
await fs9__namespace.writeFile(mdPath, content, "utf-8");
|
|
7010
7412
|
}
|
|
7011
7413
|
/**
|
|
7012
7414
|
* 生成 devstanded.md 内容
|
|
@@ -7398,14 +7800,14 @@ ${summary}`,
|
|
|
7398
7800
|
async persist() {
|
|
7399
7801
|
if (!this.persistPath) return;
|
|
7400
7802
|
const dir = path4__namespace.dirname(this.persistPath);
|
|
7401
|
-
await
|
|
7803
|
+
await fs9__namespace.mkdir(dir, { recursive: true });
|
|
7402
7804
|
const data = {
|
|
7403
7805
|
messages: this.state.messages,
|
|
7404
7806
|
totalTokens: this.state.totalTokens,
|
|
7405
7807
|
limit: this.state.limit,
|
|
7406
7808
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7407
7809
|
};
|
|
7408
|
-
await
|
|
7810
|
+
await fs9__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
|
|
7409
7811
|
}
|
|
7410
7812
|
/**
|
|
7411
7813
|
* 加载持久化的上下文
|
|
@@ -7413,7 +7815,7 @@ ${summary}`,
|
|
|
7413
7815
|
async loadPersistedContext() {
|
|
7414
7816
|
if (!this.persistPath) return;
|
|
7415
7817
|
try {
|
|
7416
|
-
const content = await
|
|
7818
|
+
const content = await fs9__namespace.readFile(this.persistPath, "utf-8");
|
|
7417
7819
|
const data = JSON.parse(content);
|
|
7418
7820
|
this.state.messages = data.messages || [];
|
|
7419
7821
|
this.state.totalTokens = data.totalTokens || 0;
|
|
@@ -7630,7 +8032,7 @@ async function handleInit(args, ctx) {
|
|
|
7630
8032
|
async function initProject(options = {}, workingDir) {
|
|
7631
8033
|
const cwd = workingDir || process.cwd();
|
|
7632
8034
|
try {
|
|
7633
|
-
const stats = await
|
|
8035
|
+
const stats = await fs9__namespace.stat(cwd);
|
|
7634
8036
|
if (!stats.isDirectory()) {
|
|
7635
8037
|
return {
|
|
7636
8038
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
@@ -7662,7 +8064,7 @@ async function initProject(options = {}, workingDir) {
|
|
|
7662
8064
|
await normsManager.initialize();
|
|
7663
8065
|
const scanResult = await normsManager.scanProject(cwd);
|
|
7664
8066
|
const agentsContent = generateAgentsMd(projectInfo, scanResult);
|
|
7665
|
-
await
|
|
8067
|
+
await fs9__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
|
|
7666
8068
|
await generateOpenSpecConfig(openspecDir, projectInfo);
|
|
7667
8069
|
return {
|
|
7668
8070
|
output: chalk9__default.default.green("\u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210\n") + chalk9__default.default.gray(` \u9879\u76EE\u7C7B\u578B: ${projectInfo.type}
|
|
@@ -7703,7 +8105,7 @@ async function createSfCliDirectory(basePath) {
|
|
|
7703
8105
|
"logs"
|
|
7704
8106
|
];
|
|
7705
8107
|
for (const dir of dirs) {
|
|
7706
|
-
await
|
|
8108
|
+
await fs9__namespace.mkdir(path4__namespace.join(basePath, dir), { recursive: true });
|
|
7707
8109
|
}
|
|
7708
8110
|
const config = {
|
|
7709
8111
|
version: "1.0.0",
|
|
@@ -7711,22 +8113,22 @@ async function createSfCliDirectory(basePath) {
|
|
|
7711
8113
|
yolo: false,
|
|
7712
8114
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7713
8115
|
};
|
|
7714
|
-
await
|
|
8116
|
+
await fs9__namespace.writeFile(
|
|
7715
8117
|
path4__namespace.join(basePath, "config.json"),
|
|
7716
8118
|
JSON.stringify(config, null, 2),
|
|
7717
8119
|
"utf-8"
|
|
7718
8120
|
);
|
|
7719
|
-
await
|
|
8121
|
+
await fs9__namespace.writeFile(
|
|
7720
8122
|
path4__namespace.join(basePath, "agents", "registry.json"),
|
|
7721
8123
|
JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
|
|
7722
8124
|
"utf-8"
|
|
7723
8125
|
);
|
|
7724
|
-
await
|
|
8126
|
+
await fs9__namespace.writeFile(
|
|
7725
8127
|
path4__namespace.join(basePath, "skills", "registry.json"),
|
|
7726
8128
|
JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
|
|
7727
8129
|
"utf-8"
|
|
7728
8130
|
);
|
|
7729
|
-
await
|
|
8131
|
+
await fs9__namespace.writeFile(
|
|
7730
8132
|
path4__namespace.join(basePath, "health", "health.md"),
|
|
7731
8133
|
generateHealthTemplate(),
|
|
7732
8134
|
"utf-8"
|
|
@@ -7736,8 +8138,8 @@ async function createOpenSpecDirectory(basePath) {
|
|
|
7736
8138
|
const changesDir = path4__namespace.join(basePath, "changes");
|
|
7737
8139
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
7738
8140
|
const specDir = path4__namespace.join(basePath, "spec");
|
|
7739
|
-
await
|
|
7740
|
-
await
|
|
8141
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
8142
|
+
await fs9__namespace.mkdir(specDir, { recursive: true });
|
|
7741
8143
|
}
|
|
7742
8144
|
async function analyzeProject(cwd) {
|
|
7743
8145
|
const result = {
|
|
@@ -7762,7 +8164,7 @@ async function analyzeProject(cwd) {
|
|
|
7762
8164
|
};
|
|
7763
8165
|
const pkgPath = path4__namespace.join(cwd, "package.json");
|
|
7764
8166
|
try {
|
|
7765
|
-
const pkgContent = await
|
|
8167
|
+
const pkgContent = await fs9__namespace.readFile(pkgPath, "utf-8");
|
|
7766
8168
|
const pkg = JSON.parse(pkgContent);
|
|
7767
8169
|
result.name = pkg.name || result.name;
|
|
7768
8170
|
result.dependencies = pkg.dependencies || {};
|
|
@@ -7845,7 +8247,7 @@ async function analyzeDirectoryStructure(cwd) {
|
|
|
7845
8247
|
others: []
|
|
7846
8248
|
};
|
|
7847
8249
|
try {
|
|
7848
|
-
const entries = await
|
|
8250
|
+
const entries = await fs9__namespace.readdir(cwd, { withFileTypes: true });
|
|
7849
8251
|
for (const entry of entries) {
|
|
7850
8252
|
if (!entry.isDirectory()) continue;
|
|
7851
8253
|
const name = entry.name;
|
|
@@ -7890,7 +8292,7 @@ async function findEntryPoints(cwd) {
|
|
|
7890
8292
|
}
|
|
7891
8293
|
async function saveProjectAnalysis(sfCliDir, analysis) {
|
|
7892
8294
|
const analysisPath = path4__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
|
|
7893
|
-
await
|
|
8295
|
+
await fs9__namespace.writeFile(
|
|
7894
8296
|
analysisPath,
|
|
7895
8297
|
JSON.stringify(analysis, null, 2),
|
|
7896
8298
|
"utf-8"
|
|
@@ -7931,7 +8333,7 @@ architecture:
|
|
|
7931
8333
|
# \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
|
|
7932
8334
|
standards: []
|
|
7933
8335
|
`;
|
|
7934
|
-
await
|
|
8336
|
+
await fs9__namespace.writeFile(configPath, content, "utf-8");
|
|
7935
8337
|
}
|
|
7936
8338
|
function generateAgentsMd(info, scanResult) {
|
|
7937
8339
|
const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
|
|
@@ -8053,7 +8455,7 @@ function generateHealthTemplate() {
|
|
|
8053
8455
|
}
|
|
8054
8456
|
async function fileExists(filePath) {
|
|
8055
8457
|
try {
|
|
8056
|
-
await
|
|
8458
|
+
await fs9__namespace.access(filePath);
|
|
8057
8459
|
return true;
|
|
8058
8460
|
} catch {
|
|
8059
8461
|
return false;
|
|
@@ -8218,6 +8620,36 @@ ${chalk9__default.default.yellow("\u793A\u4F8B:")}
|
|
|
8218
8620
|
|
|
8219
8621
|
// src/commands/model.ts
|
|
8220
8622
|
init_cjs_shims();
|
|
8623
|
+
var LoadingIndicator = class {
|
|
8624
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8625
|
+
frameIndex = 0;
|
|
8626
|
+
interval = null;
|
|
8627
|
+
message;
|
|
8628
|
+
constructor(message) {
|
|
8629
|
+
this.message = message;
|
|
8630
|
+
}
|
|
8631
|
+
start() {
|
|
8632
|
+
process.stdout.write("\x1B[?25l");
|
|
8633
|
+
this.interval = setInterval(() => {
|
|
8634
|
+
const frame = this.frames[this.frameIndex];
|
|
8635
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
8636
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
8637
|
+
}, 80);
|
|
8638
|
+
}
|
|
8639
|
+
stop(finalMessage) {
|
|
8640
|
+
if (this.interval) {
|
|
8641
|
+
clearInterval(this.interval);
|
|
8642
|
+
this.interval = null;
|
|
8643
|
+
}
|
|
8644
|
+
process.stdout.write("\x1B[?25h");
|
|
8645
|
+
if (finalMessage) {
|
|
8646
|
+
process.stdout.write(`\r${finalMessage}
|
|
8647
|
+
`);
|
|
8648
|
+
} else {
|
|
8649
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
8650
|
+
}
|
|
8651
|
+
}
|
|
8652
|
+
};
|
|
8221
8653
|
async function handleModel(args, ctx) {
|
|
8222
8654
|
const subCommand = args[0];
|
|
8223
8655
|
const configManager = ctx.configManager;
|
|
@@ -8317,9 +8749,12 @@ async function verifyCurrentModel(configManager, modelService) {
|
|
|
8317
8749
|
output: chalk9__default.default.red(`\u2717 \u672A\u77E5\u6A21\u578B: ${currentModel}`)
|
|
8318
8750
|
};
|
|
8319
8751
|
}
|
|
8752
|
+
const loader = new LoadingIndicator(`\u9A8C\u8BC1 ${modelInfo.name} API Key`);
|
|
8753
|
+
loader.start();
|
|
8320
8754
|
try {
|
|
8321
8755
|
const adapter = createAdapter(modelInfo.provider);
|
|
8322
8756
|
const isValid = await adapter.validateApiKey(apiKey);
|
|
8757
|
+
loader.stop();
|
|
8323
8758
|
if (isValid) {
|
|
8324
8759
|
return {
|
|
8325
8760
|
output: chalk9__default.default.green(`\u2713 API Key \u9A8C\u8BC1\u6210\u529F
|
|
@@ -8331,6 +8766,7 @@ async function verifyCurrentModel(configManager, modelService) {
|
|
|
8331
8766
|
};
|
|
8332
8767
|
}
|
|
8333
8768
|
} catch (error) {
|
|
8769
|
+
loader.stop();
|
|
8334
8770
|
return {
|
|
8335
8771
|
output: chalk9__default.default.red(`\u2717 \u9A8C\u8BC1\u5931\u8D25: ${error.message}`)
|
|
8336
8772
|
};
|
|
@@ -9454,9 +9890,9 @@ async function handleFileReference(filePath, ctx) {
|
|
|
9454
9890
|
const cwd = ctx.options.workingDirectory;
|
|
9455
9891
|
const absolutePath = path4__namespace.isAbsolute(filePath) ? filePath : path4__namespace.join(cwd, filePath);
|
|
9456
9892
|
try {
|
|
9457
|
-
const stats = await
|
|
9893
|
+
const stats = await fs9__namespace.stat(absolutePath);
|
|
9458
9894
|
if (stats.isDirectory()) {
|
|
9459
|
-
const files = await
|
|
9895
|
+
const files = await fs9__namespace.readdir(absolutePath);
|
|
9460
9896
|
return {
|
|
9461
9897
|
output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
|
|
9462
9898
|
${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
|
|
@@ -9464,7 +9900,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
|
|
|
9464
9900
|
contextUsed: 0
|
|
9465
9901
|
};
|
|
9466
9902
|
}
|
|
9467
|
-
const content = await
|
|
9903
|
+
const content = await fs9__namespace.readFile(absolutePath, "utf-8");
|
|
9468
9904
|
const lines = content.split("\n");
|
|
9469
9905
|
ctx.contextManager.addMessage({
|
|
9470
9906
|
role: "user",
|
|
@@ -9542,6 +9978,36 @@ async function executeShell(command, ctx) {
|
|
|
9542
9978
|
// src/commands/natural.ts
|
|
9543
9979
|
init_cjs_shims();
|
|
9544
9980
|
init_new();
|
|
9981
|
+
var LoadingIndicator3 = class {
|
|
9982
|
+
frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
9983
|
+
frameIndex = 0;
|
|
9984
|
+
interval = null;
|
|
9985
|
+
message;
|
|
9986
|
+
constructor(message) {
|
|
9987
|
+
this.message = message;
|
|
9988
|
+
}
|
|
9989
|
+
start() {
|
|
9990
|
+
process.stdout.write("\x1B[?25l");
|
|
9991
|
+
this.interval = setInterval(() => {
|
|
9992
|
+
const frame = this.frames[this.frameIndex];
|
|
9993
|
+
process.stdout.write(`\r${chalk9__default.default.cyan(frame)} ${this.message}...`);
|
|
9994
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
9995
|
+
}, 80);
|
|
9996
|
+
}
|
|
9997
|
+
stop(finalMessage) {
|
|
9998
|
+
if (this.interval) {
|
|
9999
|
+
clearInterval(this.interval);
|
|
10000
|
+
this.interval = null;
|
|
10001
|
+
}
|
|
10002
|
+
process.stdout.write("\x1B[?25h");
|
|
10003
|
+
if (finalMessage) {
|
|
10004
|
+
process.stdout.write(`\r${finalMessage}
|
|
10005
|
+
`);
|
|
10006
|
+
} else {
|
|
10007
|
+
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
10008
|
+
}
|
|
10009
|
+
}
|
|
10010
|
+
};
|
|
9545
10011
|
async function handleNaturalLanguage(input, ctx) {
|
|
9546
10012
|
const trimmedInput = input.trim();
|
|
9547
10013
|
const session = getActiveSession();
|
|
@@ -9561,6 +10027,8 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
9561
10027
|
contextUsed: 0
|
|
9562
10028
|
};
|
|
9563
10029
|
}
|
|
10030
|
+
const loader = new LoadingIndicator3("AI \u601D\u8003\u4E2D");
|
|
10031
|
+
loader.start();
|
|
9564
10032
|
try {
|
|
9565
10033
|
const response = await ctx.modelService.sendMessage(
|
|
9566
10034
|
[
|
|
@@ -9578,6 +10046,7 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
9578
10046
|
maxTokens: 2e3
|
|
9579
10047
|
}
|
|
9580
10048
|
);
|
|
10049
|
+
loader.stop();
|
|
9581
10050
|
ctx.contextManager.addMessage({
|
|
9582
10051
|
role: "user",
|
|
9583
10052
|
content: trimmedInput
|
|
@@ -9591,6 +10060,7 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
9591
10060
|
contextUsed: response.usage?.totalTokens || 0
|
|
9592
10061
|
};
|
|
9593
10062
|
} catch (error) {
|
|
10063
|
+
loader.stop();
|
|
9594
10064
|
const errorMessage = error.message;
|
|
9595
10065
|
if (errorMessage.includes("\u672A\u914D\u7F6E") || errorMessage.includes("\u672A\u521D\u59CB\u5316")) {
|
|
9596
10066
|
return {
|
|
@@ -9859,7 +10329,7 @@ var Completer = class {
|
|
|
9859
10329
|
prefix = filePath.slice(lastSlash + 1);
|
|
9860
10330
|
}
|
|
9861
10331
|
try {
|
|
9862
|
-
const entries = await
|
|
10332
|
+
const entries = await fs9__namespace.readdir(dirPath, { withFileTypes: true });
|
|
9863
10333
|
const matches = [];
|
|
9864
10334
|
for (const entry of entries) {
|
|
9865
10335
|
if (entry.name.startsWith(prefix)) {
|