@nick848/sf-cli 1.0.1 → 1.0.3

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
@@ -3,11 +3,11 @@
3
3
 
4
4
  var commander = require('commander');
5
5
  var chalk9 = require('chalk');
6
+ var fs9 = require('fs');
7
+ var path6 = require('path');
6
8
  var readline = require('readline');
7
- var path5 = require('path');
8
- var fs5 = require('fs/promises');
9
+ var fs6 = require('fs/promises');
9
10
  var enquirer = require('enquirer');
10
- var fsSync = require('fs');
11
11
  var crypto = require('crypto');
12
12
  var os = require('os');
13
13
  var tiktoken = require('tiktoken');
@@ -15,7 +15,6 @@ require('@modelcontextprotocol/sdk/client/index.js');
15
15
  require('@modelcontextprotocol/sdk/client/stdio.js');
16
16
  var child_process = require('child_process');
17
17
  require('uuid');
18
- var module$1 = require('module');
19
18
 
20
19
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
21
20
 
@@ -38,17 +37,13 @@ function _interopNamespace(e) {
38
37
  }
39
38
 
40
39
  var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
40
+ var fs9__namespace = /*#__PURE__*/_interopNamespace(fs9);
41
+ var path6__namespace = /*#__PURE__*/_interopNamespace(path6);
41
42
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
42
- var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
43
- var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
44
- var fsSync__namespace = /*#__PURE__*/_interopNamespace(fsSync);
43
+ var fs6__namespace = /*#__PURE__*/_interopNamespace(fs6);
45
44
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
46
45
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
47
46
 
48
- // node_modules/tsup/assets/cjs_shims.js
49
- var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
50
- var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
51
-
52
47
  // src/cli/parser.ts
53
48
  var CommandParser = class {
54
49
  slashCommands = [
@@ -130,8 +125,8 @@ var CommandParser = class {
130
125
  };
131
126
  }
132
127
  parseAtPath(input) {
133
- const path12 = input.slice(1).trim();
134
- if (!path12) {
128
+ const path16 = input.slice(1).trim();
129
+ if (!path16) {
135
130
  return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
136
131
  }
137
132
  return {
@@ -139,7 +134,7 @@ var CommandParser = class {
139
134
  command: {
140
135
  type: "at" /* AT */,
141
136
  raw: input,
142
- path: path12
137
+ path: path16
143
138
  }
144
139
  };
145
140
  }
@@ -211,11 +206,11 @@ var NormsManager = class {
211
206
  const files = await this.collectProjectFiles(projectPath);
212
207
  for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
213
208
  try {
214
- const stats = await fs5__namespace.stat(filePath);
209
+ const stats = await fs6__namespace.stat(filePath);
215
210
  if (stats.size > MAX_FILE_SIZE) {
216
211
  continue;
217
212
  }
218
- const content = await fs5__namespace.readFile(filePath, "utf-8");
213
+ const content = await fs6__namespace.readFile(filePath, "utf-8");
219
214
  const patterns = await this.learnFromFile(filePath, content);
220
215
  result.patternsFound += patterns.length;
221
216
  result.filesScanned++;
@@ -238,7 +233,7 @@ var NormsManager = class {
238
233
  * 从单个文件学习规范
239
234
  */
240
235
  async learnFromFile(filePath, content) {
241
- const ext = path5__namespace.extname(filePath);
236
+ const ext = path6__namespace.extname(filePath);
242
237
  const patterns = this.extractPatterns(filePath, content, ext);
243
238
  for (const pattern of patterns) {
244
239
  await this.recordOccurrence({
@@ -841,16 +836,16 @@ ${response}`;
841
836
  const files = [];
842
837
  async function scan(dir) {
843
838
  try {
844
- const entries = await fs5__namespace.readdir(dir, { withFileTypes: true });
839
+ const entries = await fs6__namespace.readdir(dir, { withFileTypes: true });
845
840
  for (const entry of entries) {
846
841
  if (entry.isDirectory()) {
847
842
  if (!IGNORED_DIRS.includes(entry.name)) {
848
- await scan(path5__namespace.join(dir, entry.name));
843
+ await scan(path6__namespace.join(dir, entry.name));
849
844
  }
850
845
  } else if (entry.isFile()) {
851
- const ext = path5__namespace.extname(entry.name);
846
+ const ext = path6__namespace.extname(entry.name);
852
847
  if (SCAN_EXTENSIONS.includes(ext)) {
853
- files.push(path5__namespace.join(dir, entry.name));
848
+ files.push(path6__namespace.join(dir, entry.name));
854
849
  }
855
850
  }
856
851
  }
@@ -884,16 +879,16 @@ ${response}`;
884
879
  * 确保规范目录存在
885
880
  */
886
881
  async ensureNormsDir() {
887
- await fs5__namespace.mkdir(this.config.normsDir, { recursive: true });
888
- await fs5__namespace.mkdir(path5__namespace.join(this.config.normsDir, "weekly"), { recursive: true });
882
+ await fs6__namespace.mkdir(this.config.normsDir, { recursive: true });
883
+ await fs6__namespace.mkdir(path6__namespace.join(this.config.normsDir, "weekly"), { recursive: true });
889
884
  }
890
885
  /**
891
886
  * 加载已有规范
892
887
  */
893
888
  async loadStandards() {
894
- const standardsPath = path5__namespace.join(this.config.normsDir, "patterns.json");
889
+ const standardsPath = path6__namespace.join(this.config.normsDir, "patterns.json");
895
890
  try {
896
- const content = await fs5__namespace.readFile(standardsPath, "utf-8");
891
+ const content = await fs6__namespace.readFile(standardsPath, "utf-8");
897
892
  const data = JSON.parse(content);
898
893
  for (const standard of data) {
899
894
  this.standards.set(standard.id, {
@@ -909,9 +904,9 @@ ${response}`;
909
904
  * 加载权重数据
910
905
  */
911
906
  async loadWeights() {
912
- const weightsPath = path5__namespace.join(this.config.normsDir, "weights.json");
907
+ const weightsPath = path6__namespace.join(this.config.normsDir, "weights.json");
913
908
  try {
914
- const content = await fs5__namespace.readFile(weightsPath, "utf-8");
909
+ const content = await fs6__namespace.readFile(weightsPath, "utf-8");
915
910
  const data = JSON.parse(content);
916
911
  for (const weight of data) {
917
912
  this.weights.set(weight.standardId, {
@@ -926,8 +921,8 @@ ${response}`;
926
921
  * 保存规范
927
922
  */
928
923
  async saveStandards() {
929
- const standardsPath = path5__namespace.join(this.config.normsDir, "patterns.json");
930
- await fs5__namespace.writeFile(
924
+ const standardsPath = path6__namespace.join(this.config.normsDir, "patterns.json");
925
+ await fs6__namespace.writeFile(
931
926
  standardsPath,
932
927
  JSON.stringify(Array.from(this.standards.values()), null, 2),
933
928
  "utf-8"
@@ -937,8 +932,8 @@ ${response}`;
937
932
  * 保存权重
938
933
  */
939
934
  async saveWeights() {
940
- const weightsPath = path5__namespace.join(this.config.normsDir, "weights.json");
941
- await fs5__namespace.writeFile(
935
+ const weightsPath = path6__namespace.join(this.config.normsDir, "weights.json");
936
+ await fs6__namespace.writeFile(
942
937
  weightsPath,
943
938
  JSON.stringify(Array.from(this.weights.values()), null, 2),
944
939
  "utf-8"
@@ -965,8 +960,8 @@ ${response}`;
965
960
  * 保存周报
966
961
  */
967
962
  async saveWeeklyReport(weekId, report) {
968
- const reportPath = path5__namespace.join(this.config.normsDir, "weekly", `${weekId}.json`);
969
- await fs5__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
963
+ const reportPath = path6__namespace.join(this.config.normsDir, "weekly", `${weekId}.json`);
964
+ await fs6__namespace.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
970
965
  }
971
966
  /**
972
967
  * 更新 devstanded.md
@@ -974,8 +969,8 @@ ${response}`;
974
969
  async updateDevStandedMd() {
975
970
  const standards = this.getEffectiveStandards();
976
971
  const content = this.generateDevStandedMd(standards);
977
- const mdPath = path5__namespace.join(this.config.normsDir, "devstanded.md");
978
- await fs5__namespace.writeFile(mdPath, content, "utf-8");
972
+ const mdPath = path6__namespace.join(this.config.normsDir, "devstanded.md");
973
+ await fs6__namespace.writeFile(mdPath, content, "utf-8");
979
974
  }
980
975
  /**
981
976
  * 生成 devstanded.md 内容
@@ -1114,7 +1109,7 @@ async function handleInit(args, ctx) {
1114
1109
  async function initProject(options = {}, workingDir) {
1115
1110
  const cwd = workingDir || process.cwd();
1116
1111
  try {
1117
- const stats = await fs5__namespace.stat(cwd);
1112
+ const stats = await fs6__namespace.stat(cwd);
1118
1113
  if (!stats.isDirectory()) {
1119
1114
  return {
1120
1115
  output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
@@ -1125,9 +1120,9 @@ async function initProject(options = {}, workingDir) {
1125
1120
  output: chalk9__default.default.red(`\u9519\u8BEF: \u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6743\u9650\u8BBF\u95EE ${cwd}`)
1126
1121
  };
1127
1122
  }
1128
- const sfCliDir = path5__namespace.join(cwd, ".sf-cli");
1129
- const openspecDir = path5__namespace.join(cwd, "openspec");
1130
- const agentsMdPath = path5__namespace.join(cwd, "AGENTS.md");
1123
+ const sfCliDir = path6__namespace.join(cwd, ".sf-cli");
1124
+ const openspecDir = path6__namespace.join(cwd, "openspec");
1125
+ const agentsMdPath = path6__namespace.join(cwd, "AGENTS.md");
1131
1126
  try {
1132
1127
  const agentsExists = await fileExists(agentsMdPath);
1133
1128
  if (agentsExists && !options.force) {
@@ -1146,7 +1141,7 @@ async function initProject(options = {}, workingDir) {
1146
1141
  await normsManager.initialize();
1147
1142
  const scanResult = await normsManager.scanProject(cwd);
1148
1143
  const agentsContent = generateAgentsMd(projectInfo, scanResult);
1149
- await fs5__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
1144
+ await fs6__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
1150
1145
  await generateOpenSpecConfig(openspecDir, projectInfo);
1151
1146
  return {
1152
1147
  output: chalk9__default.default.green("\u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210\n") + chalk9__default.default.gray(` \u9879\u76EE\u7C7B\u578B: ${projectInfo.type}
@@ -1187,7 +1182,7 @@ async function createSfCliDirectory(basePath) {
1187
1182
  "logs"
1188
1183
  ];
1189
1184
  for (const dir of dirs) {
1190
- await fs5__namespace.mkdir(path5__namespace.join(basePath, dir), { recursive: true });
1185
+ await fs6__namespace.mkdir(path6__namespace.join(basePath, dir), { recursive: true });
1191
1186
  }
1192
1187
  const config = {
1193
1188
  version: "1.0.0",
@@ -1195,37 +1190,37 @@ async function createSfCliDirectory(basePath) {
1195
1190
  yolo: false,
1196
1191
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
1197
1192
  };
1198
- await fs5__namespace.writeFile(
1199
- path5__namespace.join(basePath, "config.json"),
1193
+ await fs6__namespace.writeFile(
1194
+ path6__namespace.join(basePath, "config.json"),
1200
1195
  JSON.stringify(config, null, 2),
1201
1196
  "utf-8"
1202
1197
  );
1203
- await fs5__namespace.writeFile(
1204
- path5__namespace.join(basePath, "agents", "registry.json"),
1198
+ await fs6__namespace.writeFile(
1199
+ path6__namespace.join(basePath, "agents", "registry.json"),
1205
1200
  JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
1206
1201
  "utf-8"
1207
1202
  );
1208
- await fs5__namespace.writeFile(
1209
- path5__namespace.join(basePath, "skills", "registry.json"),
1203
+ await fs6__namespace.writeFile(
1204
+ path6__namespace.join(basePath, "skills", "registry.json"),
1210
1205
  JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
1211
1206
  "utf-8"
1212
1207
  );
1213
- await fs5__namespace.writeFile(
1214
- path5__namespace.join(basePath, "health", "health.md"),
1208
+ await fs6__namespace.writeFile(
1209
+ path6__namespace.join(basePath, "health", "health.md"),
1215
1210
  generateHealthTemplate(),
1216
1211
  "utf-8"
1217
1212
  );
1218
1213
  }
1219
1214
  async function createOpenSpecDirectory(basePath) {
1220
- const changesDir = path5__namespace.join(basePath, "changes");
1221
- const archiveDir = path5__namespace.join(changesDir, "archive");
1222
- const specDir = path5__namespace.join(basePath, "spec");
1223
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
1224
- await fs5__namespace.mkdir(specDir, { recursive: true });
1215
+ const changesDir = path6__namespace.join(basePath, "changes");
1216
+ const archiveDir = path6__namespace.join(changesDir, "archive");
1217
+ const specDir = path6__namespace.join(basePath, "spec");
1218
+ await fs6__namespace.mkdir(archiveDir, { recursive: true });
1219
+ await fs6__namespace.mkdir(specDir, { recursive: true });
1225
1220
  }
1226
1221
  async function analyzeProject(cwd) {
1227
1222
  const result = {
1228
- name: path5__namespace.basename(cwd),
1223
+ name: path6__namespace.basename(cwd),
1229
1224
  type: "unknown",
1230
1225
  framework: null,
1231
1226
  techStack: [],
@@ -1244,9 +1239,9 @@ async function analyzeProject(cwd) {
1244
1239
  hasEslint: false,
1245
1240
  hasPrettier: false
1246
1241
  };
1247
- const pkgPath = path5__namespace.join(cwd, "package.json");
1242
+ const pkgPath = path6__namespace.join(cwd, "package.json");
1248
1243
  try {
1249
- const pkgContent = await fs5__namespace.readFile(pkgPath, "utf-8");
1244
+ const pkgContent = await fs6__namespace.readFile(pkgPath, "utf-8");
1250
1245
  const pkg = JSON.parse(pkgContent);
1251
1246
  result.name = pkg.name || result.name;
1252
1247
  result.dependencies = pkg.dependencies || {};
@@ -1329,7 +1324,7 @@ async function analyzeDirectoryStructure(cwd) {
1329
1324
  others: []
1330
1325
  };
1331
1326
  try {
1332
- const entries = await fs5__namespace.readdir(cwd, { withFileTypes: true });
1327
+ const entries = await fs6__namespace.readdir(cwd, { withFileTypes: true });
1333
1328
  for (const entry of entries) {
1334
1329
  if (!entry.isDirectory()) continue;
1335
1330
  const name = entry.name;
@@ -1365,7 +1360,7 @@ async function findEntryPoints(cwd) {
1365
1360
  "index.js"
1366
1361
  ];
1367
1362
  for (const entry of possibleEntries) {
1368
- const fullPath = path5__namespace.join(cwd, entry);
1363
+ const fullPath = path6__namespace.join(cwd, entry);
1369
1364
  if (await fileExists(fullPath)) {
1370
1365
  entryPoints.push(entry);
1371
1366
  }
@@ -1373,15 +1368,15 @@ async function findEntryPoints(cwd) {
1373
1368
  return entryPoints;
1374
1369
  }
1375
1370
  async function saveProjectAnalysis(sfCliDir, analysis) {
1376
- const analysisPath = path5__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
1377
- await fs5__namespace.writeFile(
1371
+ const analysisPath = path6__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
1372
+ await fs6__namespace.writeFile(
1378
1373
  analysisPath,
1379
1374
  JSON.stringify(analysis, null, 2),
1380
1375
  "utf-8"
1381
1376
  );
1382
1377
  }
1383
1378
  async function generateOpenSpecConfig(openspecDir, analysis) {
1384
- const configPath = path5__namespace.join(openspecDir, "config.yaml");
1379
+ const configPath = path6__namespace.join(openspecDir, "config.yaml");
1385
1380
  const content = `# OpenSpec \u9879\u76EE\u914D\u7F6E
1386
1381
  # \u6B64\u6587\u4EF6\u5B9A\u4E49\u9879\u76EE\u7684\u57FA\u672C\u4FE1\u606F\uFF0C\u7528\u4E8E\u6307\u5BFC AI \u7406\u89E3\u9879\u76EE\u4E0A\u4E0B\u6587
1387
1382
 
@@ -1415,7 +1410,7 @@ architecture:
1415
1410
  # \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
1416
1411
  standards: []
1417
1412
  `;
1418
- await fs5__namespace.writeFile(configPath, content, "utf-8");
1413
+ await fs6__namespace.writeFile(configPath, content, "utf-8");
1419
1414
  }
1420
1415
  function generateAgentsMd(info, scanResult) {
1421
1416
  const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
@@ -1537,7 +1532,7 @@ function generateHealthTemplate() {
1537
1532
  }
1538
1533
  async function fileExists(filePath) {
1539
1534
  try {
1540
- await fs5__namespace.access(filePath);
1535
+ await fs6__namespace.access(filePath);
1541
1536
  return true;
1542
1537
  } catch {
1543
1538
  return false;
@@ -1708,21 +1703,21 @@ var IV_LENGTH = 16;
1708
1703
  var KEY_DIR = ".sf-cli";
1709
1704
  var KEY_FILE = ".key";
1710
1705
  function getOrCreateEncryptionKey() {
1711
- const keyPath = path5__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
1706
+ const keyPath = path6__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
1712
1707
  try {
1713
- if (fsSync__namespace.existsSync(keyPath)) {
1714
- const keyBase64 = fsSync__namespace.readFileSync(keyPath, "utf-8").trim();
1708
+ if (fs9__namespace.existsSync(keyPath)) {
1709
+ const keyBase64 = fs9__namespace.readFileSync(keyPath, "utf-8").trim();
1715
1710
  return Buffer.from(keyBase64, "base64");
1716
1711
  }
1717
1712
  } catch {
1718
1713
  }
1719
1714
  const key = crypto__namespace.randomBytes(32);
1720
1715
  try {
1721
- const keyDir = path5__namespace.dirname(keyPath);
1722
- if (!fsSync__namespace.existsSync(keyDir)) {
1723
- fsSync__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
1716
+ const keyDir = path6__namespace.dirname(keyPath);
1717
+ if (!fs9__namespace.existsSync(keyDir)) {
1718
+ fs9__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
1724
1719
  }
1725
- fsSync__namespace.writeFileSync(keyPath, key.toString("base64"), {
1720
+ fs9__namespace.writeFileSync(keyPath, key.toString("base64"), {
1726
1721
  mode: 384,
1727
1722
  // 仅所有者可读写
1728
1723
  encoding: "utf-8"
@@ -1749,9 +1744,9 @@ var ConfigManager = class {
1749
1744
  }
1750
1745
  async load(projectPath) {
1751
1746
  this.projectPath = projectPath;
1752
- this.configPath = path5__namespace.join(projectPath, ".sf-cli", "config.json");
1747
+ this.configPath = path6__namespace.join(projectPath, ".sf-cli", "config.json");
1753
1748
  try {
1754
- const content = await fs5__namespace.readFile(this.configPath, "utf-8");
1749
+ const content = await fs6__namespace.readFile(this.configPath, "utf-8");
1755
1750
  const loaded = JSON.parse(content);
1756
1751
  if (loaded.apiKey && loaded.apiKeyEncrypted) {
1757
1752
  loaded.apiKey = this.decrypt(loaded.apiKey);
@@ -1770,8 +1765,8 @@ var ConfigManager = class {
1770
1765
  configToSave.apiKey = encrypted;
1771
1766
  configToSave.apiKeyEncrypted = true;
1772
1767
  }
1773
- await fs5__namespace.mkdir(path5__namespace.dirname(this.configPath), { recursive: true });
1774
- await fs5__namespace.writeFile(
1768
+ await fs6__namespace.mkdir(path6__namespace.dirname(this.configPath), { recursive: true });
1769
+ await fs6__namespace.writeFile(
1775
1770
  this.configPath,
1776
1771
  JSON.stringify(configToSave, null, 2),
1777
1772
  "utf-8"
@@ -2029,7 +2024,7 @@ var BaseAdapter = class {
2029
2024
  * 延迟工具函数
2030
2025
  */
2031
2026
  delay(ms) {
2032
- return new Promise((resolve2) => setTimeout(resolve2, ms));
2027
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
2033
2028
  }
2034
2029
  };
2035
2030
 
@@ -2650,7 +2645,7 @@ var ModelService = class {
2650
2645
  * 初始化服务
2651
2646
  */
2652
2647
  async initialize(statsDir) {
2653
- this.statsPath = path5__namespace.join(statsDir, "tokens");
2648
+ this.statsPath = path6__namespace.join(statsDir, "tokens");
2654
2649
  await this.loadStats();
2655
2650
  const model = this.configManager.get("model");
2656
2651
  const apiKey = this.configManager.get("apiKey");
@@ -2823,11 +2818,11 @@ var ModelService = class {
2823
2818
  async loadStats() {
2824
2819
  if (!this.statsPath) return;
2825
2820
  try {
2826
- const dailyPath = path5__namespace.join(this.statsPath, "daily.json");
2827
- const totalPath = path5__namespace.join(this.statsPath, "total.json");
2821
+ const dailyPath = path6__namespace.join(this.statsPath, "daily.json");
2822
+ const totalPath = path6__namespace.join(this.statsPath, "total.json");
2828
2823
  const [daily, total] = await Promise.all([
2829
- fs5__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
2830
- fs5__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
2824
+ fs6__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
2825
+ fs6__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
2831
2826
  ]);
2832
2827
  const dailyData = JSON.parse(daily);
2833
2828
  const totalData = JSON.parse(total);
@@ -2840,12 +2835,12 @@ var ModelService = class {
2840
2835
  async saveStats() {
2841
2836
  if (!this.statsPath) return;
2842
2837
  try {
2843
- await fs5__namespace.mkdir(this.statsPath, { recursive: true });
2844
- const dailyPath = path5__namespace.join(this.statsPath, "daily.json");
2845
- const totalPath = path5__namespace.join(this.statsPath, "total.json");
2838
+ await fs6__namespace.mkdir(this.statsPath, { recursive: true });
2839
+ const dailyPath = path6__namespace.join(this.statsPath, "daily.json");
2840
+ const totalPath = path6__namespace.join(this.statsPath, "total.json");
2846
2841
  await Promise.all([
2847
- fs5__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
2848
- fs5__namespace.writeFile(totalPath, JSON.stringify({
2842
+ fs6__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
2843
+ fs6__namespace.writeFile(totalPath, JSON.stringify({
2849
2844
  totalInput: this.stats.totalInput,
2850
2845
  totalOutput: this.stats.totalOutput
2851
2846
  }))
@@ -3086,8 +3081,26 @@ function createSpinner(message) {
3086
3081
  stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
3087
3082
  };
3088
3083
  }
3089
- var CURRENT_VERSION = "1.0.0";
3090
- var PACKAGE_NAME = "sf-cli";
3084
+ function getPackageInfo() {
3085
+ const possiblePaths = [
3086
+ path6__namespace.resolve(__dirname, "..", "..", "package.json"),
3087
+ path6__namespace.resolve(__dirname, "..", "..", "..", "package.json")
3088
+ ];
3089
+ for (const pkgPath of possiblePaths) {
3090
+ try {
3091
+ if (fs9__namespace.existsSync(pkgPath)) {
3092
+ const content = fs9__namespace.readFileSync(pkgPath, "utf-8");
3093
+ return JSON.parse(content);
3094
+ }
3095
+ } catch {
3096
+ continue;
3097
+ }
3098
+ }
3099
+ return { version: "1.0.0", name: "@nick848/sf-cli" };
3100
+ }
3101
+ var packageInfo = getPackageInfo();
3102
+ var CURRENT_VERSION = packageInfo.version;
3103
+ var PACKAGE_NAME = packageInfo.name;
3091
3104
  async function handleUpdate(args, ctx) {
3092
3105
  const options = {
3093
3106
  check: args.includes("--check") || args.includes("-c"),
@@ -3114,6 +3127,9 @@ async function checkForUpdates() {
3114
3127
  const latestVersion = await getLatestVersion();
3115
3128
  if (!latestVersion) {
3116
3129
  lines.push(chalk9__default.default.yellow("\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
3130
+ lines.push(chalk9__default.default.gray("\u53EF\u80FD\u539F\u56E0:"));
3131
+ lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
3132
+ lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
3117
3133
  return { output: lines.join("\n") };
3118
3134
  }
3119
3135
  lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
@@ -3132,43 +3148,70 @@ async function checkForUpdates() {
3132
3148
  async function performUpdate(targetVersion) {
3133
3149
  const lines = [];
3134
3150
  lines.push(chalk9__default.default.cyan("\u6B63\u5728\u66F4\u65B0 sf-cli..."));
3151
+ lines.push(chalk9__default.default.gray(` \u5305\u540D: ${PACKAGE_NAME}`));
3152
+ lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
3135
3153
  try {
3136
3154
  const latestVersion = await getLatestVersion();
3155
+ if (!latestVersion && !targetVersion) {
3156
+ lines.push(chalk9__default.default.yellow("\n\u26A0 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
3157
+ lines.push(chalk9__default.default.gray("\n\u53EF\u80FD\u539F\u56E0:"));
3158
+ lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
3159
+ lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
3160
+ lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
3161
+ lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
3162
+ return { output: lines.join("\n") };
3163
+ }
3137
3164
  if (latestVersion === CURRENT_VERSION && !targetVersion) {
3138
- lines.push(chalk9__default.default.green("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
3165
+ lines.push(chalk9__default.default.green("\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
3139
3166
  return { output: lines.join("\n") };
3140
3167
  }
3141
3168
  const packageSpec = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
3142
3169
  lines.push(chalk9__default.default.gray(` \u5B89\u88C5: ${packageSpec}`));
3143
- await new Promise((resolve2, reject) => {
3170
+ const installResult = await new Promise((resolve5) => {
3144
3171
  const proc = child_process.spawn("npm", ["install", "-g", packageSpec], {
3145
3172
  stdio: "pipe",
3146
3173
  shell: true
3147
3174
  });
3175
+ let output = "";
3176
+ proc.stdout?.on("data", (data) => {
3177
+ output += data.toString();
3178
+ });
3179
+ proc.stderr?.on("data", (data) => {
3180
+ output += data.toString();
3181
+ });
3148
3182
  proc.on("close", (code) => {
3149
- if (code === 0) {
3150
- resolve2();
3151
- } else {
3152
- reject(new Error(`npm install exited with code ${code}`));
3153
- }
3183
+ resolve5({
3184
+ success: code === 0,
3185
+ output
3186
+ });
3154
3187
  });
3155
3188
  proc.on("error", (err) => {
3156
- reject(err);
3189
+ resolve5({
3190
+ success: false,
3191
+ output: err.message
3192
+ });
3157
3193
  });
3158
3194
  });
3159
- lines.push(chalk9__default.default.green("\u2713 \u66F4\u65B0\u5B8C\u6210!"));
3195
+ if (!installResult.success) {
3196
+ lines.push(chalk9__default.default.red("\n\u2717 \u66F4\u65B0\u5931\u8D25"));
3197
+ lines.push(chalk9__default.default.gray(installResult.output));
3198
+ lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
3199
+ lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
3200
+ return { output: lines.join("\n") };
3201
+ }
3202
+ lines.push(chalk9__default.default.green("\n\u2713 \u66F4\u65B0\u5B8C\u6210!"));
3160
3203
  lines.push(chalk9__default.default.gray(` \u65B0\u7248\u672C: v${targetVersion || latestVersion}`));
3161
3204
  lines.push(chalk9__default.default.gray("\n\u8BF7\u91CD\u542F CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"));
3162
3205
  } catch (error) {
3163
3206
  lines.push(chalk9__default.default.red("\u66F4\u65B0\u5931\u8D25: " + error.message));
3164
3207
  lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
3165
- lines.push(chalk9__default.default.gray(" npm install -g sf-cli@latest"));
3208
+ lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
3166
3209
  }
3167
3210
  return { output: lines.join("\n") };
3168
3211
  }
3169
3212
  async function getLatestVersion() {
3170
3213
  try {
3171
- const result = await new Promise((resolve2, reject) => {
3214
+ const result = await new Promise((resolve5, reject) => {
3172
3215
  const proc = child_process.spawn("npm", ["view", PACKAGE_NAME, "version"], {
3173
3216
  stdio: "pipe",
3174
3217
  shell: true
@@ -3178,13 +3221,17 @@ async function getLatestVersion() {
3178
3221
  output += data.toString();
3179
3222
  });
3180
3223
  proc.on("close", (code) => {
3181
- if (code === 0) {
3182
- resolve2(output.trim());
3224
+ if (code === 0 && output.trim()) {
3225
+ resolve5(output.trim());
3183
3226
  } else {
3184
3227
  reject(new Error("Failed to get version"));
3185
3228
  }
3186
3229
  });
3187
3230
  proc.on("error", reject);
3231
+ setTimeout(() => {
3232
+ proc.kill();
3233
+ reject(new Error("Timeout"));
3234
+ }, 1e4);
3188
3235
  });
3189
3236
  return result || null;
3190
3237
  } catch {
@@ -3468,7 +3515,7 @@ var WorkflowEngine = class {
3468
3515
  */
3469
3516
  async initialize(projectPath) {
3470
3517
  this.projectPath = projectPath;
3471
- this.openspecPath = path5__namespace.join(projectPath, "openspec");
3518
+ this.openspecPath = path6__namespace.join(projectPath, "openspec");
3472
3519
  await this.ensureDirectories();
3473
3520
  await this.loadProjectContext();
3474
3521
  await this.restoreState();
@@ -3478,21 +3525,21 @@ var WorkflowEngine = class {
3478
3525
  * 加载项目上下文(AGENTS.md 和 config.yaml)
3479
3526
  */
3480
3527
  async loadProjectContext() {
3481
- const agentsMdPath = path5__namespace.join(this.projectPath, "AGENTS.md");
3528
+ const agentsMdPath = path6__namespace.join(this.projectPath, "AGENTS.md");
3482
3529
  try {
3483
- this.projectContext = await fs5__namespace.readFile(agentsMdPath, "utf-8");
3530
+ this.projectContext = await fs6__namespace.readFile(agentsMdPath, "utf-8");
3484
3531
  } catch {
3485
3532
  this.projectContext = "";
3486
3533
  }
3487
- const configPath = path5__namespace.join(this.openspecPath, "config.yaml");
3534
+ const configPath = path6__namespace.join(this.openspecPath, "config.yaml");
3488
3535
  try {
3489
- this.projectConfig = await fs5__namespace.readFile(configPath, "utf-8");
3536
+ this.projectConfig = await fs6__namespace.readFile(configPath, "utf-8");
3490
3537
  } catch {
3491
3538
  this.projectConfig = "";
3492
3539
  }
3493
- const devstandedPath = path5__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
3540
+ const devstandedPath = path6__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
3494
3541
  try {
3495
- this.devStandards = await fs5__namespace.readFile(devstandedPath, "utf-8");
3542
+ this.devStandards = await fs6__namespace.readFile(devstandedPath, "utf-8");
3496
3543
  } catch {
3497
3544
  this.devStandards = "";
3498
3545
  }
@@ -3778,12 +3825,12 @@ var WorkflowEngine = class {
3778
3825
  await this.createSpecDocument(summary);
3779
3826
  await this.updateChangeRecord("archived");
3780
3827
  await this.saveState();
3781
- const changesDir = path5__namespace.join(this.openspecPath, "changes");
3782
- const archiveDir = path5__namespace.join(changesDir, "archive");
3783
- const changeFile = path5__namespace.join(changesDir, `${changeId}.md`);
3784
- const archiveFile = path5__namespace.join(archiveDir, `${changeId}.md`);
3785
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
3786
- await fs5__namespace.rename(changeFile, archiveFile).catch(() => {
3828
+ const changesDir = path6__namespace.join(this.openspecPath, "changes");
3829
+ const archiveDir = path6__namespace.join(changesDir, "archive");
3830
+ const changeFile = path6__namespace.join(changesDir, `${changeId}.md`);
3831
+ const archiveFile = path6__namespace.join(archiveDir, `${changeId}.md`);
3832
+ await fs6__namespace.mkdir(archiveDir, { recursive: true });
3833
+ await fs6__namespace.rename(changeFile, archiveFile).catch(() => {
3787
3834
  });
3788
3835
  this.state = null;
3789
3836
  this.snapshots.clear();
@@ -3805,16 +3852,16 @@ var WorkflowEngine = class {
3805
3852
  }
3806
3853
  // ==================== 私有方法 ====================
3807
3854
  async ensureDirectories() {
3808
- const changesDir = path5__namespace.join(this.openspecPath, "changes");
3809
- const archiveDir = path5__namespace.join(changesDir, "archive");
3810
- const specDir = path5__namespace.join(this.openspecPath, "spec");
3811
- await fs5__namespace.mkdir(archiveDir, { recursive: true });
3812
- await fs5__namespace.mkdir(specDir, { recursive: true });
3855
+ const changesDir = path6__namespace.join(this.openspecPath, "changes");
3856
+ const archiveDir = path6__namespace.join(changesDir, "archive");
3857
+ const specDir = path6__namespace.join(this.openspecPath, "spec");
3858
+ await fs6__namespace.mkdir(archiveDir, { recursive: true });
3859
+ await fs6__namespace.mkdir(specDir, { recursive: true });
3813
3860
  }
3814
3861
  async restoreState() {
3815
- const statePath = path5__namespace.join(this.openspecPath, ".workflow-state.json");
3862
+ const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
3816
3863
  try {
3817
- const content = await fs5__namespace.readFile(statePath, "utf-8");
3864
+ const content = await fs6__namespace.readFile(statePath, "utf-8");
3818
3865
  this.state = JSON.parse(content, (key, value) => {
3819
3866
  if (key.endsWith("At") && typeof value === "string") {
3820
3867
  return new Date(value);
@@ -3825,20 +3872,20 @@ var WorkflowEngine = class {
3825
3872
  const err = e;
3826
3873
  if (err.code !== "ENOENT") {
3827
3874
  console.warn("\u8B66\u544A: \u5DE5\u4F5C\u6D41\u72B6\u6001\u6587\u4EF6\u5DF2\u635F\u574F\uFF0C\u5C06\u91CD\u65B0\u5F00\u59CB");
3828
- await fs5__namespace.unlink(statePath).catch(() => {
3875
+ await fs6__namespace.unlink(statePath).catch(() => {
3829
3876
  });
3830
3877
  }
3831
3878
  this.state = null;
3832
3879
  }
3833
3880
  }
3834
3881
  async saveState() {
3835
- const statePath = path5__namespace.join(this.openspecPath, ".workflow-state.json");
3836
- await fs5__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
3882
+ const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
3883
+ await fs6__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
3837
3884
  }
3838
3885
  async restoreSnapshots() {
3839
- const snapshotsPath = path5__namespace.join(this.openspecPath, ".workflow-snapshots.json");
3886
+ const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
3840
3887
  try {
3841
- const content = await fs5__namespace.readFile(snapshotsPath, "utf-8");
3888
+ const content = await fs6__namespace.readFile(snapshotsPath, "utf-8");
3842
3889
  const data = JSON.parse(content, (key, value) => {
3843
3890
  if (key === "timestamp" && typeof value === "string") {
3844
3891
  return new Date(value);
@@ -3853,9 +3900,9 @@ var WorkflowEngine = class {
3853
3900
  }
3854
3901
  }
3855
3902
  async saveSnapshots() {
3856
- const snapshotsPath = path5__namespace.join(this.openspecPath, ".workflow-snapshots.json");
3903
+ const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
3857
3904
  const data = Array.from(this.snapshots.values());
3858
- await fs5__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
3905
+ await fs6__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
3859
3906
  }
3860
3907
  async createSnapshot() {
3861
3908
  if (!this.state) return;
@@ -3875,16 +3922,16 @@ var WorkflowEngine = class {
3875
3922
  }
3876
3923
  async createChangeRecord() {
3877
3924
  if (!this.state) return;
3878
- const changePath = path5__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
3879
- await fs5__namespace.writeFile(changePath, this.formatChangeRecord());
3925
+ const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
3926
+ await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
3880
3927
  }
3881
3928
  async updateChangeRecord(status) {
3882
3929
  if (!this.state) return;
3883
3930
  if (status) {
3884
3931
  this.state.status = status;
3885
3932
  }
3886
- const changePath = path5__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
3887
- await fs5__namespace.writeFile(changePath, this.formatChangeRecord());
3933
+ const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
3934
+ await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
3888
3935
  }
3889
3936
  formatChangeRecord() {
3890
3937
  if (!this.state) return "";
@@ -3923,7 +3970,7 @@ ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
3923
3970
  }
3924
3971
  async createSpecDocument(summary) {
3925
3972
  if (!this.state) return;
3926
- const specPath = path5__namespace.join(this.openspecPath, "spec", `${this.state.id}.md`);
3973
+ const specPath = path6__namespace.join(this.openspecPath, "spec", `${this.state.id}.md`);
3927
3974
  const content = `# Spec: ${this.state.title}
3928
3975
 
3929
3976
  > \u53D8\u66F4ID: ${this.state.id}
@@ -3948,7 +3995,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
3948
3995
 
3949
3996
  ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
3950
3997
  `;
3951
- await fs5__namespace.writeFile(specPath, content);
3998
+ await fs6__namespace.writeFile(specPath, content);
3952
3999
  }
3953
4000
  };
3954
4001
  var ConfirmationRequiredError = class extends Error {
@@ -3993,7 +4040,7 @@ async function newFeature(options, workingDir, workflowEngine) {
3993
4040
  const cwd = workingDir || process.cwd();
3994
4041
  const { requirement, forceComplexity } = options;
3995
4042
  try {
3996
- const stats = await fs5__namespace.stat(cwd);
4043
+ const stats = await fs6__namespace.stat(cwd);
3997
4044
  if (!stats.isDirectory()) {
3998
4045
  return {
3999
4046
  output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
@@ -4064,20 +4111,20 @@ function parseArgs(args) {
4064
4111
  }
4065
4112
  async function readProjectContext(cwd) {
4066
4113
  const defaultContext = {
4067
- name: path5__namespace.basename(cwd),
4114
+ name: path6__namespace.basename(cwd),
4068
4115
  type: "unknown",
4069
4116
  framework: null,
4070
4117
  techStack: [],
4071
4118
  description: ""
4072
4119
  };
4073
- const agentsPath = path5__namespace.join(cwd, "AGENTS.md");
4120
+ const agentsPath = path6__namespace.join(cwd, "AGENTS.md");
4074
4121
  try {
4075
- const stats = await fs5__namespace.stat(agentsPath);
4122
+ const stats = await fs6__namespace.stat(agentsPath);
4076
4123
  if (stats.size > MAX_FILE_SIZE2) {
4077
4124
  console.warn(`\u8B66\u544A: AGENTS.md \u6587\u4EF6\u8FC7\u5927 (${stats.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
4078
4125
  return defaultContext;
4079
4126
  }
4080
- const content = await fs5__namespace.readFile(agentsPath, "utf-8");
4127
+ const content = await fs6__namespace.readFile(agentsPath, "utf-8");
4081
4128
  return parseAgentsMd(content, defaultContext);
4082
4129
  } catch (e) {
4083
4130
  const err = e;
@@ -4085,14 +4132,14 @@ async function readProjectContext(cwd) {
4085
4132
  console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 AGENTS.md - ${err.message}`);
4086
4133
  }
4087
4134
  }
4088
- const configPath = path5__namespace.join(cwd, "openspec", "config.yaml");
4135
+ const configPath = path6__namespace.join(cwd, "openspec", "config.yaml");
4089
4136
  try {
4090
- const stats = await fs5__namespace.stat(configPath);
4137
+ const stats = await fs6__namespace.stat(configPath);
4091
4138
  if (stats.size > MAX_FILE_SIZE2) {
4092
4139
  console.warn(`\u8B66\u544A: config.yaml \u6587\u4EF6\u8FC7\u5927\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
4093
4140
  return defaultContext;
4094
4141
  }
4095
- const content = await fs5__namespace.readFile(configPath, "utf-8");
4142
+ const content = await fs6__namespace.readFile(configPath, "utf-8");
4096
4143
  return parseConfigYaml(content, defaultContext);
4097
4144
  } catch (e) {
4098
4145
  const err = e;
@@ -4312,10 +4359,10 @@ var FRONTEND_DEV_AGENT = {
4312
4359
  var CODE_REVIEWER_AGENT = {
4313
4360
  id: "code-reviewer",
4314
4361
  name: "\u4EE3\u7801\u5BA1\u6838",
4315
- description: "\u5BA1\u6838\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u89C4\u8303\u6027\uFF0C\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE",
4362
+ description: "\u5BA1\u6838\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u89C4\u8303\u6027\uFF0C\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE",
4316
4363
  icon: "\u{1F50D}",
4317
- version: "1.0.0",
4318
- role: "\u4F60\u662F\u4E00\u540D\u8D44\u6DF1\u4EE3\u7801\u5BA1\u6838\u4E13\u5BB6\uFF0C\u4E13\u6CE8\u4E8E\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u6700\u4F73\u5B9E\u8DF5\u3002\u4F60\u8D1F\u8D23\u5BA1\u67E5\u4EE3\u7801\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE\u3002",
4364
+ version: "1.1.0",
4365
+ role: "\u4F60\u662F\u4E00\u540D\u8D44\u6DF1\u4EE3\u7801\u5BA1\u6838\u4E13\u5BB6\uFF0C\u4E13\u6CE8\u4E8E\u4EE3\u7801\u8D28\u91CF\u3001\u5B89\u5168\u6027\u548C\u6700\u4F73\u5B9E\u8DF5\u3002\u4F60\u8D1F\u8D23\u5BA1\u67E5\u4EE3\u7801\u3001\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE\u3002",
4319
4366
  capabilities: [
4320
4367
  {
4321
4368
  id: "quality-review",
@@ -4336,13 +4383,24 @@ var CODE_REVIEWER_AGENT = {
4336
4383
  id: "performance-review",
4337
4384
  name: "\u6027\u80FD\u5BA1\u67E5",
4338
4385
  description: "\u68C0\u67E5\u6027\u80FD\u95EE\u9898\u548C\u4F18\u5316\u5EFA\u8BAE"
4386
+ },
4387
+ {
4388
+ id: "regression-test",
4389
+ name: "\u56DE\u5F52\u6D4B\u8BD5",
4390
+ description: "\u6267\u884C\u6D4B\u8BD5\u5957\u4EF6\uFF0C\u786E\u4FDD\u4FEE\u6539\u4E0D\u7834\u574F\u5DF2\u6709\u529F\u80FD"
4391
+ },
4392
+ {
4393
+ id: "coverage-analysis",
4394
+ name: "\u8986\u76D6\u7387\u5206\u6790",
4395
+ description: "\u5206\u6790\u6D4B\u8BD5\u8986\u76D6\u7387\u5E76\u63D0\u4F9B\u6539\u8FDB\u5EFA\u8BAE"
4339
4396
  }
4340
4397
  ],
4341
4398
  tools: [
4342
4399
  { name: "read_file", description: "\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9", permission: "full" },
4343
4400
  { name: "glob", description: "\u641C\u7D22\u6587\u4EF6", permission: "full" },
4344
4401
  { name: "search_file_content", description: "\u641C\u7D22\u6587\u4EF6\u5185\u5BB9", permission: "full" },
4345
- { name: "list_directory", description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9", permission: "full" }
4402
+ { name: "list_directory", description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9", permission: "full" },
4403
+ { name: "run_shell_command", description: "\u6267\u884C\u6D4B\u8BD5\u547D\u4EE4", permission: "confirm" }
4346
4404
  ],
4347
4405
  triggers: [
4348
4406
  { type: "workflow", condition: { workflowStep: "apply" }, priority: 10 },
@@ -4353,6 +4411,7 @@ var CODE_REVIEWER_AGENT = {
4353
4411
  protectedPaths: ["node_modules", ".git"]
4354
4412
  },
4355
4413
  behavior: {
4414
+ requireConfirmation: ["run_shell_command"],
4356
4415
  autoCommit: false
4357
4416
  }
4358
4417
  },
@@ -4361,6 +4420,7 @@ var CODE_REVIEWER_AGENT = {
4361
4420
  ## \u4F60\u7684\u804C\u8D23
4362
4421
  - \u5BA1\u67E5\u4EE3\u7801\u8D28\u91CF\u548C\u53EF\u7EF4\u62A4\u6027
4363
4422
  - \u68C0\u67E5\u5B89\u5168\u6F0F\u6D1E\u548C\u98CE\u9669
4423
+ - \u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u786E\u4FDD\u4FEE\u6539\u4E0D\u7834\u574F\u5DF2\u6709\u529F\u80FD
4364
4424
  - \u63D0\u4F9B\u5177\u4F53\u7684\u6539\u8FDB\u5EFA\u8BAE
4365
4425
  - \u786E\u4FDD\u9075\u5FAA\u6700\u4F73\u5B9E\u8DF5
4366
4426
 
@@ -4369,8 +4429,20 @@ var CODE_REVIEWER_AGENT = {
4369
4429
  2. **\u5B89\u5168\u6027**: XSS\u3001\u6CE8\u5165\u3001\u654F\u611F\u6570\u636E\u5904\u7406
4370
4430
  3. **\u6027\u80FD**: \u7B97\u6CD5\u6548\u7387\u3001\u5185\u5B58\u4F7F\u7528\u3001\u6E32\u67D3\u4F18\u5316
4371
4431
  4. **\u89C4\u8303\u6027**: \u547D\u540D\u3001\u683C\u5F0F\u3001\u6CE8\u91CA
4432
+ 5. **\u6D4B\u8BD5\u8986\u76D6**: \u56DE\u5F52\u6D4B\u8BD5\u7ED3\u679C\u3001\u8986\u76D6\u7387\u5206\u6790
4433
+
4434
+ ## \u56DE\u5F52\u6D4B\u8BD5\u6D41\u7A0B
4435
+ 1. \u6267\u884C \`npm test -- --run\` \u8FD0\u884C\u6D4B\u8BD5\u5957\u4EF6
4436
+ 2. \u5206\u6790\u6D4B\u8BD5\u7ED3\u679C\uFF0C\u8BC6\u522B\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B
4437
+ 3. \u5982\u679C\u6D4B\u8BD5\u5931\u8D25\uFF0C\u963B\u6B62\u5F52\u6863\u5E76\u63D0\u793A\u4FEE\u590D
4438
+ 4. \u63D0\u4F9B\u8986\u76D6\u7387\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE
4372
4439
 
4373
4440
  ## \u8F93\u51FA\u683C\u5F0F
4441
+ ### \u56DE\u5F52\u6D4B\u8BD5\u7ED3\u679C
4442
+ - \u6D4B\u8BD5\u901A\u8FC7/\u5931\u8D25\u72B6\u6001
4443
+ - \u901A\u8FC7/\u5931\u8D25\u6570\u91CF
4444
+ - \u8986\u76D6\u7387\u767E\u5206\u6BD4
4445
+
4374
4446
  ### \u5BA1\u67E5\u7ED3\u679C
4375
4447
  - \u901A\u8FC7/\u9700\u4FEE\u6539/\u4E0D\u901A\u8FC7
4376
4448
 
@@ -4396,7 +4468,7 @@ var CODE_REVIEWER_AGENT = {
4396
4468
  ## \u4E0A\u4E0B\u6587
4397
4469
  {{context}}
4398
4470
 
4399
- \u8BF7\u5BF9\u4EE5\u4E0A\u6587\u4EF6\u8FDB\u884C\u5168\u9762\u5BA1\u67E5\uFF0C\u63D0\u4F9B\u8BE6\u7EC6\u7684\u5BA1\u67E5\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE\u3002`,
4471
+ \u8BF7\u5BF9\u4EE5\u4E0A\u6587\u4EF6\u8FDB\u884C\u5168\u9762\u5BA1\u67E5\uFF0C\u6267\u884C\u56DE\u5F52\u6D4B\u8BD5\uFF0C\u5E76\u63D0\u4F9B\u8BE6\u7EC6\u7684\u5BA1\u67E5\u62A5\u544A\u548C\u6539\u8FDB\u5EFA\u8BAE\u3002`,
4400
4472
  outputFormat: {
4401
4473
  type: "markdown"
4402
4474
  }
@@ -4652,15 +4724,15 @@ async function loadProjectContext(workingDirectory) {
4652
4724
  devStandards: ""
4653
4725
  };
4654
4726
  try {
4655
- context.agentsMd = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
4727
+ context.agentsMd = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
4656
4728
  } catch {
4657
4729
  }
4658
4730
  try {
4659
- context.configYaml = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
4731
+ context.configYaml = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
4660
4732
  } catch {
4661
4733
  }
4662
4734
  try {
4663
- context.devStandards = await fs5__namespace.readFile(path5__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
4735
+ context.devStandards = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
4664
4736
  } catch {
4665
4737
  }
4666
4738
  return context;
@@ -4822,6 +4894,78 @@ ${content}`;
4822
4894
 
4823
4895
  // src/commands/opsx.ts
4824
4896
  var autoScheduleEnabled = true;
4897
+ var DEFAULT_REGRESSION_CONFIG = {
4898
+ enabled: true,
4899
+ command: "npm test -- --run",
4900
+ timeout: 12e4,
4901
+ // 2分钟
4902
+ coverageThreshold: 80
4903
+ };
4904
+ async function runRegressionTest(workingDirectory, config = DEFAULT_REGRESSION_CONFIG) {
4905
+ const startTime = Date.now();
4906
+ const result = {
4907
+ success: false,
4908
+ passed: 0,
4909
+ failed: 0,
4910
+ total: 0,
4911
+ duration: 0,
4912
+ output: "",
4913
+ errors: []
4914
+ };
4915
+ return new Promise((resolve5) => {
4916
+ const proc = child_process.spawn(config.command, [], {
4917
+ cwd: workingDirectory,
4918
+ shell: true,
4919
+ stdio: "pipe"
4920
+ });
4921
+ let stdout = "";
4922
+ let stderr = "";
4923
+ proc.stdout?.on("data", (data) => {
4924
+ stdout += data.toString();
4925
+ });
4926
+ proc.stderr?.on("data", (data) => {
4927
+ stderr += data.toString();
4928
+ });
4929
+ const timeout = setTimeout(() => {
4930
+ proc.kill();
4931
+ result.errors.push("\u6D4B\u8BD5\u8D85\u65F6");
4932
+ result.output = stdout + stderr;
4933
+ result.duration = Date.now() - startTime;
4934
+ resolve5(result);
4935
+ }, config.timeout);
4936
+ proc.on("close", (code) => {
4937
+ clearTimeout(timeout);
4938
+ result.output = stdout + stderr;
4939
+ result.duration = Date.now() - startTime;
4940
+ const passMatch = stdout.match(/(\d+)\s+(?:passed|tests?\s+passed)/i);
4941
+ const failMatch = stdout.match(/(\d+)\s+(?:failed|tests?\s+failed)/i);
4942
+ const totalMatch = stdout.match(/Tests?:\s*(\d+)/i);
4943
+ if (passMatch) {
4944
+ result.passed = parseInt(passMatch[1], 10);
4945
+ }
4946
+ if (failMatch) {
4947
+ result.failed = parseInt(failMatch[1], 10);
4948
+ }
4949
+ if (totalMatch) {
4950
+ result.total = parseInt(totalMatch[1], 10);
4951
+ } else {
4952
+ result.total = result.passed + result.failed;
4953
+ }
4954
+ const coverageMatch = stdout.match(/All files[^\d]*(\d+(?:\.\d+)?)/);
4955
+ if (coverageMatch) {
4956
+ result.coverage = parseFloat(coverageMatch[1]);
4957
+ }
4958
+ result.success = code === 0 && result.failed === 0;
4959
+ resolve5(result);
4960
+ });
4961
+ proc.on("error", (err) => {
4962
+ clearTimeout(timeout);
4963
+ result.errors.push(err.message);
4964
+ result.duration = Date.now() - startTime;
4965
+ resolve5(result);
4966
+ });
4967
+ });
4968
+ }
4825
4969
  async function handleOpsx(command, args, ctx) {
4826
4970
  const step = command.replace("opsx:", "");
4827
4971
  const workflow = new WorkflowEngine();
@@ -4836,7 +4980,7 @@ async function handleOpsx(command, args, ctx) {
4836
4980
  case "apply":
4837
4981
  return handleApply(workflow);
4838
4982
  case "archive":
4839
- return handleArchive(workflow, args);
4983
+ return handleArchive(workflow, args, ctx);
4840
4984
  case "propose":
4841
4985
  return handlePropose(workflow, args);
4842
4986
  case "status":
@@ -4851,12 +4995,50 @@ async function handleOpsx(command, args, ctx) {
4851
4995
  return handleNext(workflow);
4852
4996
  case "auto":
4853
4997
  return handleAutoSchedule(args);
4998
+ case "test":
4999
+ return handleRegressionTest(ctx);
4854
5000
  default:
4855
5001
  return {
4856
5002
  output: chalk9__default.default.red(`\u672A\u77E5\u7684OpenSpec\u547D\u4EE4: /${command}`)
4857
5003
  };
4858
5004
  }
4859
5005
  }
5006
+ async function handleRegressionTest(ctx) {
5007
+ const lines = [];
5008
+ lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u56DE\u5F52\u6D4B\u8BD5..."));
5009
+ lines.push(chalk9__default.default.gray(` \u5DE5\u4F5C\u76EE\u5F55: ${ctx.options.workingDirectory}`));
5010
+ lines.push("");
5011
+ const result = await runRegressionTest(ctx.options.workingDirectory);
5012
+ lines.push(chalk9__default.default.gray("\u2500".repeat(50)));
5013
+ if (result.success) {
5014
+ lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
5015
+ } else {
5016
+ lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
5017
+ }
5018
+ lines.push("");
5019
+ lines.push(chalk9__default.default.cyan("\u6D4B\u8BD5\u7ED3\u679C:"));
5020
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${result.passed}`));
5021
+ lines.push(chalk9__default.default.gray(` \u5931\u8D25: ${result.failed}`));
5022
+ lines.push(chalk9__default.default.gray(` \u603B\u8BA1: ${result.total}`));
5023
+ lines.push(chalk9__default.default.gray(` \u8017\u65F6: ${(result.duration / 1e3).toFixed(2)}s`));
5024
+ if (result.coverage !== void 0) {
5025
+ const coverageColor = result.coverage >= 80 ? chalk9__default.default.green : result.coverage >= 60 ? chalk9__default.default.yellow : chalk9__default.default.red;
5026
+ lines.push(coverageColor(` \u8986\u76D6\u7387: ${result.coverage}%`));
5027
+ }
5028
+ if (result.errors.length > 0) {
5029
+ lines.push("");
5030
+ lines.push(chalk9__default.default.red("\u9519\u8BEF\u4FE1\u606F:"));
5031
+ for (const error of result.errors) {
5032
+ lines.push(chalk9__default.default.gray(` - ${error}`));
5033
+ }
5034
+ }
5035
+ if (result.failed > 0) {
5036
+ lines.push("");
5037
+ lines.push(chalk9__default.default.yellow("\u26A0 \u5B58\u5728\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\uFF0C\u8BF7\u68C0\u67E5\u5E76\u4FEE\u590D"));
5038
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
5039
+ }
5040
+ return { output: lines.join("\n") };
5041
+ }
4860
5042
  function handleAutoSchedule(args) {
4861
5043
  const action = args[0]?.toLowerCase();
4862
5044
  if (!action) {
@@ -4986,13 +5168,70 @@ async function handleArchive(workflow, args, ctx) {
4986
5168
  ${generateConfirmationPrompt(confirmation.point)}`) + chalk9__default.default.cyan("\n\n\u4F7F\u7528 /opsx:confirm code-review \u786E\u8BA4\u540E\u5F52\u6863")
4987
5169
  };
4988
5170
  }
5171
+ const lines = [];
5172
+ lines.push(chalk9__default.default.cyan("\u{1F50D} \u6267\u884C\u5F52\u6863\u524D\u56DE\u5F52\u6D4B\u8BD5..."));
5173
+ lines.push("");
5174
+ const testResult = await runRegressionTest(ctx.options.workingDirectory);
5175
+ if (!testResult.success) {
5176
+ lines.push(chalk9__default.default.red("\u2717 \u56DE\u5F52\u6D4B\u8BD5\u5931\u8D25"));
5177
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u5931\u8D25: ${testResult.failed} | \u603B\u8BA1: ${testResult.total}`));
5178
+ lines.push("");
5179
+ lines.push(chalk9__default.default.yellow("\u26A0 \u5F52\u6863\u88AB\u963B\u6B62"));
5180
+ lines.push(chalk9__default.default.gray("\n\u8BF7\u4FEE\u590D\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\u540E\u91CD\u8BD5"));
5181
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:rollback \u53EF\u56DE\u6EDA\u5230\u4E4B\u524D\u7684\u9636\u6BB5"));
5182
+ lines.push(chalk9__default.default.gray("\u4F7F\u7528 /opsx:test \u53EF\u5355\u72EC\u8FD0\u884C\u56DE\u5F52\u6D4B\u8BD5"));
5183
+ return { output: lines.join("\n") };
5184
+ }
5185
+ lines.push(chalk9__default.default.green("\u2713 \u56DE\u5F52\u6D4B\u8BD5\u901A\u8FC7"));
5186
+ lines.push(chalk9__default.default.gray(` \u901A\u8FC7: ${testResult.passed} | \u8017\u65F6: ${(testResult.duration / 1e3).toFixed(2)}s`));
5187
+ lines.push("");
4989
5188
  const changeId = state.id;
4990
5189
  const summary = args.join(" ") || "\u5B8C\u6210\u53D8\u66F4";
4991
5190
  await workflow.archive(summary);
4992
- return {
4993
- output: chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5F52\u6863") + chalk9__default.default.gray(`
4994
- \u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55")
4995
- };
5191
+ await updateChangelog(ctx.options.workingDirectory, summary, changeId);
5192
+ lines.push(chalk9__default.default.green("\u2713 \u5DE5\u4F5C\u6D41\u5DF2\u5F52\u6863") + chalk9__default.default.gray(`
5193
+ \u53D8\u66F4ID: ${changeId}`) + chalk9__default.default.cyan("\n\n\u5F52\u6863\u6587\u6863\u5DF2\u751F\u6210\u5230 openspec/spec/ \u76EE\u5F55") + chalk9__default.default.gray("\nCHANGELOG.md \u5DF2\u66F4\u65B0"));
5194
+ return { output: lines.join("\n") };
5195
+ }
5196
+ async function updateChangelog(workingDirectory, summary, changeId) {
5197
+ try {
5198
+ const changelogPath = path6__namespace.join(workingDirectory, "CHANGELOG.md");
5199
+ const pkgPath = path6__namespace.join(workingDirectory, "package.json");
5200
+ let version = "1.0.0";
5201
+ try {
5202
+ const pkgContent = fs9__namespace.readFileSync(pkgPath, "utf-8");
5203
+ const pkg = JSON.parse(pkgContent);
5204
+ version = pkg.version || "1.0.0";
5205
+ } catch {
5206
+ }
5207
+ const today = /* @__PURE__ */ new Date();
5208
+ const dateStr = today.toISOString().split("T")[0];
5209
+ const entry = `
5210
+ ## v${version} (${dateStr})
5211
+
5212
+ **\u53D8\u66F4\u5185\u5BB9**
5213
+
5214
+ - ${summary} (${changeId})
5215
+ `;
5216
+ if (fs9__namespace.existsSync(changelogPath)) {
5217
+ const content = fs9__namespace.readFileSync(changelogPath, "utf-8");
5218
+ const versionPattern = /^## v\d+\.\d+\.\d+/m;
5219
+ const match = content.match(versionPattern);
5220
+ if (match && match.index !== void 0) {
5221
+ const newContent = content.slice(0, match.index) + entry + content.slice(match.index);
5222
+ fs9__namespace.writeFileSync(changelogPath, newContent, "utf-8");
5223
+ } else {
5224
+ fs9__namespace.appendFileSync(changelogPath, entry, "utf-8");
5225
+ }
5226
+ } else {
5227
+ const header = `# Changelog
5228
+
5229
+ All notable changes to this project will be documented in this file.
5230
+ `;
5231
+ fs9__namespace.writeFileSync(changelogPath, header + entry, "utf-8");
5232
+ }
5233
+ } catch (error) {
5234
+ }
4996
5235
  }
4997
5236
  async function handlePropose(workflow, args, ctx) {
4998
5237
  const state = workflow.getState();
@@ -5181,9 +5420,27 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
5181
5420
  throw e;
5182
5421
  }
5183
5422
  }
5184
- var require2 = module$1.createRequire(importMetaUrl);
5185
- var packageJson = require2("../../package.json");
5186
- var VERSION2 = packageJson.version;
5423
+
5424
+ // src/commands/runner.ts
5425
+ function getVersion() {
5426
+ const possiblePaths = [
5427
+ path6__namespace.resolve(__dirname, "..", "..", "package.json"),
5428
+ path6__namespace.resolve(__dirname, "..", "..", "..", "package.json")
5429
+ ];
5430
+ for (const pkgPath of possiblePaths) {
5431
+ try {
5432
+ if (fs9__namespace.existsSync(pkgPath)) {
5433
+ const content = fs9__namespace.readFileSync(pkgPath, "utf-8");
5434
+ const pkg = JSON.parse(content);
5435
+ return pkg.version;
5436
+ }
5437
+ } catch {
5438
+ continue;
5439
+ }
5440
+ }
5441
+ return "1.0.0";
5442
+ }
5443
+ var VERSION2 = getVersion();
5187
5444
  async function runSlashCommand(command, args, ctx) {
5188
5445
  const normalizedCommand = normalizeCommand(command);
5189
5446
  switch (normalizedCommand) {
@@ -5230,11 +5487,11 @@ function normalizeCommand(command) {
5230
5487
  }
5231
5488
  async function handleFileReference(filePath, ctx) {
5232
5489
  const cwd = ctx.options.workingDirectory;
5233
- const absolutePath = path5__namespace.isAbsolute(filePath) ? filePath : path5__namespace.join(cwd, filePath);
5490
+ const absolutePath = path6__namespace.isAbsolute(filePath) ? filePath : path6__namespace.join(cwd, filePath);
5234
5491
  try {
5235
- const stats = await fs5__namespace.stat(absolutePath);
5492
+ const stats = await fs6__namespace.stat(absolutePath);
5236
5493
  if (stats.isDirectory()) {
5237
- const files = await fs5__namespace.readdir(absolutePath);
5494
+ const files = await fs6__namespace.readdir(absolutePath);
5238
5495
  return {
5239
5496
  output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
5240
5497
  ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
@@ -5242,7 +5499,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
5242
5499
  contextUsed: 0
5243
5500
  };
5244
5501
  }
5245
- const content = await fs5__namespace.readFile(absolutePath, "utf-8");
5502
+ const content = await fs6__namespace.readFile(absolutePath, "utf-8");
5246
5503
  const lines = content.split("\n");
5247
5504
  ctx.contextManager.addMessage({
5248
5505
  role: "user",
@@ -5278,7 +5535,7 @@ async function executeShell(command, ctx) {
5278
5535
  \u547D\u4EE4 "${command}" \u53EF\u80FD\u4F1A\u5220\u9664\u91CD\u8981\u6587\u4EF6`) + chalk9__default.default.gray("\n\u4F7F\u7528 yolo \u6A21\u5F0F\u5F3A\u5236\u6267\u884C")
5279
5536
  };
5280
5537
  }
5281
- return new Promise((resolve2) => {
5538
+ return new Promise((resolve5) => {
5282
5539
  const shell = child_process.spawn(command, [], {
5283
5540
  shell: true,
5284
5541
  cwd: ctx.options.workingDirectory
@@ -5303,11 +5560,11 @@ async function executeShell(command, ctx) {
5303
5560
  output += chalk9__default.default.red(`
5304
5561
  \u9000\u51FA\u7801: ${code}`);
5305
5562
  }
5306
- resolve2({ output: output || chalk9__default.default.gray("(\u65E0\u8F93\u51FA)") });
5563
+ resolve5({ output: output || chalk9__default.default.gray("(\u65E0\u8F93\u51FA)") });
5307
5564
  });
5308
5565
  setTimeout(() => {
5309
5566
  shell.kill();
5310
- resolve2({
5567
+ resolve5({
5311
5568
  output: chalk9__default.default.yellow("\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0C\u5DF2\u7EC8\u6B62")
5312
5569
  });
5313
5570
  }, 6e4);
@@ -5533,7 +5790,7 @@ var ContextManager = class {
5533
5790
  }
5534
5791
  async initialize(projectPath) {
5535
5792
  this.projectPath = projectPath;
5536
- this.persistPath = path5__namespace.join(projectPath, ".sf-cli", "cache", "context", "context.json");
5793
+ this.persistPath = path6__namespace.join(projectPath, ".sf-cli", "cache", "context", "context.json");
5537
5794
  await this.loadPersistedContext();
5538
5795
  }
5539
5796
  /**
@@ -5774,15 +6031,15 @@ ${summary}`,
5774
6031
  */
5775
6032
  async persist() {
5776
6033
  if (!this.persistPath) return;
5777
- const dir = path5__namespace.dirname(this.persistPath);
5778
- await fs5__namespace.mkdir(dir, { recursive: true });
6034
+ const dir = path6__namespace.dirname(this.persistPath);
6035
+ await fs6__namespace.mkdir(dir, { recursive: true });
5779
6036
  const data = {
5780
6037
  messages: this.state.messages,
5781
6038
  totalTokens: this.state.totalTokens,
5782
6039
  limit: this.state.limit,
5783
6040
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
5784
6041
  };
5785
- await fs5__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
6042
+ await fs6__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
5786
6043
  }
5787
6044
  /**
5788
6045
  * 加载持久化的上下文
@@ -5790,7 +6047,7 @@ ${summary}`,
5790
6047
  async loadPersistedContext() {
5791
6048
  if (!this.persistPath) return;
5792
6049
  try {
5793
- const content = await fs5__namespace.readFile(this.persistPath, "utf-8");
6050
+ const content = await fs6__namespace.readFile(this.persistPath, "utf-8");
5794
6051
  const data = JSON.parse(content);
5795
6052
  this.state.messages = data.messages || [];
5796
6053
  this.state.totalTokens = data.totalTokens || 0;
@@ -5960,17 +6217,17 @@ var Completer = class {
5960
6217
  prefix = filePath;
5961
6218
  } else {
5962
6219
  const dir = filePath.slice(0, lastSlash);
5963
- dirPath = path5__namespace.resolve(this.workingDirectory, dir);
6220
+ dirPath = path6__namespace.resolve(this.workingDirectory, dir);
5964
6221
  prefix = filePath.slice(lastSlash + 1);
5965
6222
  }
5966
6223
  try {
5967
- const entries = await fs5__namespace.readdir(dirPath, { withFileTypes: true });
6224
+ const entries = await fs6__namespace.readdir(dirPath, { withFileTypes: true });
5968
6225
  const matches = [];
5969
6226
  for (const entry of entries) {
5970
6227
  if (entry.name.startsWith(prefix)) {
5971
6228
  const isDir = entry.isDirectory();
5972
6229
  matches.push({
5973
- text: "@" + path5__namespace.relative(this.workingDirectory, path5__namespace.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
6230
+ text: "@" + path6__namespace.relative(this.workingDirectory, path6__namespace.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
5974
6231
  displayText: entry.name + (isDir ? "/" : ""),
5975
6232
  description: isDir ? "\u76EE\u5F55" : "\u6587\u4EF6",
5976
6233
  type: isDir ? "directory" : "file"
@@ -6042,10 +6299,10 @@ var Completer = class {
6042
6299
 
6043
6300
  // src/cli/repl.ts
6044
6301
  async function startInteractiveMode(options) {
6045
- const historyFile = path5__namespace.join(options.workingDirectory, ".sf-cli", "history.json");
6302
+ const historyFile = path6__namespace.join(options.workingDirectory, ".sf-cli", "history.json");
6046
6303
  let history = [];
6047
6304
  try {
6048
- const historyData = await fs5__namespace.readFile(historyFile, "utf-8");
6305
+ const historyData = await fs6__namespace.readFile(historyFile, "utf-8");
6049
6306
  history = JSON.parse(historyData);
6050
6307
  } catch {
6051
6308
  }
@@ -6079,11 +6336,11 @@ async function startInteractiveMode(options) {
6079
6336
  const workflowEngine = new WorkflowEngine();
6080
6337
  const normsManager = new NormsManager({
6081
6338
  projectPath: options.workingDirectory,
6082
- normsDir: path5__namespace.join(options.workingDirectory, ".sf-cli", "norms")
6339
+ normsDir: path6__namespace.join(options.workingDirectory, ".sf-cli", "norms")
6083
6340
  });
6084
6341
  await configManager.load(options.workingDirectory);
6085
6342
  await contextManager.initialize(options.workingDirectory);
6086
- const statsDir = path5__namespace.join(options.workingDirectory, ".sf-cli");
6343
+ const statsDir = path6__namespace.join(options.workingDirectory, ".sf-cli");
6087
6344
  await modelService.initialize(statsDir);
6088
6345
  await workflowEngine.initialize(options.workingDirectory);
6089
6346
  await normsManager.initialize();
@@ -6114,8 +6371,8 @@ async function startInteractiveMode(options) {
6114
6371
  }
6115
6372
  const saveHistory = async () => {
6116
6373
  try {
6117
- await fs5__namespace.mkdir(path5__namespace.dirname(historyFile), { recursive: true });
6118
- await fs5__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
6374
+ await fs6__namespace.mkdir(path6__namespace.dirname(historyFile), { recursive: true });
6375
+ await fs6__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
6119
6376
  } catch {
6120
6377
  }
6121
6378
  };
@@ -6187,9 +6444,29 @@ async function startInteractiveMode(options) {
6187
6444
  rl.prompt();
6188
6445
  }
6189
6446
  }
6190
- var require3 = module$1.createRequire(importMetaUrl);
6191
- var packageJson2 = require3("../../package.json");
6192
- var VERSION3 = packageJson2.version;
6447
+
6448
+ // src/cli/index.ts
6449
+ function getPackageJson() {
6450
+ const possiblePaths = [
6451
+ // 开发环境: dist/cli/index.js -> ../../package.json (项目根目录)
6452
+ path6__namespace.resolve(__dirname, "..", "..", "package.json"),
6453
+ // 生产环境: node_modules/@nick848/sf-cli/dist/cli/index.js -> ../../package.json
6454
+ path6__namespace.resolve(__dirname, "..", "..", "package.json")
6455
+ ];
6456
+ for (const pkgPath of possiblePaths) {
6457
+ try {
6458
+ if (fs9__namespace.existsSync(pkgPath)) {
6459
+ const content = fs9__namespace.readFileSync(pkgPath, "utf-8");
6460
+ return JSON.parse(content);
6461
+ }
6462
+ } catch {
6463
+ continue;
6464
+ }
6465
+ }
6466
+ return { version: "1.0.0", name: "@nick848/sf-cli" };
6467
+ }
6468
+ var packageJson = getPackageJson();
6469
+ var VERSION3 = packageJson.version;
6193
6470
  var NAME = "sf-cli";
6194
6471
  commander.program.name(NAME).description("\u4E13\u4E3A\u524D\u7AEF\u5F00\u53D1\u8BBE\u8BA1\u7684AI\u9A71\u52A8CLI\u5DE5\u5177").version(VERSION3, "-v, --version", "\u663E\u793A\u7248\u672C\u53F7");
6195
6472
  commander.program.argument("[directory]", "\u5DE5\u4F5C\u76EE\u5F55", process.cwd()).option("-m, --model <model>", "\u6307\u5B9AAI\u6A21\u578B").option("-y, --yolo", "\u81EA\u52A8\u786E\u8BA4\u6240\u6709\u64CD\u4F5C").action(async (directory, options) => {