@nick848/sf-cli 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,8 @@
1
+ import * as path5 from 'path';
2
+ import path5__default from 'path';
3
+ import { fileURLToPath } from 'url';
1
4
  import * as fs4 from 'fs/promises';
2
5
  import * as fsSync from 'fs';
3
- import * as path4 from 'path';
4
6
  import * as crypto from 'crypto';
5
7
  import * as os from 'os';
6
8
  import { encoding_for_model } from 'tiktoken';
@@ -10,9 +12,11 @@ import chalk9 from 'chalk';
10
12
  import { v4 } from 'uuid';
11
13
  import { prompt } from 'enquirer';
12
14
  import { spawn } from 'child_process';
13
- import { createRequire } from 'module';
14
15
 
15
- // src/services/config.ts
16
+ // node_modules/tsup/assets/esm_shims.js
17
+ var getFilename = () => fileURLToPath(import.meta.url);
18
+ var getDirname = () => path5__default.dirname(getFilename());
19
+ var __dirname$1 = /* @__PURE__ */ getDirname();
16
20
  var DEFAULT_CONFIG = {
17
21
  model: "GLM-5",
18
22
  apiKey: "",
@@ -25,7 +29,7 @@ var IV_LENGTH = 16;
25
29
  var KEY_DIR = ".sf-cli";
26
30
  var KEY_FILE = ".key";
27
31
  function getOrCreateEncryptionKey() {
28
- const keyPath = path4.join(os.homedir(), KEY_DIR, KEY_FILE);
32
+ const keyPath = path5.join(os.homedir(), KEY_DIR, KEY_FILE);
29
33
  try {
30
34
  if (fsSync.existsSync(keyPath)) {
31
35
  const keyBase64 = fsSync.readFileSync(keyPath, "utf-8").trim();
@@ -35,7 +39,7 @@ function getOrCreateEncryptionKey() {
35
39
  }
36
40
  const key = crypto.randomBytes(32);
37
41
  try {
38
- const keyDir = path4.dirname(keyPath);
42
+ const keyDir = path5.dirname(keyPath);
39
43
  if (!fsSync.existsSync(keyDir)) {
40
44
  fsSync.mkdirSync(keyDir, { recursive: true, mode: 448 });
41
45
  }
@@ -66,7 +70,7 @@ var ConfigManager = class {
66
70
  }
67
71
  async load(projectPath) {
68
72
  this.projectPath = projectPath;
69
- this.configPath = path4.join(projectPath, ".sf-cli", "config.json");
73
+ this.configPath = path5.join(projectPath, ".sf-cli", "config.json");
70
74
  try {
71
75
  const content = await fs4.readFile(this.configPath, "utf-8");
72
76
  const loaded = JSON.parse(content);
@@ -87,7 +91,7 @@ var ConfigManager = class {
87
91
  configToSave.apiKey = encrypted;
88
92
  configToSave.apiKeyEncrypted = true;
89
93
  }
90
- await fs4.mkdir(path4.dirname(this.configPath), { recursive: true });
94
+ await fs4.mkdir(path5.dirname(this.configPath), { recursive: true });
91
95
  await fs4.writeFile(
92
96
  this.configPath,
93
97
  JSON.stringify(configToSave, null, 2),
@@ -346,7 +350,7 @@ var BaseAdapter = class {
346
350
  * 延迟工具函数
347
351
  */
348
352
  delay(ms) {
349
- return new Promise((resolve2) => setTimeout(resolve2, ms));
353
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
350
354
  }
351
355
  };
352
356
 
@@ -967,7 +971,7 @@ var ModelService = class {
967
971
  * 初始化服务
968
972
  */
969
973
  async initialize(statsDir) {
970
- this.statsPath = path4.join(statsDir, "tokens");
974
+ this.statsPath = path5.join(statsDir, "tokens");
971
975
  await this.loadStats();
972
976
  const model = this.configManager.get("model");
973
977
  const apiKey = this.configManager.get("apiKey");
@@ -1140,8 +1144,8 @@ var ModelService = class {
1140
1144
  async loadStats() {
1141
1145
  if (!this.statsPath) return;
1142
1146
  try {
1143
- const dailyPath = path4.join(this.statsPath, "daily.json");
1144
- const totalPath = path4.join(this.statsPath, "total.json");
1147
+ const dailyPath = path5.join(this.statsPath, "daily.json");
1148
+ const totalPath = path5.join(this.statsPath, "total.json");
1145
1149
  const [daily, total] = await Promise.all([
1146
1150
  fs4.readFile(dailyPath, "utf-8").catch(() => "{}"),
1147
1151
  fs4.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
@@ -1158,8 +1162,8 @@ var ModelService = class {
1158
1162
  if (!this.statsPath) return;
1159
1163
  try {
1160
1164
  await fs4.mkdir(this.statsPath, { recursive: true });
1161
- const dailyPath = path4.join(this.statsPath, "daily.json");
1162
- const totalPath = path4.join(this.statsPath, "total.json");
1165
+ const dailyPath = path5.join(this.statsPath, "daily.json");
1166
+ const totalPath = path5.join(this.statsPath, "total.json");
1163
1167
  await Promise.all([
1164
1168
  fs4.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
1165
1169
  fs4.writeFile(totalPath, JSON.stringify({
@@ -2833,15 +2837,15 @@ async function loadProjectContext(workingDirectory) {
2833
2837
  devStandards: ""
2834
2838
  };
2835
2839
  try {
2836
- context.agentsMd = await fs4.readFile(path4.join(workingDirectory, "AGENTS.md"), "utf-8");
2840
+ context.agentsMd = await fs4.readFile(path5.join(workingDirectory, "AGENTS.md"), "utf-8");
2837
2841
  } catch {
2838
2842
  }
2839
2843
  try {
2840
- context.configYaml = await fs4.readFile(path4.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
2844
+ context.configYaml = await fs4.readFile(path5.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
2841
2845
  } catch {
2842
2846
  }
2843
2847
  try {
2844
- context.devStandards = await fs4.readFile(path4.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
2848
+ context.devStandards = await fs4.readFile(path5.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
2845
2849
  } catch {
2846
2850
  }
2847
2851
  return context;
@@ -3777,7 +3781,7 @@ var WorkflowEngine = class {
3777
3781
  */
3778
3782
  async initialize(projectPath) {
3779
3783
  this.projectPath = projectPath;
3780
- this.openspecPath = path4.join(projectPath, "openspec");
3784
+ this.openspecPath = path5.join(projectPath, "openspec");
3781
3785
  await this.ensureDirectories();
3782
3786
  await this.loadProjectContext();
3783
3787
  await this.restoreState();
@@ -3787,19 +3791,19 @@ var WorkflowEngine = class {
3787
3791
  * 加载项目上下文(AGENTS.md 和 config.yaml)
3788
3792
  */
3789
3793
  async loadProjectContext() {
3790
- const agentsMdPath = path4.join(this.projectPath, "AGENTS.md");
3794
+ const agentsMdPath = path5.join(this.projectPath, "AGENTS.md");
3791
3795
  try {
3792
3796
  this.projectContext = await fs4.readFile(agentsMdPath, "utf-8");
3793
3797
  } catch {
3794
3798
  this.projectContext = "";
3795
3799
  }
3796
- const configPath = path4.join(this.openspecPath, "config.yaml");
3800
+ const configPath = path5.join(this.openspecPath, "config.yaml");
3797
3801
  try {
3798
3802
  this.projectConfig = await fs4.readFile(configPath, "utf-8");
3799
3803
  } catch {
3800
3804
  this.projectConfig = "";
3801
3805
  }
3802
- const devstandedPath = path4.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
3806
+ const devstandedPath = path5.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
3803
3807
  try {
3804
3808
  this.devStandards = await fs4.readFile(devstandedPath, "utf-8");
3805
3809
  } catch {
@@ -4087,10 +4091,10 @@ var WorkflowEngine = class {
4087
4091
  await this.createSpecDocument(summary);
4088
4092
  await this.updateChangeRecord("archived");
4089
4093
  await this.saveState();
4090
- const changesDir = path4.join(this.openspecPath, "changes");
4091
- const archiveDir = path4.join(changesDir, "archive");
4092
- const changeFile = path4.join(changesDir, `${changeId}.md`);
4093
- const archiveFile = path4.join(archiveDir, `${changeId}.md`);
4094
+ const changesDir = path5.join(this.openspecPath, "changes");
4095
+ const archiveDir = path5.join(changesDir, "archive");
4096
+ const changeFile = path5.join(changesDir, `${changeId}.md`);
4097
+ const archiveFile = path5.join(archiveDir, `${changeId}.md`);
4094
4098
  await fs4.mkdir(archiveDir, { recursive: true });
4095
4099
  await fs4.rename(changeFile, archiveFile).catch(() => {
4096
4100
  });
@@ -4114,14 +4118,14 @@ var WorkflowEngine = class {
4114
4118
  }
4115
4119
  // ==================== 私有方法 ====================
4116
4120
  async ensureDirectories() {
4117
- const changesDir = path4.join(this.openspecPath, "changes");
4118
- const archiveDir = path4.join(changesDir, "archive");
4119
- const specDir = path4.join(this.openspecPath, "spec");
4121
+ const changesDir = path5.join(this.openspecPath, "changes");
4122
+ const archiveDir = path5.join(changesDir, "archive");
4123
+ const specDir = path5.join(this.openspecPath, "spec");
4120
4124
  await fs4.mkdir(archiveDir, { recursive: true });
4121
4125
  await fs4.mkdir(specDir, { recursive: true });
4122
4126
  }
4123
4127
  async restoreState() {
4124
- const statePath = path4.join(this.openspecPath, ".workflow-state.json");
4128
+ const statePath = path5.join(this.openspecPath, ".workflow-state.json");
4125
4129
  try {
4126
4130
  const content = await fs4.readFile(statePath, "utf-8");
4127
4131
  this.state = JSON.parse(content, (key, value) => {
@@ -4141,11 +4145,11 @@ var WorkflowEngine = class {
4141
4145
  }
4142
4146
  }
4143
4147
  async saveState() {
4144
- const statePath = path4.join(this.openspecPath, ".workflow-state.json");
4148
+ const statePath = path5.join(this.openspecPath, ".workflow-state.json");
4145
4149
  await fs4.writeFile(statePath, JSON.stringify(this.state, null, 2));
4146
4150
  }
4147
4151
  async restoreSnapshots() {
4148
- const snapshotsPath = path4.join(this.openspecPath, ".workflow-snapshots.json");
4152
+ const snapshotsPath = path5.join(this.openspecPath, ".workflow-snapshots.json");
4149
4153
  try {
4150
4154
  const content = await fs4.readFile(snapshotsPath, "utf-8");
4151
4155
  const data = JSON.parse(content, (key, value) => {
@@ -4162,7 +4166,7 @@ var WorkflowEngine = class {
4162
4166
  }
4163
4167
  }
4164
4168
  async saveSnapshots() {
4165
- const snapshotsPath = path4.join(this.openspecPath, ".workflow-snapshots.json");
4169
+ const snapshotsPath = path5.join(this.openspecPath, ".workflow-snapshots.json");
4166
4170
  const data = Array.from(this.snapshots.values());
4167
4171
  await fs4.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
4168
4172
  }
@@ -4184,7 +4188,7 @@ var WorkflowEngine = class {
4184
4188
  }
4185
4189
  async createChangeRecord() {
4186
4190
  if (!this.state) return;
4187
- const changePath = path4.join(this.openspecPath, "changes", `${this.state.id}.md`);
4191
+ const changePath = path5.join(this.openspecPath, "changes", `${this.state.id}.md`);
4188
4192
  await fs4.writeFile(changePath, this.formatChangeRecord());
4189
4193
  }
4190
4194
  async updateChangeRecord(status) {
@@ -4192,7 +4196,7 @@ var WorkflowEngine = class {
4192
4196
  if (status) {
4193
4197
  this.state.status = status;
4194
4198
  }
4195
- const changePath = path4.join(this.openspecPath, "changes", `${this.state.id}.md`);
4199
+ const changePath = path5.join(this.openspecPath, "changes", `${this.state.id}.md`);
4196
4200
  await fs4.writeFile(changePath, this.formatChangeRecord());
4197
4201
  }
4198
4202
  formatChangeRecord() {
@@ -4232,7 +4236,7 @@ ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
4232
4236
  }
4233
4237
  async createSpecDocument(summary) {
4234
4238
  if (!this.state) return;
4235
- const specPath = path4.join(this.openspecPath, "spec", `${this.state.id}.md`);
4239
+ const specPath = path5.join(this.openspecPath, "spec", `${this.state.id}.md`);
4236
4240
  const content = `# Spec: ${this.state.title}
4237
4241
 
4238
4242
  > \u53D8\u66F4ID: ${this.state.id}
@@ -4330,7 +4334,7 @@ var NormsManager = class {
4330
4334
  * 从单个文件学习规范
4331
4335
  */
4332
4336
  async learnFromFile(filePath, content) {
4333
- const ext = path4.extname(filePath);
4337
+ const ext = path5.extname(filePath);
4334
4338
  const patterns = this.extractPatterns(filePath, content, ext);
4335
4339
  for (const pattern of patterns) {
4336
4340
  await this.recordOccurrence({
@@ -4937,12 +4941,12 @@ ${response}`;
4937
4941
  for (const entry of entries) {
4938
4942
  if (entry.isDirectory()) {
4939
4943
  if (!IGNORED_DIRS.includes(entry.name)) {
4940
- await scan(path4.join(dir, entry.name));
4944
+ await scan(path5.join(dir, entry.name));
4941
4945
  }
4942
4946
  } else if (entry.isFile()) {
4943
- const ext = path4.extname(entry.name);
4947
+ const ext = path5.extname(entry.name);
4944
4948
  if (SCAN_EXTENSIONS.includes(ext)) {
4945
- files.push(path4.join(dir, entry.name));
4949
+ files.push(path5.join(dir, entry.name));
4946
4950
  }
4947
4951
  }
4948
4952
  }
@@ -4977,13 +4981,13 @@ ${response}`;
4977
4981
  */
4978
4982
  async ensureNormsDir() {
4979
4983
  await fs4.mkdir(this.config.normsDir, { recursive: true });
4980
- await fs4.mkdir(path4.join(this.config.normsDir, "weekly"), { recursive: true });
4984
+ await fs4.mkdir(path5.join(this.config.normsDir, "weekly"), { recursive: true });
4981
4985
  }
4982
4986
  /**
4983
4987
  * 加载已有规范
4984
4988
  */
4985
4989
  async loadStandards() {
4986
- const standardsPath = path4.join(this.config.normsDir, "patterns.json");
4990
+ const standardsPath = path5.join(this.config.normsDir, "patterns.json");
4987
4991
  try {
4988
4992
  const content = await fs4.readFile(standardsPath, "utf-8");
4989
4993
  const data = JSON.parse(content);
@@ -5001,7 +5005,7 @@ ${response}`;
5001
5005
  * 加载权重数据
5002
5006
  */
5003
5007
  async loadWeights() {
5004
- const weightsPath = path4.join(this.config.normsDir, "weights.json");
5008
+ const weightsPath = path5.join(this.config.normsDir, "weights.json");
5005
5009
  try {
5006
5010
  const content = await fs4.readFile(weightsPath, "utf-8");
5007
5011
  const data = JSON.parse(content);
@@ -5018,7 +5022,7 @@ ${response}`;
5018
5022
  * 保存规范
5019
5023
  */
5020
5024
  async saveStandards() {
5021
- const standardsPath = path4.join(this.config.normsDir, "patterns.json");
5025
+ const standardsPath = path5.join(this.config.normsDir, "patterns.json");
5022
5026
  await fs4.writeFile(
5023
5027
  standardsPath,
5024
5028
  JSON.stringify(Array.from(this.standards.values()), null, 2),
@@ -5029,7 +5033,7 @@ ${response}`;
5029
5033
  * 保存权重
5030
5034
  */
5031
5035
  async saveWeights() {
5032
- const weightsPath = path4.join(this.config.normsDir, "weights.json");
5036
+ const weightsPath = path5.join(this.config.normsDir, "weights.json");
5033
5037
  await fs4.writeFile(
5034
5038
  weightsPath,
5035
5039
  JSON.stringify(Array.from(this.weights.values()), null, 2),
@@ -5057,7 +5061,7 @@ ${response}`;
5057
5061
  * 保存周报
5058
5062
  */
5059
5063
  async saveWeeklyReport(weekId, report) {
5060
- const reportPath = path4.join(this.config.normsDir, "weekly", `${weekId}.json`);
5064
+ const reportPath = path5.join(this.config.normsDir, "weekly", `${weekId}.json`);
5061
5065
  await fs4.writeFile(reportPath, JSON.stringify(report, null, 2), "utf-8");
5062
5066
  }
5063
5067
  /**
@@ -5066,7 +5070,7 @@ ${response}`;
5066
5070
  async updateDevStandedMd() {
5067
5071
  const standards = this.getEffectiveStandards();
5068
5072
  const content = this.generateDevStandedMd(standards);
5069
- const mdPath = path4.join(this.config.normsDir, "devstanded.md");
5073
+ const mdPath = path5.join(this.config.normsDir, "devstanded.md");
5070
5074
  await fs4.writeFile(mdPath, content, "utf-8");
5071
5075
  }
5072
5076
  /**
@@ -5214,7 +5218,7 @@ var ContextManager = class {
5214
5218
  }
5215
5219
  async initialize(projectPath) {
5216
5220
  this.projectPath = projectPath;
5217
- this.persistPath = path4.join(projectPath, ".sf-cli", "cache", "context", "context.json");
5221
+ this.persistPath = path5.join(projectPath, ".sf-cli", "cache", "context", "context.json");
5218
5222
  await this.loadPersistedContext();
5219
5223
  }
5220
5224
  /**
@@ -5455,7 +5459,7 @@ ${summary}`,
5455
5459
  */
5456
5460
  async persist() {
5457
5461
  if (!this.persistPath) return;
5458
- const dir = path4.dirname(this.persistPath);
5462
+ const dir = path5.dirname(this.persistPath);
5459
5463
  await fs4.mkdir(dir, { recursive: true });
5460
5464
  const data = {
5461
5465
  messages: this.state.messages,
@@ -5590,8 +5594,8 @@ var CommandParser = class {
5590
5594
  };
5591
5595
  }
5592
5596
  parseAtPath(input) {
5593
- const path11 = input.slice(1).trim();
5594
- if (!path11) {
5597
+ const path14 = input.slice(1).trim();
5598
+ if (!path14) {
5595
5599
  return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
5596
5600
  }
5597
5601
  return {
@@ -5599,7 +5603,7 @@ var CommandParser = class {
5599
5603
  command: {
5600
5604
  type: "at" /* AT */,
5601
5605
  raw: input,
5602
- path: path11
5606
+ path: path14
5603
5607
  }
5604
5608
  };
5605
5609
  }
@@ -5655,9 +5659,9 @@ async function initProject(options = {}, workingDir) {
5655
5659
  output: chalk9.red(`\u9519\u8BEF: \u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6743\u9650\u8BBF\u95EE ${cwd}`)
5656
5660
  };
5657
5661
  }
5658
- const sfCliDir = path4.join(cwd, ".sf-cli");
5659
- const openspecDir = path4.join(cwd, "openspec");
5660
- const agentsMdPath = path4.join(cwd, "AGENTS.md");
5662
+ const sfCliDir = path5.join(cwd, ".sf-cli");
5663
+ const openspecDir = path5.join(cwd, "openspec");
5664
+ const agentsMdPath = path5.join(cwd, "AGENTS.md");
5661
5665
  try {
5662
5666
  const agentsExists = await fileExists(agentsMdPath);
5663
5667
  if (agentsExists && !options.force) {
@@ -5717,7 +5721,7 @@ async function createSfCliDirectory(basePath) {
5717
5721
  "logs"
5718
5722
  ];
5719
5723
  for (const dir of dirs) {
5720
- await fs4.mkdir(path4.join(basePath, dir), { recursive: true });
5724
+ await fs4.mkdir(path5.join(basePath, dir), { recursive: true });
5721
5725
  }
5722
5726
  const config = {
5723
5727
  version: "1.0.0",
@@ -5726,36 +5730,36 @@ async function createSfCliDirectory(basePath) {
5726
5730
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
5727
5731
  };
5728
5732
  await fs4.writeFile(
5729
- path4.join(basePath, "config.json"),
5733
+ path5.join(basePath, "config.json"),
5730
5734
  JSON.stringify(config, null, 2),
5731
5735
  "utf-8"
5732
5736
  );
5733
5737
  await fs4.writeFile(
5734
- path4.join(basePath, "agents", "registry.json"),
5738
+ path5.join(basePath, "agents", "registry.json"),
5735
5739
  JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
5736
5740
  "utf-8"
5737
5741
  );
5738
5742
  await fs4.writeFile(
5739
- path4.join(basePath, "skills", "registry.json"),
5743
+ path5.join(basePath, "skills", "registry.json"),
5740
5744
  JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
5741
5745
  "utf-8"
5742
5746
  );
5743
5747
  await fs4.writeFile(
5744
- path4.join(basePath, "health", "health.md"),
5748
+ path5.join(basePath, "health", "health.md"),
5745
5749
  generateHealthTemplate(),
5746
5750
  "utf-8"
5747
5751
  );
5748
5752
  }
5749
5753
  async function createOpenSpecDirectory(basePath) {
5750
- const changesDir = path4.join(basePath, "changes");
5751
- const archiveDir = path4.join(changesDir, "archive");
5752
- const specDir = path4.join(basePath, "spec");
5754
+ const changesDir = path5.join(basePath, "changes");
5755
+ const archiveDir = path5.join(changesDir, "archive");
5756
+ const specDir = path5.join(basePath, "spec");
5753
5757
  await fs4.mkdir(archiveDir, { recursive: true });
5754
5758
  await fs4.mkdir(specDir, { recursive: true });
5755
5759
  }
5756
5760
  async function analyzeProject(cwd) {
5757
5761
  const result = {
5758
- name: path4.basename(cwd),
5762
+ name: path5.basename(cwd),
5759
5763
  type: "unknown",
5760
5764
  framework: null,
5761
5765
  techStack: [],
@@ -5774,7 +5778,7 @@ async function analyzeProject(cwd) {
5774
5778
  hasEslint: false,
5775
5779
  hasPrettier: false
5776
5780
  };
5777
- const pkgPath = path4.join(cwd, "package.json");
5781
+ const pkgPath = path5.join(cwd, "package.json");
5778
5782
  try {
5779
5783
  const pkgContent = await fs4.readFile(pkgPath, "utf-8");
5780
5784
  const pkg = JSON.parse(pkgContent);
@@ -5895,7 +5899,7 @@ async function findEntryPoints(cwd) {
5895
5899
  "index.js"
5896
5900
  ];
5897
5901
  for (const entry of possibleEntries) {
5898
- const fullPath = path4.join(cwd, entry);
5902
+ const fullPath = path5.join(cwd, entry);
5899
5903
  if (await fileExists(fullPath)) {
5900
5904
  entryPoints.push(entry);
5901
5905
  }
@@ -5903,7 +5907,7 @@ async function findEntryPoints(cwd) {
5903
5907
  return entryPoints;
5904
5908
  }
5905
5909
  async function saveProjectAnalysis(sfCliDir, analysis) {
5906
- const analysisPath = path4.join(sfCliDir, "cache", "analysis", "project-analysis.json");
5910
+ const analysisPath = path5.join(sfCliDir, "cache", "analysis", "project-analysis.json");
5907
5911
  await fs4.writeFile(
5908
5912
  analysisPath,
5909
5913
  JSON.stringify(analysis, null, 2),
@@ -5911,7 +5915,7 @@ async function saveProjectAnalysis(sfCliDir, analysis) {
5911
5915
  );
5912
5916
  }
5913
5917
  async function generateOpenSpecConfig(openspecDir, analysis) {
5914
- const configPath = path4.join(openspecDir, "config.yaml");
5918
+ const configPath = path5.join(openspecDir, "config.yaml");
5915
5919
  const content = `# OpenSpec \u9879\u76EE\u914D\u7F6E
5916
5920
  # \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
5917
5921
 
@@ -6443,8 +6447,10 @@ function createSpinner(message) {
6443
6447
  stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
6444
6448
  };
6445
6449
  }
6446
- var CURRENT_VERSION = "1.0.0";
6447
- var PACKAGE_NAME = "sf-cli";
6450
+ var packageJsonPath = path5.resolve(__dirname$1, "../../package.json");
6451
+ var packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, "utf-8"));
6452
+ var CURRENT_VERSION = packageJson.version;
6453
+ var PACKAGE_NAME = packageJson.name;
6448
6454
  async function handleUpdate(args, ctx) {
6449
6455
  const options = {
6450
6456
  check: args.includes("--check") || args.includes("-c"),
@@ -6471,6 +6477,9 @@ async function checkForUpdates() {
6471
6477
  const latestVersion = await getLatestVersion();
6472
6478
  if (!latestVersion) {
6473
6479
  lines.push(chalk9.yellow("\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
6480
+ lines.push(chalk9.gray("\u53EF\u80FD\u539F\u56E0:"));
6481
+ lines.push(chalk9.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
6482
+ lines.push(chalk9.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
6474
6483
  return { output: lines.join("\n") };
6475
6484
  }
6476
6485
  lines.push(chalk9.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
@@ -6489,43 +6498,70 @@ async function checkForUpdates() {
6489
6498
  async function performUpdate(targetVersion) {
6490
6499
  const lines = [];
6491
6500
  lines.push(chalk9.cyan("\u6B63\u5728\u66F4\u65B0 sf-cli..."));
6501
+ lines.push(chalk9.gray(` \u5305\u540D: ${PACKAGE_NAME}`));
6502
+ lines.push(chalk9.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
6492
6503
  try {
6493
6504
  const latestVersion = await getLatestVersion();
6505
+ if (!latestVersion && !targetVersion) {
6506
+ lines.push(chalk9.yellow("\n\u26A0 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
6507
+ lines.push(chalk9.gray("\n\u53EF\u80FD\u539F\u56E0:"));
6508
+ lines.push(chalk9.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
6509
+ lines.push(chalk9.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
6510
+ lines.push(chalk9.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
6511
+ lines.push(chalk9.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
6512
+ return { output: lines.join("\n") };
6513
+ }
6494
6514
  if (latestVersion === CURRENT_VERSION && !targetVersion) {
6495
- lines.push(chalk9.green("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
6515
+ lines.push(chalk9.green("\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
6496
6516
  return { output: lines.join("\n") };
6497
6517
  }
6498
6518
  const packageSpec = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
6499
6519
  lines.push(chalk9.gray(` \u5B89\u88C5: ${packageSpec}`));
6500
- await new Promise((resolve2, reject) => {
6520
+ const installResult = await new Promise((resolve4) => {
6501
6521
  const proc = spawn("npm", ["install", "-g", packageSpec], {
6502
6522
  stdio: "pipe",
6503
6523
  shell: true
6504
6524
  });
6525
+ let output = "";
6526
+ proc.stdout?.on("data", (data) => {
6527
+ output += data.toString();
6528
+ });
6529
+ proc.stderr?.on("data", (data) => {
6530
+ output += data.toString();
6531
+ });
6505
6532
  proc.on("close", (code) => {
6506
- if (code === 0) {
6507
- resolve2();
6508
- } else {
6509
- reject(new Error(`npm install exited with code ${code}`));
6510
- }
6533
+ resolve4({
6534
+ success: code === 0,
6535
+ output
6536
+ });
6511
6537
  });
6512
6538
  proc.on("error", (err) => {
6513
- reject(err);
6539
+ resolve4({
6540
+ success: false,
6541
+ output: err.message
6542
+ });
6514
6543
  });
6515
6544
  });
6516
- lines.push(chalk9.green("\u2713 \u66F4\u65B0\u5B8C\u6210!"));
6545
+ if (!installResult.success) {
6546
+ lines.push(chalk9.red("\n\u2717 \u66F4\u65B0\u5931\u8D25"));
6547
+ lines.push(chalk9.gray(installResult.output));
6548
+ lines.push(chalk9.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
6549
+ lines.push(chalk9.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
6550
+ return { output: lines.join("\n") };
6551
+ }
6552
+ lines.push(chalk9.green("\n\u2713 \u66F4\u65B0\u5B8C\u6210!"));
6517
6553
  lines.push(chalk9.gray(` \u65B0\u7248\u672C: v${targetVersion || latestVersion}`));
6518
6554
  lines.push(chalk9.gray("\n\u8BF7\u91CD\u542F CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"));
6519
6555
  } catch (error) {
6520
6556
  lines.push(chalk9.red("\u66F4\u65B0\u5931\u8D25: " + error.message));
6521
6557
  lines.push(chalk9.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
6522
- lines.push(chalk9.gray(" npm install -g sf-cli@latest"));
6558
+ lines.push(chalk9.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
6523
6559
  }
6524
6560
  return { output: lines.join("\n") };
6525
6561
  }
6526
6562
  async function getLatestVersion() {
6527
6563
  try {
6528
- const result = await new Promise((resolve2, reject) => {
6564
+ const result = await new Promise((resolve4, reject) => {
6529
6565
  const proc = spawn("npm", ["view", PACKAGE_NAME, "version"], {
6530
6566
  stdio: "pipe",
6531
6567
  shell: true
@@ -6535,13 +6571,17 @@ async function getLatestVersion() {
6535
6571
  output += data.toString();
6536
6572
  });
6537
6573
  proc.on("close", (code) => {
6538
- if (code === 0) {
6539
- resolve2(output.trim());
6574
+ if (code === 0 && output.trim()) {
6575
+ resolve4(output.trim());
6540
6576
  } else {
6541
6577
  reject(new Error("Failed to get version"));
6542
6578
  }
6543
6579
  });
6544
6580
  proc.on("error", reject);
6581
+ setTimeout(() => {
6582
+ proc.kill();
6583
+ reject(new Error("Timeout"));
6584
+ }, 1e4);
6545
6585
  });
6546
6586
  return result || null;
6547
6587
  } catch {
@@ -6723,13 +6763,13 @@ function parseArgs(args) {
6723
6763
  }
6724
6764
  async function readProjectContext(cwd) {
6725
6765
  const defaultContext = {
6726
- name: path4.basename(cwd),
6766
+ name: path5.basename(cwd),
6727
6767
  type: "unknown",
6728
6768
  framework: null,
6729
6769
  techStack: [],
6730
6770
  description: ""
6731
6771
  };
6732
- const agentsPath = path4.join(cwd, "AGENTS.md");
6772
+ const agentsPath = path5.join(cwd, "AGENTS.md");
6733
6773
  try {
6734
6774
  const stats = await fs4.stat(agentsPath);
6735
6775
  if (stats.size > MAX_FILE_SIZE2) {
@@ -6744,7 +6784,7 @@ async function readProjectContext(cwd) {
6744
6784
  console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 AGENTS.md - ${err.message}`);
6745
6785
  }
6746
6786
  }
6747
- const configPath = path4.join(cwd, "openspec", "config.yaml");
6787
+ const configPath = path5.join(cwd, "openspec", "config.yaml");
6748
6788
  try {
6749
6789
  const stats = await fs4.stat(configPath);
6750
6790
  if (stats.size > MAX_FILE_SIZE2) {
@@ -7223,9 +7263,11 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9.cyan(`
7223
7263
  throw e;
7224
7264
  }
7225
7265
  }
7226
- var require2 = createRequire(import.meta.url);
7227
- var packageJson = require2("../../package.json");
7228
- var VERSION2 = packageJson.version;
7266
+
7267
+ // src/commands/runner.ts
7268
+ var packageJsonPath2 = path5.resolve(__dirname$1, "../../package.json");
7269
+ var packageJson2 = JSON.parse(fsSync.readFileSync(packageJsonPath2, "utf-8"));
7270
+ var VERSION2 = packageJson2.version;
7229
7271
  async function runSlashCommand(command, args, ctx) {
7230
7272
  const normalizedCommand = normalizeCommand(command);
7231
7273
  switch (normalizedCommand) {
@@ -7272,7 +7314,7 @@ function normalizeCommand(command) {
7272
7314
  }
7273
7315
  async function handleFileReference(filePath, ctx) {
7274
7316
  const cwd = ctx.options.workingDirectory;
7275
- const absolutePath = path4.isAbsolute(filePath) ? filePath : path4.join(cwd, filePath);
7317
+ const absolutePath = path5.isAbsolute(filePath) ? filePath : path5.join(cwd, filePath);
7276
7318
  try {
7277
7319
  const stats = await fs4.stat(absolutePath);
7278
7320
  if (stats.isDirectory()) {
@@ -7320,7 +7362,7 @@ async function executeShell(command, ctx) {
7320
7362
  \u547D\u4EE4 "${command}" \u53EF\u80FD\u4F1A\u5220\u9664\u91CD\u8981\u6587\u4EF6`) + chalk9.gray("\n\u4F7F\u7528 yolo \u6A21\u5F0F\u5F3A\u5236\u6267\u884C")
7321
7363
  };
7322
7364
  }
7323
- return new Promise((resolve2) => {
7365
+ return new Promise((resolve4) => {
7324
7366
  const shell = spawn(command, [], {
7325
7367
  shell: true,
7326
7368
  cwd: ctx.options.workingDirectory
@@ -7345,11 +7387,11 @@ async function executeShell(command, ctx) {
7345
7387
  output += chalk9.red(`
7346
7388
  \u9000\u51FA\u7801: ${code}`);
7347
7389
  }
7348
- resolve2({ output: output || chalk9.gray("(\u65E0\u8F93\u51FA)") });
7390
+ resolve4({ output: output || chalk9.gray("(\u65E0\u8F93\u51FA)") });
7349
7391
  });
7350
7392
  setTimeout(() => {
7351
7393
  shell.kill();
7352
- resolve2({
7394
+ resolve4({
7353
7395
  output: chalk9.yellow("\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0C\u5DF2\u7EC8\u6B62")
7354
7396
  });
7355
7397
  }, 6e4);
@@ -7656,7 +7698,7 @@ var Completer = class {
7656
7698
  prefix = filePath;
7657
7699
  } else {
7658
7700
  const dir = filePath.slice(0, lastSlash);
7659
- dirPath = path4.resolve(this.workingDirectory, dir);
7701
+ dirPath = path5.resolve(this.workingDirectory, dir);
7660
7702
  prefix = filePath.slice(lastSlash + 1);
7661
7703
  }
7662
7704
  try {
@@ -7666,7 +7708,7 @@ var Completer = class {
7666
7708
  if (entry.name.startsWith(prefix)) {
7667
7709
  const isDir = entry.isDirectory();
7668
7710
  matches.push({
7669
- text: "@" + path4.relative(this.workingDirectory, path4.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
7711
+ text: "@" + path5.relative(this.workingDirectory, path5.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
7670
7712
  displayText: entry.name + (isDir ? "/" : ""),
7671
7713
  description: isDir ? "\u76EE\u5F55" : "\u6587\u4EF6",
7672
7714
  type: isDir ? "directory" : "file"