@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 CHANGED
@@ -7,7 +7,7 @@ var enquirer = require('enquirer');
7
7
  var child_process = require('child_process');
8
8
  var fs7 = require('fs');
9
9
  var path5 = require('path');
10
- var fs5 = require('fs/promises');
10
+ var fs4 = require('fs/promises');
11
11
  var commander = require('commander');
12
12
  var readline = require('readline');
13
13
  require('uuid');
@@ -39,7 +39,7 @@ function _interopNamespace(e) {
39
39
  var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
40
40
  var fs7__namespace = /*#__PURE__*/_interopNamespace(fs7);
41
41
  var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
42
- var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
42
+ var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
43
43
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
44
44
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
45
45
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
@@ -2032,24 +2032,13 @@ async function executeDevelopment(ctx, session) {
2032
2032
  loader.start();
2033
2033
  try {
2034
2034
  const taskPrompt = buildTaskPrompt(session, item, i);
2035
+ const structureInfo = session.context?.projectStructure;
2036
+ const structureGuide = buildStructureGuide(structureInfo);
2037
+ const systemPrompt = buildCodeGenerationSystemPrompt(session, structureGuide);
2035
2038
  const messages = [
2036
2039
  {
2037
2040
  role: "system",
2038
- 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
2039
-
2040
- \u26A0\uFE0F \u91CD\u8981\u89C4\u5219\uFF1A
2041
- 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
2042
- 2. \u6280\u672F\u5B9E\u73B0\u5FC5\u987B\u4E25\u683C\u9075\u5FAA\u9879\u76EE\u73B0\u6709\u7684\u5F00\u53D1\u89C4\u8303
2043
- 3. \u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801
2044
- 4. \u8FD4\u56DE\u683C\u5F0F\uFF1A\u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u4EE3\u7801 \`\`\` \u5305\u88F9
2045
-
2046
- \u9879\u76EE\u4FE1\u606F\uFF1A
2047
- - \u540D\u79F0: ${session.context?.name}
2048
- - \u6846\u67B6: ${session.context?.framework || "\u672A\u6307\u5B9A"}
2049
- - \u6280\u672F\u6808: ${session.context?.techStack.join(", ") || "\u672A\u6307\u5B9A"}
2050
-
2051
- ${session.context?.devStandards ? `\u3010\u5F00\u53D1\u89C4\u8303\u3011
2052
- ${session.context.devStandards.slice(0, 2e3)}` : ""}`
2041
+ content: systemPrompt
2053
2042
  },
2054
2043
  {
2055
2044
  role: "user",
@@ -2069,17 +2058,17 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
2069
2058
  for (const block of codeBlocks) {
2070
2059
  const filePath = path5__namespace.join(workingDir, block.filename);
2071
2060
  const dir = path5__namespace.dirname(filePath);
2072
- await fs5__namespace.mkdir(dir, { recursive: true });
2073
- await fs5__namespace.writeFile(filePath, block.code, "utf-8");
2061
+ await fs4__namespace.mkdir(dir, { recursive: true });
2062
+ await fs4__namespace.writeFile(filePath, block.code, "utf-8");
2074
2063
  files.push(block.filename);
2075
2064
  }
2076
2065
  loader.stop(chalk9__default.default.green(`${prefix} \u2713 ${item.title.slice(0, 25)} (${codeBlocks.length} \u4E2A\u6587\u4EF6)`));
2077
2066
  } else {
2078
2067
  const implDir = path5__namespace.join(workingDir, "src");
2079
- await fs5__namespace.mkdir(implDir, { recursive: true });
2068
+ await fs4__namespace.mkdir(implDir, { recursive: true });
2080
2069
  const fileName = `${item.title.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_")}.ts`;
2081
2070
  const filePath = path5__namespace.join(implDir, fileName);
2082
- await fs5__namespace.writeFile(filePath, `// TODO: ${item.title}
2071
+ await fs4__namespace.writeFile(filePath, `// TODO: ${item.title}
2083
2072
  // ${item.description}
2084
2073
  `, "utf-8");
2085
2074
  files.push(`src/${fileName}`);
@@ -2102,6 +2091,91 @@ ${session.context.devStandards.slice(0, 2e3)}` : ""}`
2102
2091
  };
2103
2092
  }
2104
2093
  }
2094
+ function buildStructureGuide(structure) {
2095
+ if (!structure) {
2096
+ return `## \u9879\u76EE\u7ED3\u6784
2097
+ - \u7EC4\u4EF6\u653E\u5728 src/components/
2098
+ - \u9875\u9762\u653E\u5728 src/pages/
2099
+ - \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/`;
2100
+ }
2101
+ const lines = ["## \u9879\u76EE\u7ED3\u6784\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09"];
2102
+ if (structure.hasSrc) {
2103
+ lines.push(`- \u6E90\u7801\u76EE\u5F55: ${structure.srcDir}/`);
2104
+ }
2105
+ if (structure.hasPages) {
2106
+ lines.push(`- \u9875\u9762\u76EE\u5F55: ${structure.pagesDir}/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
2107
+ } else {
2108
+ lines.push(`- \u9875\u9762\u76EE\u5F55: src/pages/ \uFF08\u9875\u9762\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
2109
+ }
2110
+ if (structure.hasComponents) {
2111
+ lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: ${structure.componentsDir}/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
2112
+ } else {
2113
+ lines.push(`- \u7EC4\u4EF6\u76EE\u5F55: src/components/ \uFF08\u901A\u7528\u7EC4\u4EF6\u653E\u8FD9\u91CC\uFF09`);
2114
+ }
2115
+ if (structure.hasApi) {
2116
+ lines.push(`- API \u76EE\u5F55: src/api/ \u6216 src/services/`);
2117
+ }
2118
+ if (structure.hasHooks) {
2119
+ lines.push(`- Hooks \u76EE\u5F55: src/hooks/`);
2120
+ }
2121
+ if (structure.hasStore) {
2122
+ lines.push(`- \u72B6\u6001\u7BA1\u7406\u76EE\u5F55: src/store/`);
2123
+ }
2124
+ if (structure.hasUtils) {
2125
+ lines.push(`- \u5DE5\u5177\u51FD\u6570\u76EE\u5F55: src/utils/`);
2126
+ }
2127
+ lines.push("");
2128
+ 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");
2129
+ return lines.join("\n");
2130
+ }
2131
+ function buildCodeGenerationSystemPrompt(session, structureGuide) {
2132
+ const framework = session.context?.framework || "React";
2133
+ const techStack = session.context?.techStack?.join(", ") || "TypeScript";
2134
+ const devStandards = session.context?.devStandards || "";
2135
+ const standardsText = devStandards.slice(0, 6e3);
2136
+ 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
2137
+
2138
+ ## \u26A0\uFE0F \u6838\u5FC3\u89C4\u5219\uFF08\u5FC5\u987B\u9075\u5B88\uFF09
2139
+
2140
+ 1. **\u8BED\u8A00**: \u5FC5\u987B\u4F7F\u7528 TypeScript (.tsx/.ts \u6587\u4EF6)
2141
+ 2. **\u6846\u67B6**: ${framework}
2142
+ 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
2143
+ 4. **\u6587\u4EF6\u8DEF\u5F84\u5FC5\u987B\u6B63\u786E**\uFF1A\u4E25\u683C\u6309\u7167\u9879\u76EE\u7ED3\u6784\u653E\u7F6E\u6587\u4EF6
2144
+ 5. **\u5FC5\u987B\u751F\u6210\u5B8C\u6574\u3001\u53EF\u8FD0\u884C\u7684\u4EE3\u7801**\uFF0C\u4E0D\u8981\u5199 TODO \u6216\u5360\u4F4D\u7B26
2145
+ 6. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA\u9875\u9762**\uFF0C\u5FC5\u987B\u751F\u6210\u9875\u9762\u7EC4\u4EF6
2146
+ 7. **\u5982\u679C\u4EFB\u52A1\u6D89\u53CA UI**\uFF0C\u5FC5\u987B\u751F\u6210\u5BF9\u5E94\u7684\u7EC4\u4EF6\u548C\u6837\u5F0F
2147
+
2148
+ ${structureGuide}
2149
+
2150
+ ## \u9879\u76EE\u4FE1\u606F
2151
+
2152
+ - \u540D\u79F0: ${session.context?.name || "\u672A\u547D\u540D\u9879\u76EE"}
2153
+ - \u6846\u67B6: ${framework}
2154
+ - \u6280\u672F\u6808: ${techStack}
2155
+
2156
+ ## \u5F00\u53D1\u89C4\u8303\uFF08\u5FC5\u987B\u9075\u5FAA\uFF09
2157
+
2158
+ ${standardsText || `### \u9ED8\u8BA4\u89C4\u8303
2159
+ - \u4F7F\u7528\u51FD\u6570\u5F0F\u7EC4\u4EF6
2160
+ - \u4F7F\u7528 TypeScript \u7C7B\u578B\u5B9A\u4E49
2161
+ - \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65
2162
+ - \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase
2163
+ - \u5BFC\u51FA\u4F7F\u7528 export default \u6216 export const`}
2164
+
2165
+ ## \u8F93\u51FA\u683C\u5F0F
2166
+
2167
+ \u6BCF\u4E2A\u6587\u4EF6\u7528 \`\`\`filename \u5305\u88F9\uFF0C\u4F8B\u5982\uFF1A
2168
+
2169
+ \`\`\`src/pages/HomePage.tsx
2170
+ // \u4EE3\u7801\u5185\u5BB9
2171
+ \`\`\`
2172
+
2173
+ \`\`\`src/components/Button/Button.tsx
2174
+ // \u4EE3\u7801\u5185\u5BB9
2175
+ \`\`\`
2176
+
2177
+ \u73B0\u5728\u8BF7\u6839\u636E\u4EFB\u52A1\u8981\u6C42\u751F\u6210\u4EE3\u7801\u3002`;
2178
+ }
2105
2179
  function buildTaskPrompt(session, item, index) {
2106
2180
  const lines = [];
2107
2181
  lines.push(`## \u5F53\u524D\u4EFB\u52A1 (#${index + 1})`);
@@ -2156,7 +2230,7 @@ async function executeReview(ctx, session) {
2156
2230
  const codeContents = [];
2157
2231
  for (const file of session.implFiles) {
2158
2232
  try {
2159
- const content = await fs5__namespace.readFile(path5__namespace.join(workingDir, file), "utf-8");
2233
+ const content = await fs4__namespace.readFile(path5__namespace.join(workingDir, file), "utf-8");
2160
2234
  codeContents.push(`// ${file}
2161
2235
  ${content}`);
2162
2236
  } catch {
@@ -2165,7 +2239,7 @@ ${content}`);
2165
2239
  const testContents = [];
2166
2240
  for (const file of session.testFiles) {
2167
2241
  try {
2168
- const content = await fs5__namespace.readFile(path5__namespace.join(workingDir, file), "utf-8");
2242
+ const content = await fs4__namespace.readFile(path5__namespace.join(workingDir, file), "utf-8");
2169
2243
  testContents.push(`// ${file}
2170
2244
  ${content}`);
2171
2245
  } catch {
@@ -2259,9 +2333,9 @@ async function readProjectContext(workingDir) {
2259
2333
  };
2260
2334
  const agentsPath = path5__namespace.join(workingDir, "AGENTS.md");
2261
2335
  try {
2262
- const stats = await fs5__namespace.stat(agentsPath);
2336
+ const stats = await fs4__namespace.stat(agentsPath);
2263
2337
  if (stats.size <= MAX_FILE_SIZE2) {
2264
- context.agentsMd = await fs5__namespace.readFile(agentsPath, "utf-8");
2338
+ context.agentsMd = await fs4__namespace.readFile(agentsPath, "utf-8");
2265
2339
  const nameMatch = context.agentsMd.match(/\|\s*项目名称\s*\|\s*([^\s|]+)/);
2266
2340
  if (nameMatch) context.name = nameMatch[1];
2267
2341
  const typeMatch = context.agentsMd.match(/\|\s*项目类型\s*\|\s*([^\s|]+)/);
@@ -2275,9 +2349,9 @@ async function readProjectContext(workingDir) {
2275
2349
  }
2276
2350
  const configPath = path5__namespace.join(workingDir, "openspec", "config.yaml");
2277
2351
  try {
2278
- const stats = await fs5__namespace.stat(configPath);
2352
+ const stats = await fs4__namespace.stat(configPath);
2279
2353
  if (stats.size <= MAX_FILE_SIZE2) {
2280
- context.configYaml = await fs5__namespace.readFile(configPath, "utf-8");
2354
+ context.configYaml = await fs4__namespace.readFile(configPath, "utf-8");
2281
2355
  const nameMatch = context.configYaml.match(/name:\s*(.+)/);
2282
2356
  if (nameMatch) context.name = nameMatch[1].trim();
2283
2357
  const typeMatch = context.configYaml.match(/type:\s*(.+)/);
@@ -2298,14 +2372,173 @@ async function readProjectContext(workingDir) {
2298
2372
  }
2299
2373
  const devStandardsPath = path5__namespace.join(workingDir, ".sf-cli", "norms", "devstanded.md");
2300
2374
  try {
2301
- const stats = await fs5__namespace.stat(devStandardsPath);
2375
+ const stats = await fs4__namespace.stat(devStandardsPath);
2302
2376
  if (stats.size <= MAX_FILE_SIZE2) {
2303
- context.devStandards = await fs5__namespace.readFile(devStandardsPath, "utf-8");
2377
+ context.devStandards = await fs4__namespace.readFile(devStandardsPath, "utf-8");
2304
2378
  }
2305
2379
  } catch {
2306
2380
  }
2381
+ if (!context.framework) {
2382
+ const detectedFramework = await detectFramework2(workingDir);
2383
+ if (detectedFramework) {
2384
+ context.framework = detectedFramework;
2385
+ context.techStack = [detectedFramework, ...context.techStack.filter((t) => t !== detectedFramework)];
2386
+ }
2387
+ }
2388
+ if (!context.devStandards) {
2389
+ context.devStandards = await analyzeProjectForStandards(workingDir, context);
2390
+ }
2391
+ context.projectStructure = await analyzeProjectStructure(workingDir);
2307
2392
  return context;
2308
2393
  }
2394
+ async function detectFramework2(workingDir) {
2395
+ try {
2396
+ const pkgPath = path5__namespace.join(workingDir, "package.json");
2397
+ const pkgContent = await fs4__namespace.readFile(pkgPath, "utf-8");
2398
+ const pkg = JSON.parse(pkgContent);
2399
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2400
+ if (deps["react"] || deps["next"]) return "React";
2401
+ if (deps["vue"] || deps["nuxt"]) return "Vue";
2402
+ if (deps["angular"] || deps["@angular/core"]) return "Angular";
2403
+ if (deps["svelte"]) return "Svelte";
2404
+ if (deps["solid-js"]) return "Solid";
2405
+ if (deps["vite"] || deps["webpack"]) return "JavaScript";
2406
+ if (deps["typescript"]) return "TypeScript";
2407
+ return null;
2408
+ } catch {
2409
+ return null;
2410
+ }
2411
+ }
2412
+ async function analyzeProjectForStandards(workingDir, context) {
2413
+ const standards = [];
2414
+ standards.push(`# \u9879\u76EE\u5F00\u53D1\u89C4\u8303\uFF08\u81EA\u52A8\u751F\u6210\uFF09
2415
+ > \u9879\u76EE\u540D\u79F0: ${context.name}
2416
+ > \u6846\u67B6: ${context.framework || "\u672A\u68C0\u6D4B\u5230"}
2417
+ > \u6280\u672F\u6808: ${context.techStack.join(", ") || "\u672A\u68C0\u6D4B\u5230"}
2418
+ `);
2419
+ try {
2420
+ const tsConfigPath = path5__namespace.join(workingDir, "tsconfig.json");
2421
+ await fs4__namespace.access(tsConfigPath);
2422
+ standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 TypeScript");
2423
+ } catch {
2424
+ standards.push("\n## \u8BED\u8A00\n- \u4F7F\u7528 JavaScript");
2425
+ }
2426
+ try {
2427
+ const srcDir = path5__namespace.join(workingDir, "src");
2428
+ const files = await listFilesDeep(srcDir);
2429
+ const hasCss = files.some((f) => f.endsWith(".css"));
2430
+ const hasScss = files.some((f) => f.endsWith(".scss") || f.endsWith(".sass"));
2431
+ const hasLess = files.some((f) => f.endsWith(".less"));
2432
+ const hasStyled = files.some((f) => f.includes(".styled.") || f.includes("styled-components"));
2433
+ if (hasScss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 SCSS/Sass");
2434
+ else if (hasLess) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 Less");
2435
+ else if (hasStyled) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 styled-components");
2436
+ else if (hasCss) standards.push("\n## \u6837\u5F0F\n- \u4F7F\u7528 CSS");
2437
+ } catch {
2438
+ }
2439
+ try {
2440
+ const srcDir = path5__namespace.join(workingDir, "src");
2441
+ const entries = await fs4__namespace.readdir(srcDir, { withFileTypes: true });
2442
+ const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
2443
+ if (dirs.includes("components")) standards.push("\n## \u76EE\u5F55\u7ED3\u6784\n- \u7EC4\u4EF6\u653E\u5728 src/components/");
2444
+ if (dirs.includes("pages") || dirs.includes("views")) standards.push("- \u9875\u9762\u653E\u5728 src/pages/ \u6216 src/views/");
2445
+ if (dirs.includes("hooks")) standards.push("- Hooks \u653E\u5728 src/hooks/");
2446
+ if (dirs.includes("utils")) standards.push("- \u5DE5\u5177\u51FD\u6570\u653E\u5728 src/utils/");
2447
+ if (dirs.includes("api") || dirs.includes("services")) standards.push("- API \u8C03\u7528\u653E\u5728 src/api/ \u6216 src/services/");
2448
+ if (dirs.includes("store") || dirs.includes("stores")) standards.push("- \u72B6\u6001\u7BA1\u7406\u653E\u5728 src/store/");
2449
+ } catch {
2450
+ }
2451
+ standards.push("\n## \u4EE3\u7801\u89C4\u8303");
2452
+ standards.push("- \u4F7F\u7528 ES6+ \u8BED\u6CD5");
2453
+ standards.push("- \u7EC4\u4EF6\u4F7F\u7528\u51FD\u6570\u5F0F\u5199\u6CD5");
2454
+ standards.push("- \u4F7F\u7528 async/await \u5904\u7406\u5F02\u6B65");
2455
+ standards.push("- \u53D8\u91CF\u4F7F\u7528 camelCase\uFF0C\u7EC4\u4EF6\u4F7F\u7528 PascalCase");
2456
+ standards.push("- \u5E38\u91CF\u4F7F\u7528 UPPER_SNAKE_CASE");
2457
+ return standards.join("\n");
2458
+ }
2459
+ async function listFilesDeep(dir, maxDepth = 3) {
2460
+ const files = [];
2461
+ async function scan(currentDir, depth) {
2462
+ if (depth > maxDepth) return;
2463
+ try {
2464
+ const entries = await fs4__namespace.readdir(currentDir, { withFileTypes: true });
2465
+ for (const entry of entries) {
2466
+ if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
2467
+ const fullPath = path5__namespace.join(currentDir, entry.name);
2468
+ if (entry.isDirectory()) {
2469
+ await scan(fullPath, depth + 1);
2470
+ } else {
2471
+ files.push(fullPath);
2472
+ }
2473
+ }
2474
+ } catch {
2475
+ }
2476
+ }
2477
+ await scan(dir, 0);
2478
+ return files;
2479
+ }
2480
+ async function analyzeProjectStructure(workingDir) {
2481
+ const structure = {
2482
+ hasSrc: false,
2483
+ hasPages: false,
2484
+ hasComponents: false,
2485
+ hasApi: false,
2486
+ hasHooks: false,
2487
+ hasStore: false,
2488
+ hasUtils: false,
2489
+ srcDir: "src",
2490
+ pagesDir: "",
2491
+ componentsDir: ""
2492
+ };
2493
+ try {
2494
+ const srcDir = path5__namespace.join(workingDir, "src");
2495
+ try {
2496
+ const srcStat = await fs4__namespace.stat(srcDir);
2497
+ if (srcStat.isDirectory()) {
2498
+ structure.hasSrc = true;
2499
+ structure.srcDir = "src";
2500
+ const srcEntries = await fs4__namespace.readdir(srcDir, { withFileTypes: true });
2501
+ const srcDirs = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name);
2502
+ if (srcDirs.includes("pages")) {
2503
+ structure.hasPages = true;
2504
+ structure.pagesDir = "src/pages";
2505
+ } else if (srcDirs.includes("views")) {
2506
+ structure.hasPages = true;
2507
+ structure.pagesDir = "src/views";
2508
+ }
2509
+ if (srcDirs.includes("components")) {
2510
+ structure.hasComponents = true;
2511
+ structure.componentsDir = "src/components";
2512
+ }
2513
+ if (srcDirs.includes("api") || srcDirs.includes("services")) {
2514
+ structure.hasApi = true;
2515
+ }
2516
+ if (srcDirs.includes("hooks")) {
2517
+ structure.hasHooks = true;
2518
+ }
2519
+ if (srcDirs.includes("store") || srcDirs.includes("stores")) {
2520
+ structure.hasStore = true;
2521
+ }
2522
+ if (srcDirs.includes("utils")) {
2523
+ structure.hasUtils = true;
2524
+ }
2525
+ }
2526
+ } catch {
2527
+ const rootEntries = await fs4__namespace.readdir(workingDir, { withFileTypes: true });
2528
+ const rootDirs = rootEntries.filter((e) => e.isDirectory()).map((e) => e.name);
2529
+ if (rootDirs.includes("pages")) {
2530
+ structure.hasPages = true;
2531
+ structure.pagesDir = "pages";
2532
+ }
2533
+ if (rootDirs.includes("components")) {
2534
+ structure.hasComponents = true;
2535
+ structure.componentsDir = "components";
2536
+ }
2537
+ }
2538
+ } catch {
2539
+ }
2540
+ return structure;
2541
+ }
2309
2542
  function analyzeComplexity(requirement, context) {
2310
2543
  let score = 3;
2311
2544
  if (requirement.length > 100) score += 1;
@@ -2794,10 +3027,10 @@ ${feedbacks.map((f, i) => `${i + 1}. ${f}`).join("\n")}
2794
3027
  }
2795
3028
  async function saveSpecFile(workingDir, session) {
2796
3029
  const specDir = path5__namespace.join(workingDir, "openspec", "changes");
2797
- await fs5__namespace.mkdir(specDir, { recursive: true });
3030
+ await fs4__namespace.mkdir(specDir, { recursive: true });
2798
3031
  const specPath = path5__namespace.join(specDir, `${session.id}-spec.md`);
2799
3032
  const content = formatSpecFile(session);
2800
- await fs5__namespace.writeFile(specPath, content, "utf-8");
3033
+ await fs4__namespace.writeFile(specPath, content, "utf-8");
2801
3034
  return specPath;
2802
3035
  }
2803
3036
  function formatSpecFile(session) {
@@ -2882,7 +3115,7 @@ function formatSpecFile(session) {
2882
3115
  }
2883
3116
  async function generateTests(workingDir, session, ctx) {
2884
3117
  const testDir = path5__namespace.join(workingDir, "tests");
2885
- await fs5__namespace.mkdir(testDir, { recursive: true });
3118
+ await fs4__namespace.mkdir(testDir, { recursive: true });
2886
3119
  const testFiles = [];
2887
3120
  if (ctx?.modelService) {
2888
3121
  for (const scenario of session.bddScenarios) {
@@ -2892,12 +3125,12 @@ async function generateTests(workingDir, session, ctx) {
2892
3125
  loader.start();
2893
3126
  try {
2894
3127
  const content = await generateTestFileWithAI(scenario, session, ctx);
2895
- await fs5__namespace.writeFile(testPath, content, "utf-8");
3128
+ await fs4__namespace.writeFile(testPath, content, "utf-8");
2896
3129
  testFiles.push(`tests/${testName}.test.ts`);
2897
3130
  loader.stop(chalk9__default.default.green(` \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210`));
2898
3131
  } catch {
2899
3132
  const content = generateTestFile(scenario, session);
2900
- await fs5__namespace.writeFile(testPath, content, "utf-8");
3133
+ await fs4__namespace.writeFile(testPath, content, "utf-8");
2901
3134
  testFiles.push(`tests/${testName}.test.ts`);
2902
3135
  loader.stop(chalk9__default.default.yellow(" \u26A0 \u4F7F\u7528\u57FA\u7840\u6D4B\u8BD5\u6A21\u677F"));
2903
3136
  }
@@ -2907,7 +3140,7 @@ async function generateTests(workingDir, session, ctx) {
2907
3140
  const testName = scenario.feature.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, "_");
2908
3141
  const testPath = path5__namespace.join(testDir, `${testName}.test.ts`);
2909
3142
  const content = generateTestFile(scenario, session);
2910
- await fs5__namespace.writeFile(testPath, content, "utf-8");
3143
+ await fs4__namespace.writeFile(testPath, content, "utf-8");
2911
3144
  testFiles.push(`tests/${testName}.test.ts`);
2912
3145
  }
2913
3146
  }
@@ -3001,7 +3234,7 @@ function generateTestFile(scenario, session) {
3001
3234
  async function archiveWorkflow(workingDir) {
3002
3235
  if (!activeSession) return;
3003
3236
  const archiveDir = path5__namespace.join(workingDir, "openspec", "spec");
3004
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
3237
+ await fs4__namespace.mkdir(archiveDir, { recursive: true });
3005
3238
  const archivePath = path5__namespace.join(archiveDir, `${activeSession.id}.md`);
3006
3239
  const content = `# \u5F52\u6863: ${activeSession.requirement.slice(0, 50)}
3007
3240
 
@@ -3028,7 +3261,7 @@ ${activeSession.refinedRequirement}
3028
3261
 
3029
3262
  ${activeSession.testFiles.map((f) => `- ${f}`).join("\n") || "\u65E0"}
3030
3263
  `;
3031
- await fs5__namespace.writeFile(archivePath, content, "utf-8");
3264
+ await fs4__namespace.writeFile(archivePath, content, "utf-8");
3032
3265
  }
3033
3266
  function generateSessionId() {
3034
3267
  const timestamp = Date.now().toString(36);
@@ -3450,11 +3683,11 @@ var NormsManager = class {
3450
3683
  const files = await this.collectProjectFiles(projectPath);
3451
3684
  for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
3452
3685
  try {
3453
- const stats = await fs5__namespace.stat(filePath);
3686
+ const stats = await fs4__namespace.stat(filePath);
3454
3687
  if (stats.size > MAX_FILE_SIZE) {
3455
3688
  continue;
3456
3689
  }
3457
- const content = await fs5__namespace.readFile(filePath, "utf-8");
3690
+ const content = await fs4__namespace.readFile(filePath, "utf-8");
3458
3691
  const patterns = await this.learnFromFile(filePath, content);
3459
3692
  result.patternsFound += patterns.length;
3460
3693
  result.filesScanned++;
@@ -4080,7 +4313,7 @@ ${response}`;
4080
4313
  const files = [];
4081
4314
  async function scan(dir) {
4082
4315
  try {
4083
- const entries = await fs5__namespace.readdir(dir, { withFileTypes: true });
4316
+ const entries = await fs4__namespace.readdir(dir, { withFileTypes: true });
4084
4317
  for (const entry of entries) {
4085
4318
  if (entry.isDirectory()) {
4086
4319
  if (!IGNORED_DIRS.includes(entry.name)) {
@@ -4123,8 +4356,8 @@ ${response}`;
4123
4356
  * 确保规范目录存在
4124
4357
  */
4125
4358
  async ensureNormsDir() {
4126
- await fs5__namespace.mkdir(this.config.normsDir, { recursive: true });
4127
- await fs5__namespace.mkdir(path5__namespace.join(this.config.normsDir, "weekly"), { recursive: true });
4359
+ await fs4__namespace.mkdir(this.config.normsDir, { recursive: true });
4360
+ await fs4__namespace.mkdir(path5__namespace.join(this.config.normsDir, "weekly"), { recursive: true });
4128
4361
  }
4129
4362
  /**
4130
4363
  * 加载已有规范
@@ -4132,7 +4365,7 @@ ${response}`;
4132
4365
  async loadStandards() {
4133
4366
  const standardsPath = path5__namespace.join(this.config.normsDir, "patterns.json");
4134
4367
  try {
4135
- const content = await fs5__namespace.readFile(standardsPath, "utf-8");
4368
+ const content = await fs4__namespace.readFile(standardsPath, "utf-8");
4136
4369
  const data = JSON.parse(content);
4137
4370
  for (const standard of data) {
4138
4371
  this.standards.set(standard.id, {
@@ -4150,7 +4383,7 @@ ${response}`;
4150
4383
  async loadWeights() {
4151
4384
  const weightsPath = path5__namespace.join(this.config.normsDir, "weights.json");
4152
4385
  try {
4153
- const content = await fs5__namespace.readFile(weightsPath, "utf-8");
4386
+ const content = await fs4__namespace.readFile(weightsPath, "utf-8");
4154
4387
  const data = JSON.parse(content);
4155
4388
  for (const weight of data) {
4156
4389
  this.weights.set(weight.standardId, {
@@ -4166,7 +4399,7 @@ ${response}`;
4166
4399
  */
4167
4400
  async saveStandards() {
4168
4401
  const standardsPath = path5__namespace.join(this.config.normsDir, "patterns.json");
4169
- await fs5__namespace.writeFile(
4402
+ await fs4__namespace.writeFile(
4170
4403
  standardsPath,
4171
4404
  JSON.stringify(Array.from(this.standards.values()), null, 2),
4172
4405
  "utf-8"
@@ -4177,7 +4410,7 @@ ${response}`;
4177
4410
  */
4178
4411
  async saveWeights() {
4179
4412
  const weightsPath = path5__namespace.join(this.config.normsDir, "weights.json");
4180
- await fs5__namespace.writeFile(
4413
+ await fs4__namespace.writeFile(
4181
4414
  weightsPath,
4182
4415
  JSON.stringify(Array.from(this.weights.values()), null, 2),
4183
4416
  "utf-8"
@@ -4205,7 +4438,7 @@ ${response}`;
4205
4438
  */
4206
4439
  async saveWeeklyReport(weekId, report) {
4207
4440
  const reportPath = path5__namespace.join(this.config.normsDir, "weekly", `${weekId}.json`);
4208
- await fs5__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
4441
+ await fs4__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
4209
4442
  }
4210
4443
  /**
4211
4444
  * 更新 devstanded.md
@@ -4214,7 +4447,7 @@ ${response}`;
4214
4447
  const standards = this.getEffectiveStandards();
4215
4448
  const content = this.generateDevStandedMd(standards);
4216
4449
  const mdPath = path5__namespace.join(this.config.normsDir, "devstanded.md");
4217
- await fs5__namespace.writeFile(mdPath, content, "utf-8");
4450
+ await fs4__namespace.writeFile(mdPath, content, "utf-8");
4218
4451
  }
4219
4452
  /**
4220
4453
  * 生成 devstanded.md 内容
@@ -4353,7 +4586,7 @@ async function handleInit(args, ctx) {
4353
4586
  async function initProject(options = {}, workingDir) {
4354
4587
  const cwd = workingDir || process.cwd();
4355
4588
  try {
4356
- const stats = await fs5__namespace.stat(cwd);
4589
+ const stats = await fs4__namespace.stat(cwd);
4357
4590
  if (!stats.isDirectory()) {
4358
4591
  return {
4359
4592
  output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
@@ -4385,7 +4618,7 @@ async function initProject(options = {}, workingDir) {
4385
4618
  await normsManager.initialize();
4386
4619
  const scanResult = await normsManager.scanProject(cwd);
4387
4620
  const agentsContent = generateAgentsMd(projectInfo, scanResult);
4388
- await fs5__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
4621
+ await fs4__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
4389
4622
  await generateOpenSpecConfig(openspecDir, projectInfo);
4390
4623
  return {
4391
4624
  output: chalk9__default.default.green("\u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210\n") + chalk9__default.default.gray(` \u9879\u76EE\u7C7B\u578B: ${projectInfo.type}
@@ -4426,7 +4659,7 @@ async function createSfCliDirectory(basePath) {
4426
4659
  "logs"
4427
4660
  ];
4428
4661
  for (const dir of dirs) {
4429
- await fs5__namespace.mkdir(path5__namespace.join(basePath, dir), { recursive: true });
4662
+ await fs4__namespace.mkdir(path5__namespace.join(basePath, dir), { recursive: true });
4430
4663
  }
4431
4664
  const config = {
4432
4665
  version: "1.0.0",
@@ -4434,22 +4667,22 @@ async function createSfCliDirectory(basePath) {
4434
4667
  yolo: false,
4435
4668
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
4436
4669
  };
4437
- await fs5__namespace.writeFile(
4670
+ await fs4__namespace.writeFile(
4438
4671
  path5__namespace.join(basePath, "config.json"),
4439
4672
  JSON.stringify(config, null, 2),
4440
4673
  "utf-8"
4441
4674
  );
4442
- await fs5__namespace.writeFile(
4675
+ await fs4__namespace.writeFile(
4443
4676
  path5__namespace.join(basePath, "agents", "registry.json"),
4444
4677
  JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
4445
4678
  "utf-8"
4446
4679
  );
4447
- await fs5__namespace.writeFile(
4680
+ await fs4__namespace.writeFile(
4448
4681
  path5__namespace.join(basePath, "skills", "registry.json"),
4449
4682
  JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
4450
4683
  "utf-8"
4451
4684
  );
4452
- await fs5__namespace.writeFile(
4685
+ await fs4__namespace.writeFile(
4453
4686
  path5__namespace.join(basePath, "health", "health.md"),
4454
4687
  generateHealthTemplate(),
4455
4688
  "utf-8"
@@ -4459,8 +4692,8 @@ async function createOpenSpecDirectory(basePath) {
4459
4692
  const changesDir = path5__namespace.join(basePath, "changes");
4460
4693
  const archiveDir = path5__namespace.join(changesDir, "archive");
4461
4694
  const specDir = path5__namespace.join(basePath, "spec");
4462
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
4463
- await fs5__namespace.mkdir(specDir, { recursive: true });
4695
+ await fs4__namespace.mkdir(archiveDir, { recursive: true });
4696
+ await fs4__namespace.mkdir(specDir, { recursive: true });
4464
4697
  }
4465
4698
  async function analyzeProject(cwd) {
4466
4699
  const result = {
@@ -4485,7 +4718,7 @@ async function analyzeProject(cwd) {
4485
4718
  };
4486
4719
  const pkgPath = path5__namespace.join(cwd, "package.json");
4487
4720
  try {
4488
- const pkgContent = await fs5__namespace.readFile(pkgPath, "utf-8");
4721
+ const pkgContent = await fs4__namespace.readFile(pkgPath, "utf-8");
4489
4722
  const pkg = JSON.parse(pkgContent);
4490
4723
  result.name = pkg.name || result.name;
4491
4724
  result.dependencies = pkg.dependencies || {};
@@ -4568,7 +4801,7 @@ async function analyzeDirectoryStructure(cwd) {
4568
4801
  others: []
4569
4802
  };
4570
4803
  try {
4571
- const entries = await fs5__namespace.readdir(cwd, { withFileTypes: true });
4804
+ const entries = await fs4__namespace.readdir(cwd, { withFileTypes: true });
4572
4805
  for (const entry of entries) {
4573
4806
  if (!entry.isDirectory()) continue;
4574
4807
  const name = entry.name;
@@ -4613,7 +4846,7 @@ async function findEntryPoints(cwd) {
4613
4846
  }
4614
4847
  async function saveProjectAnalysis(sfCliDir, analysis) {
4615
4848
  const analysisPath = path5__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
4616
- await fs5__namespace.writeFile(
4849
+ await fs4__namespace.writeFile(
4617
4850
  analysisPath,
4618
4851
  JSON.stringify(analysis, null, 2),
4619
4852
  "utf-8"
@@ -4654,7 +4887,7 @@ architecture:
4654
4887
  # \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
4655
4888
  standards: []
4656
4889
  `;
4657
- await fs5__namespace.writeFile(configPath, content, "utf-8");
4890
+ await fs4__namespace.writeFile(configPath, content, "utf-8");
4658
4891
  }
4659
4892
  function generateAgentsMd(info, scanResult) {
4660
4893
  const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
@@ -4776,7 +5009,7 @@ function generateHealthTemplate() {
4776
5009
  }
4777
5010
  async function fileExists(filePath) {
4778
5011
  try {
4779
- await fs5__namespace.access(filePath);
5012
+ await fs4__namespace.access(filePath);
4780
5013
  return true;
4781
5014
  } catch {
4782
5015
  return false;
@@ -5243,19 +5476,19 @@ var WorkflowEngine = class {
5243
5476
  async loadProjectContext() {
5244
5477
  const agentsMdPath = path5__namespace.join(this.projectPath, "AGENTS.md");
5245
5478
  try {
5246
- this.projectContext = await fs5__namespace.readFile(agentsMdPath, "utf-8");
5479
+ this.projectContext = await fs4__namespace.readFile(agentsMdPath, "utf-8");
5247
5480
  } catch {
5248
5481
  this.projectContext = "";
5249
5482
  }
5250
5483
  const configPath = path5__namespace.join(this.openspecPath, "config.yaml");
5251
5484
  try {
5252
- this.projectConfig = await fs5__namespace.readFile(configPath, "utf-8");
5485
+ this.projectConfig = await fs4__namespace.readFile(configPath, "utf-8");
5253
5486
  } catch {
5254
5487
  this.projectConfig = "";
5255
5488
  }
5256
5489
  const devstandedPath = path5__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
5257
5490
  try {
5258
- this.devStandards = await fs5__namespace.readFile(devstandedPath, "utf-8");
5491
+ this.devStandards = await fs4__namespace.readFile(devstandedPath, "utf-8");
5259
5492
  } catch {
5260
5493
  this.devStandards = "";
5261
5494
  }
@@ -5284,7 +5517,7 @@ var WorkflowEngine = class {
5284
5517
  const specPath = this.getSpecFilePath();
5285
5518
  if (!specPath) return false;
5286
5519
  try {
5287
- await fs5__namespace.access(specPath);
5520
+ await fs4__namespace.access(specPath);
5288
5521
  return true;
5289
5522
  } catch {
5290
5523
  return false;
@@ -5518,11 +5751,11 @@ var WorkflowEngine = class {
5518
5751
  const workflows = [];
5519
5752
  const changesDir = path5__namespace.join(this.openspecPath, "changes");
5520
5753
  try {
5521
- const files = await fs5__namespace.readdir(changesDir);
5754
+ const files = await fs4__namespace.readdir(changesDir);
5522
5755
  for (const file of files) {
5523
5756
  if (!file.endsWith(".md") || file.includes("-spec.md")) continue;
5524
5757
  const filePath = path5__namespace.join(changesDir, file);
5525
- const content = await fs5__namespace.readFile(filePath, "utf-8");
5758
+ const content = await fs4__namespace.readFile(filePath, "utf-8");
5526
5759
  const state = this.parseChangeRecord(content);
5527
5760
  if (state && state.status === "running") {
5528
5761
  workflows.push(state);
@@ -5573,7 +5806,7 @@ var WorkflowEngine = class {
5573
5806
  }
5574
5807
  const statePath = path5__namespace.join(this.openspecPath, ".workflow-states", `${changeId}.json`);
5575
5808
  try {
5576
- const content = await fs5__namespace.readFile(statePath, "utf-8");
5809
+ const content = await fs4__namespace.readFile(statePath, "utf-8");
5577
5810
  this.state = JSON.parse(content, (key, value) => {
5578
5811
  if (key.endsWith("At") && typeof value === "string") {
5579
5812
  return new Date(value);
@@ -5586,7 +5819,7 @@ var WorkflowEngine = class {
5586
5819
  const changesDir = path5__namespace.join(this.openspecPath, "changes");
5587
5820
  const changeFile = path5__namespace.join(changesDir, `${changeId}.md`);
5588
5821
  try {
5589
- const content = await fs5__namespace.readFile(changeFile, "utf-8");
5822
+ const content = await fs4__namespace.readFile(changeFile, "utf-8");
5590
5823
  const parsed = this.parseChangeRecord(content);
5591
5824
  if (parsed && parsed.status === "running") {
5592
5825
  this.state = parsed;
@@ -5651,8 +5884,8 @@ var WorkflowEngine = class {
5651
5884
  const archiveDir = path5__namespace.join(changesDir, "archive");
5652
5885
  const changeFile = path5__namespace.join(changesDir, `${changeId}.md`);
5653
5886
  const archiveFile = path5__namespace.join(archiveDir, `${changeId}.md`);
5654
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
5655
- await fs5__namespace.rename(changeFile, archiveFile).catch(() => {
5887
+ await fs4__namespace.mkdir(archiveDir, { recursive: true });
5888
+ await fs4__namespace.rename(changeFile, archiveFile).catch(() => {
5656
5889
  });
5657
5890
  this.state = null;
5658
5891
  this.snapshots.clear();
@@ -5678,15 +5911,15 @@ var WorkflowEngine = class {
5678
5911
  const archiveDir = path5__namespace.join(changesDir, "archive");
5679
5912
  const specDir = path5__namespace.join(this.openspecPath, "spec");
5680
5913
  const statesDir = path5__namespace.join(this.openspecPath, ".workflow-states");
5681
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
5682
- await fs5__namespace.mkdir(specDir, { recursive: true });
5683
- await fs5__namespace.mkdir(statesDir, { recursive: true });
5914
+ await fs4__namespace.mkdir(archiveDir, { recursive: true });
5915
+ await fs4__namespace.mkdir(specDir, { recursive: true });
5916
+ await fs4__namespace.mkdir(statesDir, { recursive: true });
5684
5917
  }
5685
5918
  async restoreState() {
5686
5919
  const activePath = path5__namespace.join(this.openspecPath, ".workflow-active.json");
5687
5920
  let activeId = null;
5688
5921
  try {
5689
- const activeContent = await fs5__namespace.readFile(activePath, "utf-8");
5922
+ const activeContent = await fs4__namespace.readFile(activePath, "utf-8");
5690
5923
  const activeData = JSON.parse(activeContent);
5691
5924
  activeId = activeData.activeId;
5692
5925
  } catch {
@@ -5694,7 +5927,7 @@ var WorkflowEngine = class {
5694
5927
  if (activeId) {
5695
5928
  const statePath = path5__namespace.join(this.openspecPath, ".workflow-states", `${activeId}.json`);
5696
5929
  try {
5697
- const content = await fs5__namespace.readFile(statePath, "utf-8");
5930
+ const content = await fs4__namespace.readFile(statePath, "utf-8");
5698
5931
  this.state = JSON.parse(content, (key, value) => {
5699
5932
  if (key.endsWith("At") && typeof value === "string") {
5700
5933
  return new Date(value);
@@ -5707,7 +5940,7 @@ var WorkflowEngine = class {
5707
5940
  }
5708
5941
  const oldStatePath = path5__namespace.join(this.openspecPath, ".workflow-state.json");
5709
5942
  try {
5710
- const content = await fs5__namespace.readFile(oldStatePath, "utf-8");
5943
+ const content = await fs4__namespace.readFile(oldStatePath, "utf-8");
5711
5944
  this.state = JSON.parse(content, (key, value) => {
5712
5945
  if (key.endsWith("At") && typeof value === "string") {
5713
5946
  return new Date(value);
@@ -5716,7 +5949,7 @@ var WorkflowEngine = class {
5716
5949
  });
5717
5950
  if (this.state) {
5718
5951
  await this.saveState();
5719
- await fs5__namespace.unlink(oldStatePath).catch(() => {
5952
+ await fs4__namespace.unlink(oldStatePath).catch(() => {
5720
5953
  });
5721
5954
  }
5722
5955
  } catch (e) {
@@ -5730,16 +5963,16 @@ var WorkflowEngine = class {
5730
5963
  async saveState() {
5731
5964
  if (!this.state) return;
5732
5965
  const statesDir = path5__namespace.join(this.openspecPath, ".workflow-states");
5733
- await fs5__namespace.mkdir(statesDir, { recursive: true });
5966
+ await fs4__namespace.mkdir(statesDir, { recursive: true });
5734
5967
  const statePath = path5__namespace.join(statesDir, `${this.state.id}.json`);
5735
- await fs5__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
5968
+ await fs4__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
5736
5969
  const activePath = path5__namespace.join(this.openspecPath, ".workflow-active.json");
5737
- await fs5__namespace.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
5970
+ await fs4__namespace.writeFile(activePath, JSON.stringify({ activeId: this.state.id }, null, 2));
5738
5971
  }
5739
5972
  async restoreSnapshots() {
5740
5973
  const snapshotsPath = path5__namespace.join(this.openspecPath, ".workflow-snapshots.json");
5741
5974
  try {
5742
- const content = await fs5__namespace.readFile(snapshotsPath, "utf-8");
5975
+ const content = await fs4__namespace.readFile(snapshotsPath, "utf-8");
5743
5976
  const data = JSON.parse(content, (key, value) => {
5744
5977
  if (key === "timestamp" && typeof value === "string") {
5745
5978
  return new Date(value);
@@ -5756,7 +5989,7 @@ var WorkflowEngine = class {
5756
5989
  async saveSnapshots() {
5757
5990
  const snapshotsPath = path5__namespace.join(this.openspecPath, ".workflow-snapshots.json");
5758
5991
  const data = Array.from(this.snapshots.values());
5759
- await fs5__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
5992
+ await fs4__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
5760
5993
  }
5761
5994
  async createSnapshot() {
5762
5995
  if (!this.state) return;
@@ -5777,7 +6010,7 @@ var WorkflowEngine = class {
5777
6010
  async createChangeRecord() {
5778
6011
  if (!this.state) return;
5779
6012
  const changePath = path5__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
5780
- await fs5__namespace.writeFile(changePath, this.formatChangeRecord());
6013
+ await fs4__namespace.writeFile(changePath, this.formatChangeRecord());
5781
6014
  }
5782
6015
  async updateChangeRecord(status) {
5783
6016
  if (!this.state) return;
@@ -5785,7 +6018,7 @@ var WorkflowEngine = class {
5785
6018
  this.state.status = status;
5786
6019
  }
5787
6020
  const changePath = path5__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
5788
- await fs5__namespace.writeFile(changePath, this.formatChangeRecord());
6021
+ await fs4__namespace.writeFile(changePath, this.formatChangeRecord());
5789
6022
  }
5790
6023
  formatChangeRecord() {
5791
6024
  if (!this.state) return "";
@@ -5849,7 +6082,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
5849
6082
 
5850
6083
  ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
5851
6084
  `;
5852
- await fs5__namespace.writeFile(specPath, content);
6085
+ await fs4__namespace.writeFile(specPath, content);
5853
6086
  }
5854
6087
  };
5855
6088
  var ConfirmationRequiredError = class extends Error {
@@ -6346,15 +6579,15 @@ async function loadProjectContext(workingDirectory) {
6346
6579
  devStandards: ""
6347
6580
  };
6348
6581
  try {
6349
- context.agentsMd = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
6582
+ context.agentsMd = await fs4__namespace.readFile(path5__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
6350
6583
  } catch {
6351
6584
  }
6352
6585
  try {
6353
- context.configYaml = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
6586
+ context.configYaml = await fs4__namespace.readFile(path5__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
6354
6587
  } catch {
6355
6588
  }
6356
6589
  try {
6357
- context.devStandards = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
6590
+ context.devStandards = await fs4__namespace.readFile(path5__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
6358
6591
  } catch {
6359
6592
  }
6360
6593
  return context;
@@ -7276,9 +7509,9 @@ async function handleFileReference(filePath, ctx) {
7276
7509
  const cwd = ctx.options.workingDirectory;
7277
7510
  const absolutePath = path5__namespace.isAbsolute(filePath) ? filePath : path5__namespace.join(cwd, filePath);
7278
7511
  try {
7279
- const stats = await fs5__namespace.stat(absolutePath);
7512
+ const stats = await fs4__namespace.stat(absolutePath);
7280
7513
  if (stats.isDirectory()) {
7281
- const files = await fs5__namespace.readdir(absolutePath);
7514
+ const files = await fs4__namespace.readdir(absolutePath);
7282
7515
  return {
7283
7516
  output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
7284
7517
  ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
@@ -7286,7 +7519,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
7286
7519
  contextUsed: 0
7287
7520
  };
7288
7521
  }
7289
- const content = await fs5__namespace.readFile(absolutePath, "utf-8");
7522
+ const content = await fs4__namespace.readFile(absolutePath, "utf-8");
7290
7523
  const lines = content.split("\n");
7291
7524
  ctx.contextManager.addMessage({
7292
7525
  role: "user",
@@ -7872,14 +8105,14 @@ ${summary}`,
7872
8105
  async persist() {
7873
8106
  if (!this.persistPath) return;
7874
8107
  const dir = path5__namespace.dirname(this.persistPath);
7875
- await fs5__namespace.mkdir(dir, { recursive: true });
8108
+ await fs4__namespace.mkdir(dir, { recursive: true });
7876
8109
  const data = {
7877
8110
  messages: this.state.messages,
7878
8111
  totalTokens: this.state.totalTokens,
7879
8112
  limit: this.state.limit,
7880
8113
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
7881
8114
  };
7882
- await fs5__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
8115
+ await fs4__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
7883
8116
  }
7884
8117
  /**
7885
8118
  * 加载持久化的上下文
@@ -7887,7 +8120,7 @@ ${summary}`,
7887
8120
  async loadPersistedContext() {
7888
8121
  if (!this.persistPath) return;
7889
8122
  try {
7890
- const content = await fs5__namespace.readFile(this.persistPath, "utf-8");
8123
+ const content = await fs4__namespace.readFile(this.persistPath, "utf-8");
7891
8124
  const data = JSON.parse(content);
7892
8125
  this.state.messages = data.messages || [];
7893
8126
  this.state.totalTokens = data.totalTokens || 0;
@@ -7976,7 +8209,7 @@ var ConfigManager = class {
7976
8209
  this.projectPath = projectPath;
7977
8210
  this.configPath = path5__namespace.join(projectPath, ".sf-cli", "config.json");
7978
8211
  try {
7979
- const content = await fs5__namespace.readFile(this.configPath, "utf-8");
8212
+ const content = await fs4__namespace.readFile(this.configPath, "utf-8");
7980
8213
  const loaded = JSON.parse(content);
7981
8214
  if (loaded.apiKey && loaded.apiKeyEncrypted) {
7982
8215
  loaded.apiKey = this.decrypt(loaded.apiKey);
@@ -7995,8 +8228,8 @@ var ConfigManager = class {
7995
8228
  configToSave.apiKey = encrypted;
7996
8229
  configToSave.apiKeyEncrypted = true;
7997
8230
  }
7998
- await fs5__namespace.mkdir(path5__namespace.dirname(this.configPath), { recursive: true });
7999
- await fs5__namespace.writeFile(
8231
+ await fs4__namespace.mkdir(path5__namespace.dirname(this.configPath), { recursive: true });
8232
+ await fs4__namespace.writeFile(
8000
8233
  this.configPath,
8001
8234
  JSON.stringify(configToSave, null, 2),
8002
8235
  "utf-8"
@@ -8248,8 +8481,8 @@ var ModelService = class {
8248
8481
  const dailyPath = path5__namespace.join(this.statsPath, "daily.json");
8249
8482
  const totalPath = path5__namespace.join(this.statsPath, "total.json");
8250
8483
  const [daily, total] = await Promise.all([
8251
- fs5__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
8252
- fs5__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
8484
+ fs4__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
8485
+ fs4__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
8253
8486
  ]);
8254
8487
  const dailyData = JSON.parse(daily);
8255
8488
  const totalData = JSON.parse(total);
@@ -8262,12 +8495,12 @@ var ModelService = class {
8262
8495
  async saveStats() {
8263
8496
  if (!this.statsPath) return;
8264
8497
  try {
8265
- await fs5__namespace.mkdir(this.statsPath, { recursive: true });
8498
+ await fs4__namespace.mkdir(this.statsPath, { recursive: true });
8266
8499
  const dailyPath = path5__namespace.join(this.statsPath, "daily.json");
8267
8500
  const totalPath = path5__namespace.join(this.statsPath, "total.json");
8268
8501
  await Promise.all([
8269
- fs5__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
8270
- fs5__namespace.writeFile(totalPath, JSON.stringify({
8502
+ fs4__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
8503
+ fs4__namespace.writeFile(totalPath, JSON.stringify({
8271
8504
  totalInput: this.stats.totalInput,
8272
8505
  totalOutput: this.stats.totalOutput
8273
8506
  }))
@@ -8480,7 +8713,7 @@ var Completer = class {
8480
8713
  prefix = filePath.slice(lastSlash + 1);
8481
8714
  }
8482
8715
  try {
8483
- const entries = await fs5__namespace.readdir(dirPath, { withFileTypes: true });
8716
+ const entries = await fs4__namespace.readdir(dirPath, { withFileTypes: true });
8484
8717
  const matches = [];
8485
8718
  for (const entry of entries) {
8486
8719
  if (entry.name.startsWith(prefix)) {
@@ -8562,7 +8795,7 @@ async function startInteractiveMode(options) {
8562
8795
  const historyFile = path5__namespace.join(options.workingDirectory, ".sf-cli", "history.json");
8563
8796
  let history = [];
8564
8797
  try {
8565
- const historyData = await fs5__namespace.readFile(historyFile, "utf-8");
8798
+ const historyData = await fs4__namespace.readFile(historyFile, "utf-8");
8566
8799
  history = JSON.parse(historyData);
8567
8800
  } catch {
8568
8801
  }
@@ -8649,8 +8882,8 @@ async function startInteractiveMode(options) {
8649
8882
  }
8650
8883
  const saveHistory = async () => {
8651
8884
  try {
8652
- await fs5__namespace.mkdir(path5__namespace.dirname(historyFile), { recursive: true });
8653
- await fs5__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
8885
+ await fs4__namespace.mkdir(path5__namespace.dirname(historyFile), { recursive: true });
8886
+ await fs4__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
8654
8887
  } catch {
8655
8888
  }
8656
8889
  };