@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/index.mjs CHANGED
@@ -2,7 +2,7 @@ import * as path5 from 'path';
2
2
  import path5__default from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import chalk9 from 'chalk';
5
- import * as fs4 from 'fs/promises';
5
+ import * as fs9 from 'fs/promises';
6
6
  import * as fs10 from 'fs';
7
7
  import * as crypto from 'crypto';
8
8
  import * as os from 'os';
@@ -642,24 +642,13 @@ async function executeDevelopment(ctx, session) {
642
642
  loader.start();
643
643
  try {
644
644
  const taskPrompt = buildTaskPrompt(session, item, i);
645
+ const structureInfo = session.context?.projectStructure;
646
+ const structureGuide = buildStructureGuide(structureInfo);
647
+ const systemPrompt = buildCodeGenerationSystemPrompt(session, structureGuide);
645
648
  const messages = [
646
649
  {
647
650
  role: "system",
648
- content: `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u7A0B\u5E08\u3002\u8BF7\u6839\u636E\u4EFB\u52A1\u63CF\u8FF0\u751F\u6210\u4EE3\u7801\u5B9E\u73B0\u3002
649
-
650
- \u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
651
- 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
652
- 2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
653
- 3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
654
- 4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
655
-
656
- \u9879\u76EE\u4FE1\u606F\uFF1A
657
- - \u540D\u79F0: ${session.context?.name}
658
- - \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
659
- - \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
660
-
661
- ${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
662
- ${session.context.devStandards.slice(0, 2e3)}` : ""}`
651
+ content: systemPrompt
663
652
  },
664
653
  {
665
654
  role: "user",
@@ -679,17 +668,17 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
679
668
  for (const block of codeBlocks) {
680
669
  const filePath = path5.join(workingDir, block.filename);
681
670
  const dir = path5.dirname(filePath);
682
- await fs4.mkdir(dir, { recursive: true });
683
- await fs4.writeFile(filePath, block.code, "utf-8");
671
+ await fs9.mkdir(dir, { recursive: true });
672
+ await fs9.writeFile(filePath, block.code, "utf-8");
684
673
  files.push(block.filename);
685
674
  }
686
675
  loader.stop(chalk9.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
687
676
  } else {
688
677
  const implDir = path5.join(workingDir, "src");
689
- await fs4.mkdir(implDir, { recursive: true });
678
+ await fs9.mkdir(implDir, { recursive: true });
690
679
  const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
691
680
  const filePath = path5.join(implDir, fileName);
692
- await fs4.writeFile(filePath, `// TODO: ${item.title}
681
+ await fs9.writeFile(filePath, `// TODO: ${item.title}
693
682
  // ${item.description}
694
683
  `, "utf-8");
695
684
  files.push(`src/${fileName}`);
@@ -712,6 +701,91 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
712
701
  };
713
702
  }
714
703
  }
704
+ function buildStructureGuide(structure) {
705
+ if (!structure) {
706
+ return `## \u9879\u76EE\u7ED3\u6784
707
+ - \u7EC4\u4EF6\u653E\u5728 src/components/
708
+ - \u9875\u9762\u653E\u5728 src/pages/
709
+ - \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/`;
710
+ }
711
+ const lines = ["## \u9879\u76EE\u7ED3\u6784\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09"];
712
+ if (structure.hasSrc) {
713
+ lines.push(`- \u6E90\u7801\u76EE\u5F55: ${structure.srcDir}/`);
714
+ }
715
+ if (structure.hasPages) {
716
+ lines.push(`- \u9875\u9762\u76EE\u5F55: ${structure.pagesDir}/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
717
+ } else {
718
+ lines.push(`- \u9875\u9762\u76EE\u5F55: src/pages/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
719
+ }
720
+ if (structure.hasComponents) {
721
+ lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: ${structure.componentsDir}/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
722
+ } else {
723
+ lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: src/components/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
724
+ }
725
+ if (structure.hasApi) {
726
+ lines.push(`- API \u76EE\u5F55: src/api/ \u6216 src/services/`);
727
+ }
728
+ if (structure.hasHooks) {
729
+ lines.push(`- Hooks \u76EE\u5F55: src/hooks/`);
730
+ }
731
+ if (structure.hasStore) {
732
+ lines.push(`- \u72B6\u6001\u7BA1\u7406\u76EE\u5F55: src/store/`);
733
+ }
734
+ if (structure.hasUtils) {
735
+ lines.push(`- \u5DE5\u5177\u51FD\u6570\u76EE\u5F55: src/utils/`);
736
+ }
737
+ lines.push("");
738
+ 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");
739
+ return lines.join("\n");
740
+ }
741
+ function buildCodeGenerationSystemPrompt(session, structureGuide) {
742
+ const framework = session.context?.framework || "React";
743
+ const techStack = session.context?.techStack?.join(", ") || "TypeScript";
744
+ const devStandards = session.context?.devStandards || "";
745
+ const standardsText = devStandards.slice(0, 6e3);
746
+ 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
747
+
748
+ ## \u26A0\uFE0F \u6838\u5FC3\u89C4\u5219\uFF08\u5FC5\u987B\u9075\u5B88\uFF09
749
+
750
+ 1. **\u8BED\u8A00**: \u5FC5\u987B\u4F7F\u7528 TypeScript (.tsx/.ts \u6587\u4EF6)
751
+ 2. **\u6846\u67B6**: ${framework}
752
+ 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
753
+ 4. **\u6587\u4EF6\u8DEF\u5F84\u5FC5\u987B\u6B63\u786E**\uFF1A\u4E25\u683C\u6309\u7167\u9879\u76EE\u7ED3\u6784\u653E\u7F6E\u6587\u4EF6
754
+ 5. **\u5FC5\u987B\u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801**\uFF0C\u4E0D\u8981\u5199 TODO \u6216\u5360\u4F4D\u7B26
755
+ 6. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA\u9875\u9762**\uFF0C\u5FC5\u987B\u751F\u6210\u9875\u9762\u7EC4\u4EF6
756
+ 7. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA UI**\uFF0C\u5FC5\u987B\u751F\u6210\u5BF9\u5E94\u7684\u7EC4\u4EF6\u548C\u6837\u5F0F
757
+
758
+ ${structureGuide}
759
+
760
+ ## \u9879\u76EE\u4FE1\u606F
761
+
762
+ - \u540D\u79F0: ${session.context?.name || "\u672A\u547D\u540D\u9879\u76EE"}
763
+ - \u6846\u67B6: ${framework}
764
+ - \u6280\u672F\u6808: ${techStack}
765
+
766
+ ## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
767
+
768
+ ${standardsText || `### \u9ED8\u8BA4\u89C4\u8303
769
+ - \u4F7F\u7528\u51FD\u6570\u5F0F\u7EC4\u4EF6
770
+ - \u4F7F\u7528 TypeScript \u7C7B\u578B\u5B9A\u4E49
771
+ - \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65
772
+ - \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase
773
+ - \u5BFC\u51FA\u4F7F\u7528 export default \u6216 export const`}
774
+
775
+ ## \u8F93\u51FA\u683C\u5F0F
776
+
777
+ \u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u5305\u88F9\uFF0C\u4F8B\u5982\uFF1A
778
+
779
+ \`\`\`src/pages/HomePage.tsx
780
+ // \u4EE3\u7801\u5185\u5BB9
781
+ \`\`\`
782
+
783
+ \`\`\`src/components/Button/Button.tsx
784
+ // \u4EE3\u7801\u5185\u5BB9
785
+ \`\`\`
786
+
787
+ \u73B0\u5728\u8BF7\u6839\u636E\u4EFB\u52A1\u8981\u6C42\u751F\u6210\u4EE3\u7801\u3002`;
788
+ }
715
789
  function buildTaskPrompt(session, item, index) {
716
790
  const lines = [];
717
791
  lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
@@ -766,7 +840,7 @@ async function executeReview(ctx, session) {
766
840
  const codeContents = [];
767
841
  for (const file of session.implFiles) {
768
842
  try {
769
- const content = await fs4.readFile(path5.join(workingDir, file), "utf-8");
843
+ const content = await fs9.readFile(path5.join(workingDir, file), "utf-8");
770
844
  codeContents.push(`// ${file}
771
845
  ${content}`);
772
846
  } catch {
@@ -775,7 +849,7 @@ ${content}`);
775
849
  const testContents = [];
776
850
  for (const file of session.testFiles) {
777
851
  try {
778
- const content = await fs4.readFile(path5.join(workingDir, file), "utf-8");
852
+ const content = await fs9.readFile(path5.join(workingDir, file), "utf-8");
779
853
  testContents.push(`// ${file}
780
854
  ${content}`);
781
855
  } catch {
@@ -869,9 +943,9 @@ async function readProjectContext(workingDir) {
869
943
  };
870
944
  const agentsPath = path5.join(workingDir, "AGENTS.md");
871
945
  try {
872
- const stats = await fs4.stat(agentsPath);
946
+ const stats = await fs9.stat(agentsPath);
873
947
  if (stats.size <= MAX_FILE_SIZE2) {
874
- context.agentsMd = await fs4.readFile(agentsPath, "utf-8");
948
+ context.agentsMd = await fs9.readFile(agentsPath, "utf-8");
875
949
  const nameMatch = context.agentsMd.match(/\|\s*项目名称\s*\|\s*([^\s|]+)/);
876
950
  if (nameMatch) context.name = nameMatch[1];
877
951
  const typeMatch = context.agentsMd.match(/\|\s*项目类型\s*\|\s*([^\s|]+)/);
@@ -885,9 +959,9 @@ async function readProjectContext(workingDir) {
885
959
  }
886
960
  const configPath = path5.join(workingDir, "openspec", "config.yaml");
887
961
  try {
888
- const stats = await fs4.stat(configPath);
962
+ const stats = await fs9.stat(configPath);
889
963
  if (stats.size <= MAX_FILE_SIZE2) {
890
- context.configYaml = await fs4.readFile(configPath, "utf-8");
964
+ context.configYaml = await fs9.readFile(configPath, "utf-8");
891
965
  const nameMatch = context.configYaml.match(/name:\s*(.+)/);
892
966
  if (nameMatch) context.name = nameMatch[1].trim();
893
967
  const typeMatch = context.configYaml.match(/type:\s*(.+)/);
@@ -908,14 +982,173 @@ async function readProjectContext(workingDir) {
908
982
  }
909
983
  const devStandardsPath = path5.join(workingDir, ".sf-cli", "norms", "devstanded.md");
910
984
  try {
911
- const stats = await fs4.stat(devStandardsPath);
985
+ const stats = await fs9.stat(devStandardsPath);
912
986
  if (stats.size <= MAX_FILE_SIZE2) {
913
- context.devStandards = await fs4.readFile(devStandardsPath, "utf-8");
987
+ context.devStandards = await fs9.readFile(devStandardsPath, "utf-8");
914
988
  }
915
989
  } catch {
916
990
  }
991
+ if (!context.framework) {
992
+ const detectedFramework = await detectFramework2(workingDir);
993
+ if (detectedFramework) {
994
+ context.framework = detectedFramework;
995
+ context.techStack = [detectedFramework, ...context.techStack.filter((t) => t !== detectedFramework)];
996
+ }
997
+ }
998
+ if (!context.devStandards) {
999
+ context.devStandards = await analyzeProjectForStandards(workingDir, context);
1000
+ }
1001
+ context.projectStructure = await analyzeProjectStructure(workingDir);
917
1002
  return context;
918
1003
  }
1004
+ async function detectFramework2(workingDir) {
1005
+ try {
1006
+ const pkgPath = path5.join(workingDir, "package.json");
1007
+ const pkgContent = await fs9.readFile(pkgPath, "utf-8");
1008
+ const pkg = JSON.parse(pkgContent);
1009
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
1010
+ if (deps["react"] || deps["next"]) return "React";
1011
+ if (deps["vue"] || deps["nuxt"]) return "Vue";
1012
+ if (deps["angular"] || deps["@angular/core"]) return "Angular";
1013
+ if (deps["svelte"]) return "Svelte";
1014
+ if (deps["solid-js"]) return "Solid";
1015
+ if (deps["vite"] || deps["webpack"]) return "JavaScript";
1016
+ if (deps["typescript"]) return "TypeScript";
1017
+ return null;
1018
+ } catch {
1019
+ return null;
1020
+ }
1021
+ }
1022
+ async function analyzeProjectForStandards(workingDir, context) {
1023
+ const standards = [];
1024
+ standards.push(`# \u9879\u76EE\u5F00\u53D1\u89C4\u8303\uFF08\u81EA\u52A8\u751F\u6210\uFF09
1025
+ > \u9879\u76EE\u540D\u79F0: ${context.name}
1026
+ > \u6846\u67B6: ${context.framework || "\u672A\u68C0\u6D4B\u5230"}
1027
+ > \u6280\u672F\u6808: ${context.techStack.join(", ") || "\u672A\u68C0\u6D4B\u5230"}
1028
+ `);
1029
+ try {
1030
+ const tsConfigPath = path5.join(workingDir, "tsconfig.json");
1031
+ await fs9.access(tsConfigPath);
1032
+ standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 TypeScript");
1033
+ } catch {
1034
+ standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 JavaScript");
1035
+ }
1036
+ try {
1037
+ const srcDir = path5.join(workingDir, "src");
1038
+ const files = await listFilesDeep(srcDir);
1039
+ const hasCss = files.some((f) => f.endsWith(".css"));
1040
+ const hasScss = files.some((f) => f.endsWith(".scss") || f.endsWith(".sass"));
1041
+ const hasLess = files.some((f) => f.endsWith(".less"));
1042
+ const hasStyled = files.some((f) => f.includes(".styled.") || f.includes("styled-components"));
1043
+ if (hasScss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 SCSS/Sass");
1044
+ else if (hasLess) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 Less");
1045
+ else if (hasStyled) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 styled-components");
1046
+ else if (hasCss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 CSS");
1047
+ } catch {
1048
+ }
1049
+ try {
1050
+ const srcDir = path5.join(workingDir, "src");
1051
+ const entries = await fs9.readdir(srcDir, { withFileTypes: true });
1052
+ const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
1053
+ if (dirs.includes("components")) standards.push("\n## \u76EE\u5F55\u7ED3\u6784\n- \u7EC4\u4EF6\u653E\u5728 src/components/");
1054
+ if (dirs.includes("pages") || dirs.includes("views")) standards.push("- \u9875\u9762\u653E\u5728 src/pages/ \u6216 src/views/");
1055
+ if (dirs.includes("hooks")) standards.push("- Hooks \u653E\u5728 src/hooks/");
1056
+ if (dirs.includes("utils")) standards.push("- \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/");
1057
+ if (dirs.includes("api") || dirs.includes("services")) standards.push("- API \u8C03\u7528\u653E\u5728 src/api/ \u6216 src/services/");
1058
+ if (dirs.includes("store") || dirs.includes("stores")) standards.push("- \u72B6\u6001\u7BA1\u7406\u653E\u5728 src/store/");
1059
+ } catch {
1060
+ }
1061
+ standards.push("\n## \u4EE3\u7801\u89C4\u8303");
1062
+ standards.push("- \u4F7F\u7528 ES6+ \u8BED\u6CD5");
1063
+ standards.push("- \u7EC4\u4EF6\u4F7F\u7528\u51FD\u6570\u5F0F\u5199\u6CD5");
1064
+ standards.push("- \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65");
1065
+ standards.push("- \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase");
1066
+ standards.push("- \u5E38\u91CF\u4F7F\u7528 UPPER_SNAKE_CASE");
1067
+ return standards.join("\n");
1068
+ }
1069
+ async function listFilesDeep(dir, maxDepth = 3) {
1070
+ const files = [];
1071
+ async function scan(currentDir, depth) {
1072
+ if (depth > maxDepth) return;
1073
+ try {
1074
+ const entries = await fs9.readdir(currentDir, { withFileTypes: true });
1075
+ for (const entry of entries) {
1076
+ if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
1077
+ const fullPath = path5.join(currentDir, entry.name);
1078
+ if (entry.isDirectory()) {
1079
+ await scan(fullPath, depth + 1);
1080
+ } else {
1081
+ files.push(fullPath);
1082
+ }
1083
+ }
1084
+ } catch {
1085
+ }
1086
+ }
1087
+ await scan(dir, 0);
1088
+ return files;
1089
+ }
1090
+ async function analyzeProjectStructure(workingDir) {
1091
+ const structure = {
1092
+ hasSrc: false,
1093
+ hasPages: false,
1094
+ hasComponents: false,
1095
+ hasApi: false,
1096
+ hasHooks: false,
1097
+ hasStore: false,
1098
+ hasUtils: false,
1099
+ srcDir: "src",
1100
+ pagesDir: "",
1101
+ componentsDir: ""
1102
+ };
1103
+ try {
1104
+ const srcDir = path5.join(workingDir, "src");
1105
+ try {
1106
+ const srcStat = await fs9.stat(srcDir);
1107
+ if (srcStat.isDirectory()) {
1108
+ structure.hasSrc = true;
1109
+ structure.srcDir = "src";
1110
+ const srcEntries = await fs9.readdir(srcDir, { withFileTypes: true });
1111
+ const srcDirs = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name);
1112
+ if (srcDirs.includes("pages")) {
1113
+ structure.hasPages = true;
1114
+ structure.pagesDir = "src/pages";
1115
+ } else if (srcDirs.includes("views")) {
1116
+ structure.hasPages = true;
1117
+ structure.pagesDir = "src/views";
1118
+ }
1119
+ if (srcDirs.includes("components")) {
1120
+ structure.hasComponents = true;
1121
+ structure.componentsDir = "src/components";
1122
+ }
1123
+ if (srcDirs.includes("api") || srcDirs.includes("services")) {
1124
+ structure.hasApi = true;
1125
+ }
1126
+ if (srcDirs.includes("hooks")) {
1127
+ structure.hasHooks = true;
1128
+ }
1129
+ if (srcDirs.includes("store") || srcDirs.includes("stores")) {
1130
+ structure.hasStore = true;
1131
+ }
1132
+ if (srcDirs.includes("utils")) {
1133
+ structure.hasUtils = true;
1134
+ }
1135
+ }
1136
+ } catch {
1137
+ const rootEntries = await fs9.readdir(workingDir, { withFileTypes: true });
1138
+ const rootDirs = rootEntries.filter((e) => e.isDirectory()).map((e) => e.name);
1139
+ if (rootDirs.includes("pages")) {
1140
+ structure.hasPages = true;
1141
+ structure.pagesDir = "pages";
1142
+ }
1143
+ if (rootDirs.includes("components")) {
1144
+ structure.hasComponents = true;
1145
+ structure.componentsDir = "components";
1146
+ }
1147
+ }
1148
+ } catch {
1149
+ }
1150
+ return structure;
1151
+ }
919
1152
  function analyzeComplexity(requirement, context) {
920
1153
  let score = 3;
921
1154
  if (requirement.length > 100) score += 1;
@@ -1404,10 +1637,10 @@ ${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
1404
1637
  }
1405
1638
  async function saveSpecFile(workingDir, session) {
1406
1639
  const specDir = path5.join(workingDir, "openspec", "changes");
1407
- await fs4.mkdir(specDir, { recursive: true });
1640
+ await fs9.mkdir(specDir, { recursive: true });
1408
1641
  const specPath = path5.join(specDir, `${session.id}-spec.md`);
1409
1642
  const content = formatSpecFile(session);
1410
- await fs4.writeFile(specPath, content, "utf-8");
1643
+ await fs9.writeFile(specPath, content, "utf-8");
1411
1644
  return specPath;
1412
1645
  }
1413
1646
  function formatSpecFile(session) {
@@ -1492,7 +1725,7 @@ function formatSpecFile(session) {
1492
1725
  }
1493
1726
  async function generateTests(workingDir, session, ctx) {
1494
1727
  const testDir = path5.join(workingDir, "tests");
1495
- await fs4.mkdir(testDir, { recursive: true });
1728
+ await fs9.mkdir(testDir, { recursive: true });
1496
1729
  const testFiles = [];
1497
1730
  if (ctx?.modelService) {
1498
1731
  for (const scenario of session.bddScenarios) {
@@ -1502,12 +1735,12 @@ async function generateTests(workingDir, session, ctx) {
1502
1735
  loader.start();
1503
1736
  try {
1504
1737
  const content = await generateTestFileWithAI(scenario, session, ctx);
1505
- await fs4.writeFile(testPath, content, "utf-8");
1738
+ await fs9.writeFile(testPath, content, "utf-8");
1506
1739
  testFiles.push(`tests/${testName}.test.ts`);
1507
1740
  loader.stop(chalk9.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
1508
1741
  } catch {
1509
1742
  const content = generateTestFile(scenario, session);
1510
- await fs4.writeFile(testPath, content, "utf-8");
1743
+ await fs9.writeFile(testPath, content, "utf-8");
1511
1744
  testFiles.push(`tests/${testName}.test.ts`);
1512
1745
  loader.stop(chalk9.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
1513
1746
  }
@@ -1517,7 +1750,7 @@ async function generateTests(workingDir, session, ctx) {
1517
1750
  const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
1518
1751
  const testPath = path5.join(testDir, `${testName}.test.ts`);
1519
1752
  const content = generateTestFile(scenario, session);
1520
- await fs4.writeFile(testPath, content, "utf-8");
1753
+ await fs9.writeFile(testPath, content, "utf-8");
1521
1754
  testFiles.push(`tests/${testName}.test.ts`);
1522
1755
  }
1523
1756
  }
@@ -1611,7 +1844,7 @@ function generateTestFile(scenario, session) {
1611
1844
  async function archiveWorkflow(workingDir) {
1612
1845
  if (!activeSession) return;
1613
1846
  const archiveDir = path5.join(workingDir, "openspec", "spec");
1614
- await fs4.mkdir(archiveDir, { recursive: true });
1847
+ await fs9.mkdir(archiveDir, { recursive: true });
1615
1848
  const archivePath = path5.join(archiveDir, `${activeSession.id}.md`);
1616
1849
  const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
1617
1850
 
@@ -1638,7 +1871,7 @@ ${activeSession.refinedRequirement}
1638
1871
 
1639
1872
  ${activeSession.testFiles.map((f) => `- ${f}`).join("\n") || "\u65E0"}
1640
1873
  `;
1641
- await fs4.writeFile(archivePath, content, "utf-8");
1874
+ await fs9.writeFile(archivePath, content, "utf-8");
1642
1875
  }
1643
1876
  function generateSessionId() {
1644
1877
  const timestamp = Date.now().toString(36);
@@ -1914,7 +2147,7 @@ var ConfigManager = class {
1914
2147
  this.projectPath = projectPath;
1915
2148
  this.configPath = path5.join(projectPath, ".sf-cli", "config.json");
1916
2149
  try {
1917
- const content = await fs4.readFile(this.configPath, "utf-8");
2150
+ const content = await fs9.readFile(this.configPath, "utf-8");
1918
2151
  const loaded = JSON.parse(content);
1919
2152
  if (loaded.apiKey && loaded.apiKeyEncrypted) {
1920
2153
  loaded.apiKey = this.decrypt(loaded.apiKey);
@@ -1933,8 +2166,8 @@ var ConfigManager = class {
1933
2166
  configToSave.apiKey = encrypted;
1934
2167
  configToSave.apiKeyEncrypted = true;
1935
2168
  }
1936
- await fs4.mkdir(path5.dirname(this.configPath), { recursive: true });
1937
- await fs4.writeFile(
2169
+ await fs9.mkdir(path5.dirname(this.configPath), { recursive: true });
2170
+ await fs9.writeFile(
1938
2171
  this.configPath,
1939
2172
  JSON.stringify(configToSave, null, 2),
1940
2173
  "utf-8"
@@ -3032,8 +3265,8 @@ var ModelService = class {
3032
3265
  const dailyPath = path5.join(this.statsPath, "daily.json");
3033
3266
  const totalPath = path5.join(this.statsPath, "total.json");
3034
3267
  const [daily, total] = await Promise.all([
3035
- fs4.readFile(dailyPath, "utf-8").catch(() => "{}"),
3036
- fs4.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
3268
+ fs9.readFile(dailyPath, "utf-8").catch(() => "{}"),
3269
+ fs9.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
3037
3270
  ]);
3038
3271
  const dailyData = JSON.parse(daily);
3039
3272
  const totalData = JSON.parse(total);
@@ -3046,12 +3279,12 @@ var ModelService = class {
3046
3279
  async saveStats() {
3047
3280
  if (!this.statsPath) return;
3048
3281
  try {
3049
- await fs4.mkdir(this.statsPath, { recursive: true });
3282
+ await fs9.mkdir(this.statsPath, { recursive: true });
3050
3283
  const dailyPath = path5.join(this.statsPath, "daily.json");
3051
3284
  const totalPath = path5.join(this.statsPath, "total.json");
3052
3285
  await Promise.all([
3053
- fs4.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
3054
- fs4.writeFile(totalPath, JSON.stringify({
3286
+ fs9.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
3287
+ fs9.writeFile(totalPath, JSON.stringify({
3055
3288
  totalInput: this.stats.totalInput,
3056
3289
  totalOutput: this.stats.totalOutput
3057
3290
  }))
@@ -4760,15 +4993,15 @@ async function loadProjectContext(workingDirectory) {
4760
4993
  devStandards: ""
4761
4994
  };
4762
4995
  try {
4763
- context.agentsMd = await fs4.readFile(path5.join(workingDirectory, "AGENTS.md"), "utf-8");
4996
+ context.agentsMd = await fs9.readFile(path5.join(workingDirectory, "AGENTS.md"), "utf-8");
4764
4997
  } catch {
4765
4998
  }
4766
4999
  try {
4767
- context.configYaml = await fs4.readFile(path5.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
5000
+ context.configYaml = await fs9.readFile(path5.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
4768
5001
  } catch {
4769
5002
  }
4770
5003
  try {
4771
- context.devStandards = await fs4.readFile(path5.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
5004
+ context.devStandards = await fs9.readFile(path5.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
4772
5005
  } catch {
4773
5006
  }
4774
5007
  return context;
@@ -5731,19 +5964,19 @@ var WorkflowEngine = class {
5731
5964
  async loadProjectContext() {
5732
5965
  const agentsMdPath = path5.join(this.projectPath, "AGENTS.md");
5733
5966
  try {
5734
- this.projectContext = await fs4.readFile(agentsMdPath, "utf-8");
5967
+ this.projectContext = await fs9.readFile(agentsMdPath, "utf-8");
5735
5968
  } catch {
5736
5969
  this.projectContext = "";
5737
5970
  }
5738
5971
  const configPath = path5.join(this.openspecPath, "config.yaml");
5739
5972
  try {
5740
- this.projectConfig = await fs4.readFile(configPath, "utf-8");
5973
+ this.projectConfig = await fs9.readFile(configPath, "utf-8");
5741
5974
  } catch {
5742
5975
  this.projectConfig = "";
5743
5976
  }
5744
5977
  const devstandedPath = path5.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
5745
5978
  try {
5746
- this.devStandards = await fs4.readFile(devstandedPath, "utf-8");
5979
+ this.devStandards = await fs9.readFile(devstandedPath, "utf-8");
5747
5980
  } catch {
5748
5981
  this.devStandards = "";
5749
5982
  }
@@ -5772,7 +6005,7 @@ var WorkflowEngine = class {
5772
6005
  const specPath = this.getSpecFilePath();
5773
6006
  if (!specPath) return false;
5774
6007
  try {
5775
- await fs4.access(specPath);
6008
+ await fs9.access(specPath);
5776
6009
  return true;
5777
6010
  } catch {
5778
6011
  return false;
@@ -6006,11 +6239,11 @@ var WorkflowEngine = class {
6006
6239
  const workflows = [];
6007
6240
  const changesDir = path5.join(this.openspecPath, "changes");
6008
6241
  try {
6009
- const files = await fs4.readdir(changesDir);
6242
+ const files = await fs9.readdir(changesDir);
6010
6243
  for (const file of files) {
6011
6244
  if (!file.endsWith(".md") || file.includes("-spec.md")) continue;
6012
6245
  const filePath = path5.join(changesDir, file);
6013
- const content = await fs4.readFile(filePath, "utf-8");
6246
+ const content = await fs9.readFile(filePath, "utf-8");
6014
6247
  const state = this.parseChangeRecord(content);
6015
6248
  if (state && state.status === "running") {
6016
6249
  workflows.push(state);
@@ -6061,7 +6294,7 @@ var WorkflowEngine = class {
6061
6294
  }
6062
6295
  const statePath = path5.join(this.openspecPath, ".workflow-states", `${changeId}.json`);
6063
6296
  try {
6064
- const content = await fs4.readFile(statePath, "utf-8");
6297
+ const content = await fs9.readFile(statePath, "utf-8");
6065
6298
  this.state = JSON.parse(content, (key, value) => {
6066
6299
  if (key.endsWith("At") && typeof value === "string") {
6067
6300
  return new Date(value);
@@ -6074,7 +6307,7 @@ var WorkflowEngine = class {
6074
6307
  const changesDir = path5.join(this.openspecPath, "changes");
6075
6308
  const changeFile = path5.join(changesDir, `${changeId}.md`);
6076
6309
  try {
6077
- const content = await fs4.readFile(changeFile, "utf-8");
6310
+ const content = await fs9.readFile(changeFile, "utf-8");
6078
6311
  const parsed = this.parseChangeRecord(content);
6079
6312
  if (parsed && parsed.status === "running") {
6080
6313
  this.state = parsed;
@@ -6139,8 +6372,8 @@ var WorkflowEngine = class {
6139
6372
  const archiveDir = path5.join(changesDir, "archive");
6140
6373
  const changeFile = path5.join(changesDir, `${changeId}.md`);
6141
6374
  const archiveFile = path5.join(archiveDir, `${changeId}.md`);
6142
- await fs4.mkdir(archiveDir, { recursive: true });
6143
- await fs4.rename(changeFile, archiveFile).catch(() => {
6375
+ await fs9.mkdir(archiveDir, { recursive: true });
6376
+ await fs9.rename(changeFile, archiveFile).catch(() => {
6144
6377
  });
6145
6378
  this.state = null;
6146
6379
  this.snapshots.clear();
@@ -6166,15 +6399,15 @@ var WorkflowEngine = class {
6166
6399
  const archiveDir = path5.join(changesDir, "archive");
6167
6400
  const specDir = path5.join(this.openspecPath, "spec");
6168
6401
  const statesDir = path5.join(this.openspecPath, ".workflow-states");
6169
- await fs4.mkdir(archiveDir, { recursive: true });
6170
- await fs4.mkdir(specDir, { recursive: true });
6171
- await fs4.mkdir(statesDir, { recursive: true });
6402
+ await fs9.mkdir(archiveDir, { recursive: true });
6403
+ await fs9.mkdir(specDir, { recursive: true });
6404
+ await fs9.mkdir(statesDir, { recursive: true });
6172
6405
  }
6173
6406
  async restoreState() {
6174
6407
  const activePath = path5.join(this.openspecPath, ".workflow-active.json");
6175
6408
  let activeId = null;
6176
6409
  try {
6177
- const activeContent = await fs4.readFile(activePath, "utf-8");
6410
+ const activeContent = await fs9.readFile(activePath, "utf-8");
6178
6411
  const activeData = JSON.parse(activeContent);
6179
6412
  activeId = activeData.activeId;
6180
6413
  } catch {
@@ -6182,7 +6415,7 @@ var WorkflowEngine = class {
6182
6415
  if (activeId) {
6183
6416
  const statePath = path5.join(this.openspecPath, ".workflow-states", `${activeId}.json`);
6184
6417
  try {
6185
- const content = await fs4.readFile(statePath, "utf-8");
6418
+ const content = await fs9.readFile(statePath, "utf-8");
6186
6419
  this.state = JSON.parse(content, (key, value) => {
6187
6420
  if (key.endsWith("At") && typeof value === "string") {
6188
6421
  return new Date(value);
@@ -6195,7 +6428,7 @@ var WorkflowEngine = class {
6195
6428
  }
6196
6429
  const oldStatePath = path5.join(this.openspecPath, ".workflow-state.json");
6197
6430
  try {
6198
- const content = await fs4.readFile(oldStatePath, "utf-8");
6431
+ const content = await fs9.readFile(oldStatePath, "utf-8");
6199
6432
  this.state = JSON.parse(content, (key, value) => {
6200
6433
  if (key.endsWith("At") && typeof value === "string") {
6201
6434
  return new Date(value);
@@ -6204,7 +6437,7 @@ var WorkflowEngine = class {
6204
6437
  });
6205
6438
  if (this.state) {
6206
6439
  await this.saveState();
6207
- await fs4.unlink(oldStatePath).catch(() => {
6440
+ await fs9.unlink(oldStatePath).catch(() => {
6208
6441
  });
6209
6442
  }
6210
6443
  } catch (e) {
@@ -6218,16 +6451,16 @@ var WorkflowEngine = class {
6218
6451
  async saveState() {
6219
6452
  if (!this.state) return;
6220
6453
  const statesDir = path5.join(this.openspecPath, ".workflow-states");
6221
- await fs4.mkdir(statesDir, { recursive: true });
6454
+ await fs9.mkdir(statesDir, { recursive: true });
6222
6455
  const statePath = path5.join(statesDir, `${this.state.id}.json`);
6223
- await fs4.writeFile(statePath, JSON.stringify(this.state, null, 2));
6456
+ await fs9.writeFile(statePath, JSON.stringify(this.state, null, 2));
6224
6457
  const activePath = path5.join(this.openspecPath, ".workflow-active.json");
6225
- await fs4.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
6458
+ await fs9.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
6226
6459
  }
6227
6460
  async restoreSnapshots() {
6228
6461
  const snapshotsPath = path5.join(this.openspecPath, ".workflow-snapshots.json");
6229
6462
  try {
6230
- const content = await fs4.readFile(snapshotsPath, "utf-8");
6463
+ const content = await fs9.readFile(snapshotsPath, "utf-8");
6231
6464
  const data = JSON.parse(content, (key, value) => {
6232
6465
  if (key === "timestamp" && typeof value === "string") {
6233
6466
  return new Date(value);
@@ -6244,7 +6477,7 @@ var WorkflowEngine = class {
6244
6477
  async saveSnapshots() {
6245
6478
  const snapshotsPath = path5.join(this.openspecPath, ".workflow-snapshots.json");
6246
6479
  const data = Array.from(this.snapshots.values());
6247
- await fs4.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
6480
+ await fs9.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
6248
6481
  }
6249
6482
  async createSnapshot() {
6250
6483
  if (!this.state) return;
@@ -6265,7 +6498,7 @@ var WorkflowEngine = class {
6265
6498
  async createChangeRecord() {
6266
6499
  if (!this.state) return;
6267
6500
  const changePath = path5.join(this.openspecPath, "changes", `${this.state.id}.md`);
6268
- await fs4.writeFile(changePath, this.formatChangeRecord());
6501
+ await fs9.writeFile(changePath, this.formatChangeRecord());
6269
6502
  }
6270
6503
  async updateChangeRecord(status) {
6271
6504
  if (!this.state) return;
@@ -6273,7 +6506,7 @@ var WorkflowEngine = class {
6273
6506
  this.state.status = status;
6274
6507
  }
6275
6508
  const changePath = path5.join(this.openspecPath, "changes", `${this.state.id}.md`);
6276
- await fs4.writeFile(changePath, this.formatChangeRecord());
6509
+ await fs9.writeFile(changePath, this.formatChangeRecord());
6277
6510
  }
6278
6511
  formatChangeRecord() {
6279
6512
  if (!this.state) return "";
@@ -6337,7 +6570,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
6337
6570
 
6338
6571
  ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
6339
6572
  `;
6340
- await fs4.writeFile(specPath, content);
6573
+ await fs9.writeFile(specPath, content);
6341
6574
  }
6342
6575
  };
6343
6576
  var ConfirmationRequiredError = class extends Error {
@@ -6386,11 +6619,11 @@ var NormsManager = class {
6386
6619
  const files = await this.collectProjectFiles(projectPath);
6387
6620
  for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
6388
6621
  try {
6389
- const stats = await fs4.stat(filePath);
6622
+ const stats = await fs9.stat(filePath);
6390
6623
  if (stats.size > MAX_FILE_SIZE) {
6391
6624
  continue;
6392
6625
  }
6393
- const content = await fs4.readFile(filePath, "utf-8");
6626
+ const content = await fs9.readFile(filePath, "utf-8");
6394
6627
  const patterns = await this.learnFromFile(filePath, content);
6395
6628
  result.patternsFound += patterns.length;
6396
6629
  result.filesScanned++;
@@ -7016,7 +7249,7 @@ ${response}`;
7016
7249
  const files = [];
7017
7250
  async function scan(dir) {
7018
7251
  try {
7019
- const entries = await fs4.readdir(dir, { withFileTypes: true });
7252
+ const entries = await fs9.readdir(dir, { withFileTypes: true });
7020
7253
  for (const entry of entries) {
7021
7254
  if (entry.isDirectory()) {
7022
7255
  if (!IGNORED_DIRS.includes(entry.name)) {
@@ -7059,8 +7292,8 @@ ${response}`;
7059
7292
  * 确保规范目录存在
7060
7293
  */
7061
7294
  async ensureNormsDir() {
7062
- await fs4.mkdir(this.config.normsDir, { recursive: true });
7063
- await fs4.mkdir(path5.join(this.config.normsDir, "weekly"), { recursive: true });
7295
+ await fs9.mkdir(this.config.normsDir, { recursive: true });
7296
+ await fs9.mkdir(path5.join(this.config.normsDir, "weekly"), { recursive: true });
7064
7297
  }
7065
7298
  /**
7066
7299
  * 加载已有规范
@@ -7068,7 +7301,7 @@ ${response}`;
7068
7301
  async loadStandards() {
7069
7302
  const standardsPath = path5.join(this.config.normsDir, "patterns.json");
7070
7303
  try {
7071
- const content = await fs4.readFile(standardsPath, "utf-8");
7304
+ const content = await fs9.readFile(standardsPath, "utf-8");
7072
7305
  const data = JSON.parse(content);
7073
7306
  for (const standard of data) {
7074
7307
  this.standards.set(standard.id, {
@@ -7086,7 +7319,7 @@ ${response}`;
7086
7319
  async loadWeights() {
7087
7320
  const weightsPath = path5.join(this.config.normsDir, "weights.json");
7088
7321
  try {
7089
- const content = await fs4.readFile(weightsPath, "utf-8");
7322
+ const content = await fs9.readFile(weightsPath, "utf-8");
7090
7323
  const data = JSON.parse(content);
7091
7324
  for (const weight of data) {
7092
7325
  this.weights.set(weight.standardId, {
@@ -7102,7 +7335,7 @@ ${response}`;
7102
7335
  */
7103
7336
  async saveStandards() {
7104
7337
  const standardsPath = path5.join(this.config.normsDir, "patterns.json");
7105
- await fs4.writeFile(
7338
+ await fs9.writeFile(
7106
7339
  standardsPath,
7107
7340
  JSON.stringify(Array.from(this.standards.values()), null, 2),
7108
7341
  "utf-8"
@@ -7113,7 +7346,7 @@ ${response}`;
7113
7346
  */
7114
7347
  async saveWeights() {
7115
7348
  const weightsPath = path5.join(this.config.normsDir, "weights.json");
7116
- await fs4.writeFile(
7349
+ await fs9.writeFile(
7117
7350
  weightsPath,
7118
7351
  JSON.stringify(Array.from(this.weights.values()), null, 2),
7119
7352
  "utf-8"
@@ -7141,7 +7374,7 @@ ${response}`;
7141
7374
  */
7142
7375
  async saveWeeklyReport(weekId, report) {
7143
7376
  const reportPath = path5.join(this.config.normsDir, "weekly", `${weekId}.json`);
7144
- await fs4.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
7377
+ await fs9.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
7145
7378
  }
7146
7379
  /**
7147
7380
  * 更新 devstanded.md
@@ -7150,7 +7383,7 @@ ${response}`;
7150
7383
  const standards = this.getEffectiveStandards();
7151
7384
  const content = this.generateDevStandedMd(standards);
7152
7385
  const mdPath = path5.join(this.config.normsDir, "devstanded.md");
7153
- await fs4.writeFile(mdPath, content, "utf-8");
7386
+ await fs9.writeFile(mdPath, content, "utf-8");
7154
7387
  }
7155
7388
  /**
7156
7389
  * 生成 devstanded.md 内容
@@ -7542,14 +7775,14 @@ ${summary}`,
7542
7775
  async persist() {
7543
7776
  if (!this.persistPath) return;
7544
7777
  const dir = path5.dirname(this.persistPath);
7545
- await fs4.mkdir(dir, { recursive: true });
7778
+ await fs9.mkdir(dir, { recursive: true });
7546
7779
  const data = {
7547
7780
  messages: this.state.messages,
7548
7781
  totalTokens: this.state.totalTokens,
7549
7782
  limit: this.state.limit,
7550
7783
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
7551
7784
  };
7552
- await fs4.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
7785
+ await fs9.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
7553
7786
  }
7554
7787
  /**
7555
7788
  * 加载持久化的上下文
@@ -7557,7 +7790,7 @@ ${summary}`,
7557
7790
  async loadPersistedContext() {
7558
7791
  if (!this.persistPath) return;
7559
7792
  try {
7560
- const content = await fs4.readFile(this.persistPath, "utf-8");
7793
+ const content = await fs9.readFile(this.persistPath, "utf-8");
7561
7794
  const data = JSON.parse(content);
7562
7795
  this.state.messages = data.messages || [];
7563
7796
  this.state.totalTokens = data.totalTokens || 0;
@@ -7774,7 +8007,7 @@ async function handleInit(args, ctx) {
7774
8007
  async function initProject(options = {}, workingDir) {
7775
8008
  const cwd = workingDir || process.cwd();
7776
8009
  try {
7777
- const stats = await fs4.stat(cwd);
8010
+ const stats = await fs9.stat(cwd);
7778
8011
  if (!stats.isDirectory()) {
7779
8012
  return {
7780
8013
  output: chalk9.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
@@ -7806,7 +8039,7 @@ async function initProject(options = {}, workingDir) {
7806
8039
  await normsManager.initialize();
7807
8040
  const scanResult = await normsManager.scanProject(cwd);
7808
8041
  const agentsContent = generateAgentsMd(projectInfo, scanResult);
7809
- await fs4.writeFile(agentsMdPath, agentsContent, "utf-8");
8042
+ await fs9.writeFile(agentsMdPath, agentsContent, "utf-8");
7810
8043
  await generateOpenSpecConfig(openspecDir, projectInfo);
7811
8044
  return {
7812
8045
  output: chalk9.green("\u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210\n") + chalk9.gray(` \u9879\u76EE\u7C7B\u578B: ${projectInfo.type}
@@ -7847,7 +8080,7 @@ async function createSfCliDirectory(basePath) {
7847
8080
  "logs"
7848
8081
  ];
7849
8082
  for (const dir of dirs) {
7850
- await fs4.mkdir(path5.join(basePath, dir), { recursive: true });
8083
+ await fs9.mkdir(path5.join(basePath, dir), { recursive: true });
7851
8084
  }
7852
8085
  const config = {
7853
8086
  version: "1.0.0",
@@ -7855,22 +8088,22 @@ async function createSfCliDirectory(basePath) {
7855
8088
  yolo: false,
7856
8089
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
7857
8090
  };
7858
- await fs4.writeFile(
8091
+ await fs9.writeFile(
7859
8092
  path5.join(basePath, "config.json"),
7860
8093
  JSON.stringify(config, null, 2),
7861
8094
  "utf-8"
7862
8095
  );
7863
- await fs4.writeFile(
8096
+ await fs9.writeFile(
7864
8097
  path5.join(basePath, "agents", "registry.json"),
7865
8098
  JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
7866
8099
  "utf-8"
7867
8100
  );
7868
- await fs4.writeFile(
8101
+ await fs9.writeFile(
7869
8102
  path5.join(basePath, "skills", "registry.json"),
7870
8103
  JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
7871
8104
  "utf-8"
7872
8105
  );
7873
- await fs4.writeFile(
8106
+ await fs9.writeFile(
7874
8107
  path5.join(basePath, "health", "health.md"),
7875
8108
  generateHealthTemplate(),
7876
8109
  "utf-8"
@@ -7880,8 +8113,8 @@ async function createOpenSpecDirectory(basePath) {
7880
8113
  const changesDir = path5.join(basePath, "changes");
7881
8114
  const archiveDir = path5.join(changesDir, "archive");
7882
8115
  const specDir = path5.join(basePath, "spec");
7883
- await fs4.mkdir(archiveDir, { recursive: true });
7884
- await fs4.mkdir(specDir, { recursive: true });
8116
+ await fs9.mkdir(archiveDir, { recursive: true });
8117
+ await fs9.mkdir(specDir, { recursive: true });
7885
8118
  }
7886
8119
  async function analyzeProject(cwd) {
7887
8120
  const result = {
@@ -7906,7 +8139,7 @@ async function analyzeProject(cwd) {
7906
8139
  };
7907
8140
  const pkgPath = path5.join(cwd, "package.json");
7908
8141
  try {
7909
- const pkgContent = await fs4.readFile(pkgPath, "utf-8");
8142
+ const pkgContent = await fs9.readFile(pkgPath, "utf-8");
7910
8143
  const pkg = JSON.parse(pkgContent);
7911
8144
  result.name = pkg.name || result.name;
7912
8145
  result.dependencies = pkg.dependencies || {};
@@ -7989,7 +8222,7 @@ async function analyzeDirectoryStructure(cwd) {
7989
8222
  others: []
7990
8223
  };
7991
8224
  try {
7992
- const entries = await fs4.readdir(cwd, { withFileTypes: true });
8225
+ const entries = await fs9.readdir(cwd, { withFileTypes: true });
7993
8226
  for (const entry of entries) {
7994
8227
  if (!entry.isDirectory()) continue;
7995
8228
  const name = entry.name;
@@ -8034,7 +8267,7 @@ async function findEntryPoints(cwd) {
8034
8267
  }
8035
8268
  async function saveProjectAnalysis(sfCliDir, analysis) {
8036
8269
  const analysisPath = path5.join(sfCliDir, "cache", "analysis", "project-analysis.json");
8037
- await fs4.writeFile(
8270
+ await fs9.writeFile(
8038
8271
  analysisPath,
8039
8272
  JSON.stringify(analysis, null, 2),
8040
8273
  "utf-8"
@@ -8075,7 +8308,7 @@ architecture:
8075
8308
  # \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
8076
8309
  standards: []
8077
8310
  `;
8078
- await fs4.writeFile(configPath, content, "utf-8");
8311
+ await fs9.writeFile(configPath, content, "utf-8");
8079
8312
  }
8080
8313
  function generateAgentsMd(info, scanResult) {
8081
8314
  const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
@@ -8197,7 +8430,7 @@ function generateHealthTemplate() {
8197
8430
  }
8198
8431
  async function fileExists(filePath) {
8199
8432
  try {
8200
- await fs4.access(filePath);
8433
+ await fs9.access(filePath);
8201
8434
  return true;
8202
8435
  } catch {
8203
8436
  return false;
@@ -9632,9 +9865,9 @@ async function handleFileReference(filePath, ctx) {
9632
9865
  const cwd = ctx.options.workingDirectory;
9633
9866
  const absolutePath = path5.isAbsolute(filePath) ? filePath : path5.join(cwd, filePath);
9634
9867
  try {
9635
- const stats = await fs4.stat(absolutePath);
9868
+ const stats = await fs9.stat(absolutePath);
9636
9869
  if (stats.isDirectory()) {
9637
- const files = await fs4.readdir(absolutePath);
9870
+ const files = await fs9.readdir(absolutePath);
9638
9871
  return {
9639
9872
  output: chalk9.cyan(`\u{1F4C1} ${filePath}/`) + chalk9.gray(`
9640
9873
  ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9.gray(`
@@ -9642,7 +9875,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9.gray(`
9642
9875
  contextUsed: 0
9643
9876
  };
9644
9877
  }
9645
- const content = await fs4.readFile(absolutePath, "utf-8");
9878
+ const content = await fs9.readFile(absolutePath, "utf-8");
9646
9879
  const lines = content.split("\n");
9647
9880
  ctx.contextManager.addMessage({
9648
9881
  role: "user",
@@ -10071,7 +10304,7 @@ var Completer = class {
10071
10304
  prefix = filePath.slice(lastSlash + 1);
10072
10305
  }
10073
10306
  try {
10074
- const entries = await fs4.readdir(dirPath, { withFileTypes: true });
10307
+ const entries = await fs9.readdir(dirPath, { withFileTypes: true });
10075
10308
  const matches = [];
10076
10309
  for (const entry of entries) {
10077
10310
  if (entry.name.startsWith(prefix)) {