@nick848/sf-cli 1.0.22 → 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 +341 -108
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +338 -105
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +337 -104
- 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);
|
|
@@ -667,24 +667,13 @@ async function executeDevelopment(ctx, session) {
|
|
|
667
667
|
loader.start();
|
|
668
668
|
try {
|
|
669
669
|
const taskPrompt = buildTaskPrompt(session, item, i);
|
|
670
|
+
const structureInfo = session.context?.projectStructure;
|
|
671
|
+
const structureGuide = buildStructureGuide(structureInfo);
|
|
672
|
+
const systemPrompt = buildCodeGenerationSystemPrompt(session, structureGuide);
|
|
670
673
|
const messages = [
|
|
671
674
|
{
|
|
672
675
|
role: "system",
|
|
673
|
-
content:
|
|
674
|
-
|
|
675
|
-
\u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
|
|
676
|
-
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
|
|
677
|
-
2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
|
|
678
|
-
3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
|
|
679
|
-
4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
|
|
680
|
-
|
|
681
|
-
\u9879\u76EE\u4FE1\u606F\uFF1A
|
|
682
|
-
- \u540D\u79F0: ${session.context?.name}
|
|
683
|
-
- \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
|
|
684
|
-
- \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
|
|
685
|
-
|
|
686
|
-
${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
|
|
687
|
-
${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
676
|
+
content: systemPrompt
|
|
688
677
|
},
|
|
689
678
|
{
|
|
690
679
|
role: "user",
|
|
@@ -704,17 +693,17 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
704
693
|
for (const block of codeBlocks) {
|
|
705
694
|
const filePath = path4__namespace.join(workingDir, block.filename);
|
|
706
695
|
const dir = path4__namespace.dirname(filePath);
|
|
707
|
-
await
|
|
708
|
-
await
|
|
696
|
+
await fs9__namespace.mkdir(dir, { recursive: true });
|
|
697
|
+
await fs9__namespace.writeFile(filePath, block.code, "utf-8");
|
|
709
698
|
files.push(block.filename);
|
|
710
699
|
}
|
|
711
700
|
loader.stop(chalk9__default.default.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
|
|
712
701
|
} else {
|
|
713
702
|
const implDir = path4__namespace.join(workingDir, "src");
|
|
714
|
-
await
|
|
703
|
+
await fs9__namespace.mkdir(implDir, { recursive: true });
|
|
715
704
|
const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
|
|
716
705
|
const filePath = path4__namespace.join(implDir, fileName);
|
|
717
|
-
await
|
|
706
|
+
await fs9__namespace.writeFile(filePath, `// TODO: ${item.title}
|
|
718
707
|
// ${item.description}
|
|
719
708
|
`, "utf-8");
|
|
720
709
|
files.push(`src/${fileName}`);
|
|
@@ -737,6 +726,91 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
|
|
|
737
726
|
};
|
|
738
727
|
}
|
|
739
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
|
+
}
|
|
740
814
|
function buildTaskPrompt(session, item, index) {
|
|
741
815
|
const lines = [];
|
|
742
816
|
lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
|
|
@@ -791,7 +865,7 @@ async function executeReview(ctx, session) {
|
|
|
791
865
|
const codeContents = [];
|
|
792
866
|
for (const file of session.implFiles) {
|
|
793
867
|
try {
|
|
794
|
-
const content = await
|
|
868
|
+
const content = await fs9__namespace.readFile(path4__namespace.join(workingDir, file), "utf-8");
|
|
795
869
|
codeContents.push(`// ${file}
|
|
796
870
|
${content}`);
|
|
797
871
|
} catch {
|
|
@@ -800,7 +874,7 @@ ${content}`);
|
|
|
800
874
|
const testContents = [];
|
|
801
875
|
for (const file of session.testFiles) {
|
|
802
876
|
try {
|
|
803
|
-
const content = await
|
|
877
|
+
const content = await fs9__namespace.readFile(path4__namespace.join(workingDir, file), "utf-8");
|
|
804
878
|
testContents.push(`// ${file}
|
|
805
879
|
${content}`);
|
|
806
880
|
} catch {
|
|
@@ -894,9 +968,9 @@ async function readProjectContext(workingDir) {
|
|
|
894
968
|
};
|
|
895
969
|
const agentsPath = path4__namespace.join(workingDir, "AGENTS.md");
|
|
896
970
|
try {
|
|
897
|
-
const stats = await
|
|
971
|
+
const stats = await fs9__namespace.stat(agentsPath);
|
|
898
972
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
899
|
-
context.agentsMd = await
|
|
973
|
+
context.agentsMd = await fs9__namespace.readFile(agentsPath, "utf-8");
|
|
900
974
|
const nameMatch = context.agentsMd.match(/\|\s*项目名称\s*\|\s*([^\s|]+)/);
|
|
901
975
|
if (nameMatch) context.name = nameMatch[1];
|
|
902
976
|
const typeMatch = context.agentsMd.match(/\|\s*项目类型\s*\|\s*([^\s|]+)/);
|
|
@@ -910,9 +984,9 @@ async function readProjectContext(workingDir) {
|
|
|
910
984
|
}
|
|
911
985
|
const configPath = path4__namespace.join(workingDir, "openspec", "config.yaml");
|
|
912
986
|
try {
|
|
913
|
-
const stats = await
|
|
987
|
+
const stats = await fs9__namespace.stat(configPath);
|
|
914
988
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
915
|
-
context.configYaml = await
|
|
989
|
+
context.configYaml = await fs9__namespace.readFile(configPath, "utf-8");
|
|
916
990
|
const nameMatch = context.configYaml.match(/name:\s*(.+)/);
|
|
917
991
|
if (nameMatch) context.name = nameMatch[1].trim();
|
|
918
992
|
const typeMatch = context.configYaml.match(/type:\s*(.+)/);
|
|
@@ -933,14 +1007,173 @@ async function readProjectContext(workingDir) {
|
|
|
933
1007
|
}
|
|
934
1008
|
const devStandardsPath = path4__namespace.join(workingDir, ".sf-cli", "norms", "devstanded.md");
|
|
935
1009
|
try {
|
|
936
|
-
const stats = await
|
|
1010
|
+
const stats = await fs9__namespace.stat(devStandardsPath);
|
|
937
1011
|
if (stats.size <= MAX_FILE_SIZE2) {
|
|
938
|
-
context.devStandards = await
|
|
1012
|
+
context.devStandards = await fs9__namespace.readFile(devStandardsPath, "utf-8");
|
|
939
1013
|
}
|
|
940
1014
|
} catch {
|
|
941
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);
|
|
942
1027
|
return context;
|
|
943
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
|
+
}
|
|
944
1177
|
function analyzeComplexity(requirement, context) {
|
|
945
1178
|
let score = 3;
|
|
946
1179
|
if (requirement.length > 100) score += 1;
|
|
@@ -1429,10 +1662,10 @@ ${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
|
|
|
1429
1662
|
}
|
|
1430
1663
|
async function saveSpecFile(workingDir, session) {
|
|
1431
1664
|
const specDir = path4__namespace.join(workingDir, "openspec", "changes");
|
|
1432
|
-
await
|
|
1665
|
+
await fs9__namespace.mkdir(specDir, { recursive: true });
|
|
1433
1666
|
const specPath = path4__namespace.join(specDir, `${session.id}-spec.md`);
|
|
1434
1667
|
const content = formatSpecFile(session);
|
|
1435
|
-
await
|
|
1668
|
+
await fs9__namespace.writeFile(specPath, content, "utf-8");
|
|
1436
1669
|
return specPath;
|
|
1437
1670
|
}
|
|
1438
1671
|
function formatSpecFile(session) {
|
|
@@ -1517,7 +1750,7 @@ function formatSpecFile(session) {
|
|
|
1517
1750
|
}
|
|
1518
1751
|
async function generateTests(workingDir, session, ctx) {
|
|
1519
1752
|
const testDir = path4__namespace.join(workingDir, "tests");
|
|
1520
|
-
await
|
|
1753
|
+
await fs9__namespace.mkdir(testDir, { recursive: true });
|
|
1521
1754
|
const testFiles = [];
|
|
1522
1755
|
if (ctx?.modelService) {
|
|
1523
1756
|
for (const scenario of session.bddScenarios) {
|
|
@@ -1527,12 +1760,12 @@ async function generateTests(workingDir, session, ctx) {
|
|
|
1527
1760
|
loader.start();
|
|
1528
1761
|
try {
|
|
1529
1762
|
const content = await generateTestFileWithAI(scenario, session, ctx);
|
|
1530
|
-
await
|
|
1763
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1531
1764
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1532
1765
|
loader.stop(chalk9__default.default.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
|
|
1533
1766
|
} catch {
|
|
1534
1767
|
const content = generateTestFile(scenario, session);
|
|
1535
|
-
await
|
|
1768
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1536
1769
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1537
1770
|
loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
|
|
1538
1771
|
}
|
|
@@ -1542,7 +1775,7 @@ async function generateTests(workingDir, session, ctx) {
|
|
|
1542
1775
|
const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
|
|
1543
1776
|
const testPath = path4__namespace.join(testDir, `${testName}.test.ts`);
|
|
1544
1777
|
const content = generateTestFile(scenario, session);
|
|
1545
|
-
await
|
|
1778
|
+
await fs9__namespace.writeFile(testPath, content, "utf-8");
|
|
1546
1779
|
testFiles.push(`tests/${testName}.test.ts`);
|
|
1547
1780
|
}
|
|
1548
1781
|
}
|
|
@@ -1636,7 +1869,7 @@ function generateTestFile(scenario, session) {
|
|
|
1636
1869
|
async function archiveWorkflow(workingDir) {
|
|
1637
1870
|
if (!activeSession) return;
|
|
1638
1871
|
const archiveDir = path4__namespace.join(workingDir, "openspec", "spec");
|
|
1639
|
-
await
|
|
1872
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
1640
1873
|
const archivePath = path4__namespace.join(archiveDir, `${activeSession.id}.md`);
|
|
1641
1874
|
const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
|
|
1642
1875
|
|
|
@@ -1663,7 +1896,7 @@ ${activeSession.refinedRequirement}
|
|
|
1663
1896
|
|
|
1664
1897
|
${activeSession.testFiles.map((f) => `- ${f}`).join("\n") || "\u65E0"}
|
|
1665
1898
|
`;
|
|
1666
|
-
await
|
|
1899
|
+
await fs9__namespace.writeFile(archivePath, content, "utf-8");
|
|
1667
1900
|
}
|
|
1668
1901
|
function generateSessionId() {
|
|
1669
1902
|
const timestamp = Date.now().toString(36);
|
|
@@ -1939,7 +2172,7 @@ var ConfigManager = class {
|
|
|
1939
2172
|
this.projectPath = projectPath;
|
|
1940
2173
|
this.configPath = path4__namespace.join(projectPath, ".sf-cli", "config.json");
|
|
1941
2174
|
try {
|
|
1942
|
-
const content = await
|
|
2175
|
+
const content = await fs9__namespace.readFile(this.configPath, "utf-8");
|
|
1943
2176
|
const loaded = JSON.parse(content);
|
|
1944
2177
|
if (loaded.apiKey && loaded.apiKeyEncrypted) {
|
|
1945
2178
|
loaded.apiKey = this.decrypt(loaded.apiKey);
|
|
@@ -1958,8 +2191,8 @@ var ConfigManager = class {
|
|
|
1958
2191
|
configToSave.apiKey = encrypted;
|
|
1959
2192
|
configToSave.apiKeyEncrypted = true;
|
|
1960
2193
|
}
|
|
1961
|
-
await
|
|
1962
|
-
await
|
|
2194
|
+
await fs9__namespace.mkdir(path4__namespace.dirname(this.configPath), { recursive: true });
|
|
2195
|
+
await fs9__namespace.writeFile(
|
|
1963
2196
|
this.configPath,
|
|
1964
2197
|
JSON.stringify(configToSave, null, 2),
|
|
1965
2198
|
"utf-8"
|
|
@@ -3057,8 +3290,8 @@ var ModelService = class {
|
|
|
3057
3290
|
const dailyPath = path4__namespace.join(this.statsPath, "daily.json");
|
|
3058
3291
|
const totalPath = path4__namespace.join(this.statsPath, "total.json");
|
|
3059
3292
|
const [daily, total] = await Promise.all([
|
|
3060
|
-
|
|
3061
|
-
|
|
3293
|
+
fs9__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
|
|
3294
|
+
fs9__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
|
|
3062
3295
|
]);
|
|
3063
3296
|
const dailyData = JSON.parse(daily);
|
|
3064
3297
|
const totalData = JSON.parse(total);
|
|
@@ -3071,12 +3304,12 @@ var ModelService = class {
|
|
|
3071
3304
|
async saveStats() {
|
|
3072
3305
|
if (!this.statsPath) return;
|
|
3073
3306
|
try {
|
|
3074
|
-
await
|
|
3307
|
+
await fs9__namespace.mkdir(this.statsPath, { recursive: true });
|
|
3075
3308
|
const dailyPath = path4__namespace.join(this.statsPath, "daily.json");
|
|
3076
3309
|
const totalPath = path4__namespace.join(this.statsPath, "total.json");
|
|
3077
3310
|
await Promise.all([
|
|
3078
|
-
|
|
3079
|
-
|
|
3311
|
+
fs9__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
|
|
3312
|
+
fs9__namespace.writeFile(totalPath, JSON.stringify({
|
|
3080
3313
|
totalInput: this.stats.totalInput,
|
|
3081
3314
|
totalOutput: this.stats.totalOutput
|
|
3082
3315
|
}))
|
|
@@ -4785,15 +5018,15 @@ async function loadProjectContext(workingDirectory) {
|
|
|
4785
5018
|
devStandards: ""
|
|
4786
5019
|
};
|
|
4787
5020
|
try {
|
|
4788
|
-
context.agentsMd = await
|
|
5021
|
+
context.agentsMd = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
|
|
4789
5022
|
} catch {
|
|
4790
5023
|
}
|
|
4791
5024
|
try {
|
|
4792
|
-
context.configYaml = await
|
|
5025
|
+
context.configYaml = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
|
|
4793
5026
|
} catch {
|
|
4794
5027
|
}
|
|
4795
5028
|
try {
|
|
4796
|
-
context.devStandards = await
|
|
5029
|
+
context.devStandards = await fs9__namespace.readFile(path4__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
|
|
4797
5030
|
} catch {
|
|
4798
5031
|
}
|
|
4799
5032
|
return context;
|
|
@@ -5756,19 +5989,19 @@ var WorkflowEngine = class {
|
|
|
5756
5989
|
async loadProjectContext() {
|
|
5757
5990
|
const agentsMdPath = path4__namespace.join(this.projectPath, "AGENTS.md");
|
|
5758
5991
|
try {
|
|
5759
|
-
this.projectContext = await
|
|
5992
|
+
this.projectContext = await fs9__namespace.readFile(agentsMdPath, "utf-8");
|
|
5760
5993
|
} catch {
|
|
5761
5994
|
this.projectContext = "";
|
|
5762
5995
|
}
|
|
5763
5996
|
const configPath = path4__namespace.join(this.openspecPath, "config.yaml");
|
|
5764
5997
|
try {
|
|
5765
|
-
this.projectConfig = await
|
|
5998
|
+
this.projectConfig = await fs9__namespace.readFile(configPath, "utf-8");
|
|
5766
5999
|
} catch {
|
|
5767
6000
|
this.projectConfig = "";
|
|
5768
6001
|
}
|
|
5769
6002
|
const devstandedPath = path4__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
|
|
5770
6003
|
try {
|
|
5771
|
-
this.devStandards = await
|
|
6004
|
+
this.devStandards = await fs9__namespace.readFile(devstandedPath, "utf-8");
|
|
5772
6005
|
} catch {
|
|
5773
6006
|
this.devStandards = "";
|
|
5774
6007
|
}
|
|
@@ -5797,7 +6030,7 @@ var WorkflowEngine = class {
|
|
|
5797
6030
|
const specPath = this.getSpecFilePath();
|
|
5798
6031
|
if (!specPath) return false;
|
|
5799
6032
|
try {
|
|
5800
|
-
await
|
|
6033
|
+
await fs9__namespace.access(specPath);
|
|
5801
6034
|
return true;
|
|
5802
6035
|
} catch {
|
|
5803
6036
|
return false;
|
|
@@ -6031,11 +6264,11 @@ var WorkflowEngine = class {
|
|
|
6031
6264
|
const workflows = [];
|
|
6032
6265
|
const changesDir = path4__namespace.join(this.openspecPath, "changes");
|
|
6033
6266
|
try {
|
|
6034
|
-
const files = await
|
|
6267
|
+
const files = await fs9__namespace.readdir(changesDir);
|
|
6035
6268
|
for (const file of files) {
|
|
6036
6269
|
if (!file.endsWith(".md") || file.includes("-spec.md")) continue;
|
|
6037
6270
|
const filePath = path4__namespace.join(changesDir, file);
|
|
6038
|
-
const content = await
|
|
6271
|
+
const content = await fs9__namespace.readFile(filePath, "utf-8");
|
|
6039
6272
|
const state = this.parseChangeRecord(content);
|
|
6040
6273
|
if (state && state.status === "running") {
|
|
6041
6274
|
workflows.push(state);
|
|
@@ -6086,7 +6319,7 @@ var WorkflowEngine = class {
|
|
|
6086
6319
|
}
|
|
6087
6320
|
const statePath = path4__namespace.join(this.openspecPath, ".workflow-states", `${changeId}.json`);
|
|
6088
6321
|
try {
|
|
6089
|
-
const content = await
|
|
6322
|
+
const content = await fs9__namespace.readFile(statePath, "utf-8");
|
|
6090
6323
|
this.state = JSON.parse(content, (key, value) => {
|
|
6091
6324
|
if (key.endsWith("At") && typeof value === "string") {
|
|
6092
6325
|
return new Date(value);
|
|
@@ -6099,7 +6332,7 @@ var WorkflowEngine = class {
|
|
|
6099
6332
|
const changesDir = path4__namespace.join(this.openspecPath, "changes");
|
|
6100
6333
|
const changeFile = path4__namespace.join(changesDir, `${changeId}.md`);
|
|
6101
6334
|
try {
|
|
6102
|
-
const content = await
|
|
6335
|
+
const content = await fs9__namespace.readFile(changeFile, "utf-8");
|
|
6103
6336
|
const parsed = this.parseChangeRecord(content);
|
|
6104
6337
|
if (parsed && parsed.status === "running") {
|
|
6105
6338
|
this.state = parsed;
|
|
@@ -6164,8 +6397,8 @@ var WorkflowEngine = class {
|
|
|
6164
6397
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
6165
6398
|
const changeFile = path4__namespace.join(changesDir, `${changeId}.md`);
|
|
6166
6399
|
const archiveFile = path4__namespace.join(archiveDir, `${changeId}.md`);
|
|
6167
|
-
await
|
|
6168
|
-
await
|
|
6400
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
6401
|
+
await fs9__namespace.rename(changeFile, archiveFile).catch(() => {
|
|
6169
6402
|
});
|
|
6170
6403
|
this.state = null;
|
|
6171
6404
|
this.snapshots.clear();
|
|
@@ -6191,15 +6424,15 @@ var WorkflowEngine = class {
|
|
|
6191
6424
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
6192
6425
|
const specDir = path4__namespace.join(this.openspecPath, "spec");
|
|
6193
6426
|
const statesDir = path4__namespace.join(this.openspecPath, ".workflow-states");
|
|
6194
|
-
await
|
|
6195
|
-
await
|
|
6196
|
-
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 });
|
|
6197
6430
|
}
|
|
6198
6431
|
async restoreState() {
|
|
6199
6432
|
const activePath = path4__namespace.join(this.openspecPath, ".workflow-active.json");
|
|
6200
6433
|
let activeId = null;
|
|
6201
6434
|
try {
|
|
6202
|
-
const activeContent = await
|
|
6435
|
+
const activeContent = await fs9__namespace.readFile(activePath, "utf-8");
|
|
6203
6436
|
const activeData = JSON.parse(activeContent);
|
|
6204
6437
|
activeId = activeData.activeId;
|
|
6205
6438
|
} catch {
|
|
@@ -6207,7 +6440,7 @@ var WorkflowEngine = class {
|
|
|
6207
6440
|
if (activeId) {
|
|
6208
6441
|
const statePath = path4__namespace.join(this.openspecPath, ".workflow-states", `${activeId}.json`);
|
|
6209
6442
|
try {
|
|
6210
|
-
const content = await
|
|
6443
|
+
const content = await fs9__namespace.readFile(statePath, "utf-8");
|
|
6211
6444
|
this.state = JSON.parse(content, (key, value) => {
|
|
6212
6445
|
if (key.endsWith("At") && typeof value === "string") {
|
|
6213
6446
|
return new Date(value);
|
|
@@ -6220,7 +6453,7 @@ var WorkflowEngine = class {
|
|
|
6220
6453
|
}
|
|
6221
6454
|
const oldStatePath = path4__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
6222
6455
|
try {
|
|
6223
|
-
const content = await
|
|
6456
|
+
const content = await fs9__namespace.readFile(oldStatePath, "utf-8");
|
|
6224
6457
|
this.state = JSON.parse(content, (key, value) => {
|
|
6225
6458
|
if (key.endsWith("At") && typeof value === "string") {
|
|
6226
6459
|
return new Date(value);
|
|
@@ -6229,7 +6462,7 @@ var WorkflowEngine = class {
|
|
|
6229
6462
|
});
|
|
6230
6463
|
if (this.state) {
|
|
6231
6464
|
await this.saveState();
|
|
6232
|
-
await
|
|
6465
|
+
await fs9__namespace.unlink(oldStatePath).catch(() => {
|
|
6233
6466
|
});
|
|
6234
6467
|
}
|
|
6235
6468
|
} catch (e) {
|
|
@@ -6243,16 +6476,16 @@ var WorkflowEngine = class {
|
|
|
6243
6476
|
async saveState() {
|
|
6244
6477
|
if (!this.state) return;
|
|
6245
6478
|
const statesDir = path4__namespace.join(this.openspecPath, ".workflow-states");
|
|
6246
|
-
await
|
|
6479
|
+
await fs9__namespace.mkdir(statesDir, { recursive: true });
|
|
6247
6480
|
const statePath = path4__namespace.join(statesDir, `${this.state.id}.json`);
|
|
6248
|
-
await
|
|
6481
|
+
await fs9__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
|
|
6249
6482
|
const activePath = path4__namespace.join(this.openspecPath, ".workflow-active.json");
|
|
6250
|
-
await
|
|
6483
|
+
await fs9__namespace.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
|
|
6251
6484
|
}
|
|
6252
6485
|
async restoreSnapshots() {
|
|
6253
6486
|
const snapshotsPath = path4__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
6254
6487
|
try {
|
|
6255
|
-
const content = await
|
|
6488
|
+
const content = await fs9__namespace.readFile(snapshotsPath, "utf-8");
|
|
6256
6489
|
const data = JSON.parse(content, (key, value) => {
|
|
6257
6490
|
if (key === "timestamp" && typeof value === "string") {
|
|
6258
6491
|
return new Date(value);
|
|
@@ -6269,7 +6502,7 @@ var WorkflowEngine = class {
|
|
|
6269
6502
|
async saveSnapshots() {
|
|
6270
6503
|
const snapshotsPath = path4__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
6271
6504
|
const data = Array.from(this.snapshots.values());
|
|
6272
|
-
await
|
|
6505
|
+
await fs9__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
|
|
6273
6506
|
}
|
|
6274
6507
|
async createSnapshot() {
|
|
6275
6508
|
if (!this.state) return;
|
|
@@ -6290,7 +6523,7 @@ var WorkflowEngine = class {
|
|
|
6290
6523
|
async createChangeRecord() {
|
|
6291
6524
|
if (!this.state) return;
|
|
6292
6525
|
const changePath = path4__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
6293
|
-
await
|
|
6526
|
+
await fs9__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
6294
6527
|
}
|
|
6295
6528
|
async updateChangeRecord(status) {
|
|
6296
6529
|
if (!this.state) return;
|
|
@@ -6298,7 +6531,7 @@ var WorkflowEngine = class {
|
|
|
6298
6531
|
this.state.status = status;
|
|
6299
6532
|
}
|
|
6300
6533
|
const changePath = path4__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
6301
|
-
await
|
|
6534
|
+
await fs9__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
6302
6535
|
}
|
|
6303
6536
|
formatChangeRecord() {
|
|
6304
6537
|
if (!this.state) return "";
|
|
@@ -6362,7 +6595,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
|
|
|
6362
6595
|
|
|
6363
6596
|
${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
6364
6597
|
`;
|
|
6365
|
-
await
|
|
6598
|
+
await fs9__namespace.writeFile(specPath, content);
|
|
6366
6599
|
}
|
|
6367
6600
|
};
|
|
6368
6601
|
var ConfirmationRequiredError = class extends Error {
|
|
@@ -6411,11 +6644,11 @@ var NormsManager = class {
|
|
|
6411
6644
|
const files = await this.collectProjectFiles(projectPath);
|
|
6412
6645
|
for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
|
|
6413
6646
|
try {
|
|
6414
|
-
const stats = await
|
|
6647
|
+
const stats = await fs9__namespace.stat(filePath);
|
|
6415
6648
|
if (stats.size > MAX_FILE_SIZE) {
|
|
6416
6649
|
continue;
|
|
6417
6650
|
}
|
|
6418
|
-
const content = await
|
|
6651
|
+
const content = await fs9__namespace.readFile(filePath, "utf-8");
|
|
6419
6652
|
const patterns = await this.learnFromFile(filePath, content);
|
|
6420
6653
|
result.patternsFound += patterns.length;
|
|
6421
6654
|
result.filesScanned++;
|
|
@@ -7041,7 +7274,7 @@ ${response}`;
|
|
|
7041
7274
|
const files = [];
|
|
7042
7275
|
async function scan(dir) {
|
|
7043
7276
|
try {
|
|
7044
|
-
const entries = await
|
|
7277
|
+
const entries = await fs9__namespace.readdir(dir, { withFileTypes: true });
|
|
7045
7278
|
for (const entry of entries) {
|
|
7046
7279
|
if (entry.isDirectory()) {
|
|
7047
7280
|
if (!IGNORED_DIRS.includes(entry.name)) {
|
|
@@ -7084,8 +7317,8 @@ ${response}`;
|
|
|
7084
7317
|
* 确保规范目录存在
|
|
7085
7318
|
*/
|
|
7086
7319
|
async ensureNormsDir() {
|
|
7087
|
-
await
|
|
7088
|
-
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 });
|
|
7089
7322
|
}
|
|
7090
7323
|
/**
|
|
7091
7324
|
* 加载已有规范
|
|
@@ -7093,7 +7326,7 @@ ${response}`;
|
|
|
7093
7326
|
async loadStandards() {
|
|
7094
7327
|
const standardsPath = path4__namespace.join(this.config.normsDir, "patterns.json");
|
|
7095
7328
|
try {
|
|
7096
|
-
const content = await
|
|
7329
|
+
const content = await fs9__namespace.readFile(standardsPath, "utf-8");
|
|
7097
7330
|
const data = JSON.parse(content);
|
|
7098
7331
|
for (const standard of data) {
|
|
7099
7332
|
this.standards.set(standard.id, {
|
|
@@ -7111,7 +7344,7 @@ ${response}`;
|
|
|
7111
7344
|
async loadWeights() {
|
|
7112
7345
|
const weightsPath = path4__namespace.join(this.config.normsDir, "weights.json");
|
|
7113
7346
|
try {
|
|
7114
|
-
const content = await
|
|
7347
|
+
const content = await fs9__namespace.readFile(weightsPath, "utf-8");
|
|
7115
7348
|
const data = JSON.parse(content);
|
|
7116
7349
|
for (const weight of data) {
|
|
7117
7350
|
this.weights.set(weight.standardId, {
|
|
@@ -7127,7 +7360,7 @@ ${response}`;
|
|
|
7127
7360
|
*/
|
|
7128
7361
|
async saveStandards() {
|
|
7129
7362
|
const standardsPath = path4__namespace.join(this.config.normsDir, "patterns.json");
|
|
7130
|
-
await
|
|
7363
|
+
await fs9__namespace.writeFile(
|
|
7131
7364
|
standardsPath,
|
|
7132
7365
|
JSON.stringify(Array.from(this.standards.values()), null, 2),
|
|
7133
7366
|
"utf-8"
|
|
@@ -7138,7 +7371,7 @@ ${response}`;
|
|
|
7138
7371
|
*/
|
|
7139
7372
|
async saveWeights() {
|
|
7140
7373
|
const weightsPath = path4__namespace.join(this.config.normsDir, "weights.json");
|
|
7141
|
-
await
|
|
7374
|
+
await fs9__namespace.writeFile(
|
|
7142
7375
|
weightsPath,
|
|
7143
7376
|
JSON.stringify(Array.from(this.weights.values()), null, 2),
|
|
7144
7377
|
"utf-8"
|
|
@@ -7166,7 +7399,7 @@ ${response}`;
|
|
|
7166
7399
|
*/
|
|
7167
7400
|
async saveWeeklyReport(weekId, report) {
|
|
7168
7401
|
const reportPath = path4__namespace.join(this.config.normsDir, "weekly", `${weekId}.json`);
|
|
7169
|
-
await
|
|
7402
|
+
await fs9__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
|
|
7170
7403
|
}
|
|
7171
7404
|
/**
|
|
7172
7405
|
* 更新 devstanded.md
|
|
@@ -7175,7 +7408,7 @@ ${response}`;
|
|
|
7175
7408
|
const standards = this.getEffectiveStandards();
|
|
7176
7409
|
const content = this.generateDevStandedMd(standards);
|
|
7177
7410
|
const mdPath = path4__namespace.join(this.config.normsDir, "devstanded.md");
|
|
7178
|
-
await
|
|
7411
|
+
await fs9__namespace.writeFile(mdPath, content, "utf-8");
|
|
7179
7412
|
}
|
|
7180
7413
|
/**
|
|
7181
7414
|
* 生成 devstanded.md 内容
|
|
@@ -7567,14 +7800,14 @@ ${summary}`,
|
|
|
7567
7800
|
async persist() {
|
|
7568
7801
|
if (!this.persistPath) return;
|
|
7569
7802
|
const dir = path4__namespace.dirname(this.persistPath);
|
|
7570
|
-
await
|
|
7803
|
+
await fs9__namespace.mkdir(dir, { recursive: true });
|
|
7571
7804
|
const data = {
|
|
7572
7805
|
messages: this.state.messages,
|
|
7573
7806
|
totalTokens: this.state.totalTokens,
|
|
7574
7807
|
limit: this.state.limit,
|
|
7575
7808
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7576
7809
|
};
|
|
7577
|
-
await
|
|
7810
|
+
await fs9__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
|
|
7578
7811
|
}
|
|
7579
7812
|
/**
|
|
7580
7813
|
* 加载持久化的上下文
|
|
@@ -7582,7 +7815,7 @@ ${summary}`,
|
|
|
7582
7815
|
async loadPersistedContext() {
|
|
7583
7816
|
if (!this.persistPath) return;
|
|
7584
7817
|
try {
|
|
7585
|
-
const content = await
|
|
7818
|
+
const content = await fs9__namespace.readFile(this.persistPath, "utf-8");
|
|
7586
7819
|
const data = JSON.parse(content);
|
|
7587
7820
|
this.state.messages = data.messages || [];
|
|
7588
7821
|
this.state.totalTokens = data.totalTokens || 0;
|
|
@@ -7799,7 +8032,7 @@ async function handleInit(args, ctx) {
|
|
|
7799
8032
|
async function initProject(options = {}, workingDir) {
|
|
7800
8033
|
const cwd = workingDir || process.cwd();
|
|
7801
8034
|
try {
|
|
7802
|
-
const stats = await
|
|
8035
|
+
const stats = await fs9__namespace.stat(cwd);
|
|
7803
8036
|
if (!stats.isDirectory()) {
|
|
7804
8037
|
return {
|
|
7805
8038
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
@@ -7831,7 +8064,7 @@ async function initProject(options = {}, workingDir) {
|
|
|
7831
8064
|
await normsManager.initialize();
|
|
7832
8065
|
const scanResult = await normsManager.scanProject(cwd);
|
|
7833
8066
|
const agentsContent = generateAgentsMd(projectInfo, scanResult);
|
|
7834
|
-
await
|
|
8067
|
+
await fs9__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
|
|
7835
8068
|
await generateOpenSpecConfig(openspecDir, projectInfo);
|
|
7836
8069
|
return {
|
|
7837
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}
|
|
@@ -7872,7 +8105,7 @@ async function createSfCliDirectory(basePath) {
|
|
|
7872
8105
|
"logs"
|
|
7873
8106
|
];
|
|
7874
8107
|
for (const dir of dirs) {
|
|
7875
|
-
await
|
|
8108
|
+
await fs9__namespace.mkdir(path4__namespace.join(basePath, dir), { recursive: true });
|
|
7876
8109
|
}
|
|
7877
8110
|
const config = {
|
|
7878
8111
|
version: "1.0.0",
|
|
@@ -7880,22 +8113,22 @@ async function createSfCliDirectory(basePath) {
|
|
|
7880
8113
|
yolo: false,
|
|
7881
8114
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7882
8115
|
};
|
|
7883
|
-
await
|
|
8116
|
+
await fs9__namespace.writeFile(
|
|
7884
8117
|
path4__namespace.join(basePath, "config.json"),
|
|
7885
8118
|
JSON.stringify(config, null, 2),
|
|
7886
8119
|
"utf-8"
|
|
7887
8120
|
);
|
|
7888
|
-
await
|
|
8121
|
+
await fs9__namespace.writeFile(
|
|
7889
8122
|
path4__namespace.join(basePath, "agents", "registry.json"),
|
|
7890
8123
|
JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
|
|
7891
8124
|
"utf-8"
|
|
7892
8125
|
);
|
|
7893
|
-
await
|
|
8126
|
+
await fs9__namespace.writeFile(
|
|
7894
8127
|
path4__namespace.join(basePath, "skills", "registry.json"),
|
|
7895
8128
|
JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
|
|
7896
8129
|
"utf-8"
|
|
7897
8130
|
);
|
|
7898
|
-
await
|
|
8131
|
+
await fs9__namespace.writeFile(
|
|
7899
8132
|
path4__namespace.join(basePath, "health", "health.md"),
|
|
7900
8133
|
generateHealthTemplate(),
|
|
7901
8134
|
"utf-8"
|
|
@@ -7905,8 +8138,8 @@ async function createOpenSpecDirectory(basePath) {
|
|
|
7905
8138
|
const changesDir = path4__namespace.join(basePath, "changes");
|
|
7906
8139
|
const archiveDir = path4__namespace.join(changesDir, "archive");
|
|
7907
8140
|
const specDir = path4__namespace.join(basePath, "spec");
|
|
7908
|
-
await
|
|
7909
|
-
await
|
|
8141
|
+
await fs9__namespace.mkdir(archiveDir, { recursive: true });
|
|
8142
|
+
await fs9__namespace.mkdir(specDir, { recursive: true });
|
|
7910
8143
|
}
|
|
7911
8144
|
async function analyzeProject(cwd) {
|
|
7912
8145
|
const result = {
|
|
@@ -7931,7 +8164,7 @@ async function analyzeProject(cwd) {
|
|
|
7931
8164
|
};
|
|
7932
8165
|
const pkgPath = path4__namespace.join(cwd, "package.json");
|
|
7933
8166
|
try {
|
|
7934
|
-
const pkgContent = await
|
|
8167
|
+
const pkgContent = await fs9__namespace.readFile(pkgPath, "utf-8");
|
|
7935
8168
|
const pkg = JSON.parse(pkgContent);
|
|
7936
8169
|
result.name = pkg.name || result.name;
|
|
7937
8170
|
result.dependencies = pkg.dependencies || {};
|
|
@@ -8014,7 +8247,7 @@ async function analyzeDirectoryStructure(cwd) {
|
|
|
8014
8247
|
others: []
|
|
8015
8248
|
};
|
|
8016
8249
|
try {
|
|
8017
|
-
const entries = await
|
|
8250
|
+
const entries = await fs9__namespace.readdir(cwd, { withFileTypes: true });
|
|
8018
8251
|
for (const entry of entries) {
|
|
8019
8252
|
if (!entry.isDirectory()) continue;
|
|
8020
8253
|
const name = entry.name;
|
|
@@ -8059,7 +8292,7 @@ async function findEntryPoints(cwd) {
|
|
|
8059
8292
|
}
|
|
8060
8293
|
async function saveProjectAnalysis(sfCliDir, analysis) {
|
|
8061
8294
|
const analysisPath = path4__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
|
|
8062
|
-
await
|
|
8295
|
+
await fs9__namespace.writeFile(
|
|
8063
8296
|
analysisPath,
|
|
8064
8297
|
JSON.stringify(analysis, null, 2),
|
|
8065
8298
|
"utf-8"
|
|
@@ -8100,7 +8333,7 @@ architecture:
|
|
|
8100
8333
|
# \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
|
|
8101
8334
|
standards: []
|
|
8102
8335
|
`;
|
|
8103
|
-
await
|
|
8336
|
+
await fs9__namespace.writeFile(configPath, content, "utf-8");
|
|
8104
8337
|
}
|
|
8105
8338
|
function generateAgentsMd(info, scanResult) {
|
|
8106
8339
|
const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
|
|
@@ -8222,7 +8455,7 @@ function generateHealthTemplate() {
|
|
|
8222
8455
|
}
|
|
8223
8456
|
async function fileExists(filePath) {
|
|
8224
8457
|
try {
|
|
8225
|
-
await
|
|
8458
|
+
await fs9__namespace.access(filePath);
|
|
8226
8459
|
return true;
|
|
8227
8460
|
} catch {
|
|
8228
8461
|
return false;
|
|
@@ -9657,9 +9890,9 @@ async function handleFileReference(filePath, ctx) {
|
|
|
9657
9890
|
const cwd = ctx.options.workingDirectory;
|
|
9658
9891
|
const absolutePath = path4__namespace.isAbsolute(filePath) ? filePath : path4__namespace.join(cwd, filePath);
|
|
9659
9892
|
try {
|
|
9660
|
-
const stats = await
|
|
9893
|
+
const stats = await fs9__namespace.stat(absolutePath);
|
|
9661
9894
|
if (stats.isDirectory()) {
|
|
9662
|
-
const files = await
|
|
9895
|
+
const files = await fs9__namespace.readdir(absolutePath);
|
|
9663
9896
|
return {
|
|
9664
9897
|
output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
|
|
9665
9898
|
${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
|
|
@@ -9667,7 +9900,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
|
|
|
9667
9900
|
contextUsed: 0
|
|
9668
9901
|
};
|
|
9669
9902
|
}
|
|
9670
|
-
const content = await
|
|
9903
|
+
const content = await fs9__namespace.readFile(absolutePath, "utf-8");
|
|
9671
9904
|
const lines = content.split("\n");
|
|
9672
9905
|
ctx.contextManager.addMessage({
|
|
9673
9906
|
role: "user",
|
|
@@ -10096,7 +10329,7 @@ var Completer = class {
|
|
|
10096
10329
|
prefix = filePath.slice(lastSlash + 1);
|
|
10097
10330
|
}
|
|
10098
10331
|
try {
|
|
10099
|
-
const entries = await
|
|
10332
|
+
const entries = await fs9__namespace.readdir(dirPath, { withFileTypes: true });
|
|
10100
10333
|
const matches = [];
|
|
10101
10334
|
for (const entry of entries) {
|
|
10102
10335
|
if (entry.name.startsWith(prefix)) {
|