@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/cli/index.js +202 -167
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +72 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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 fsSync = require('fs');
|
|
7
|
+
var path6 = require('path');
|
|
6
8
|
var readline = require('readline');
|
|
7
|
-
var
|
|
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);
|
|
41
|
-
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
42
|
-
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
43
|
-
var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
|
|
44
40
|
var fsSync__namespace = /*#__PURE__*/_interopNamespace(fsSync);
|
|
41
|
+
var path6__namespace = /*#__PURE__*/_interopNamespace(path6);
|
|
42
|
+
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
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
|
|
134
|
-
if (!
|
|
128
|
+
const path15 = input.slice(1).trim();
|
|
129
|
+
if (!path15) {
|
|
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:
|
|
137
|
+
path: path15
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
843
|
+
await scan(path6__namespace.join(dir, entry.name));
|
|
849
844
|
}
|
|
850
845
|
} else if (entry.isFile()) {
|
|
851
|
-
const ext =
|
|
846
|
+
const ext = path6__namespace.extname(entry.name);
|
|
852
847
|
if (SCAN_EXTENSIONS.includes(ext)) {
|
|
853
|
-
files.push(
|
|
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
|
|
888
|
-
await
|
|
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 =
|
|
889
|
+
const standardsPath = path6__namespace.join(this.config.normsDir, "patterns.json");
|
|
895
890
|
try {
|
|
896
|
-
const content = await
|
|
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 =
|
|
907
|
+
const weightsPath = path6__namespace.join(this.config.normsDir, "weights.json");
|
|
913
908
|
try {
|
|
914
|
-
const content = await
|
|
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 =
|
|
930
|
-
await
|
|
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 =
|
|
941
|
-
await
|
|
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 =
|
|
969
|
-
await
|
|
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 =
|
|
978
|
-
await
|
|
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
|
|
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 =
|
|
1129
|
-
const openspecDir =
|
|
1130
|
-
const agentsMdPath =
|
|
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
|
|
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
|
|
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
|
|
1199
|
-
|
|
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
|
|
1204
|
-
|
|
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
|
|
1209
|
-
|
|
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
|
|
1214
|
-
|
|
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 =
|
|
1221
|
-
const archiveDir =
|
|
1222
|
-
const specDir =
|
|
1223
|
-
await
|
|
1224
|
-
await
|
|
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:
|
|
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 =
|
|
1242
|
+
const pkgPath = path6__namespace.join(cwd, "package.json");
|
|
1248
1243
|
try {
|
|
1249
|
-
const pkgContent = await
|
|
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
|
|
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 =
|
|
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 =
|
|
1377
|
-
await
|
|
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 =
|
|
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
|
|
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
|
|
1535
|
+
await fs6__namespace.access(filePath);
|
|
1541
1536
|
return true;
|
|
1542
1537
|
} catch {
|
|
1543
1538
|
return false;
|
|
@@ -1708,7 +1703,7 @@ var IV_LENGTH = 16;
|
|
|
1708
1703
|
var KEY_DIR = ".sf-cli";
|
|
1709
1704
|
var KEY_FILE = ".key";
|
|
1710
1705
|
function getOrCreateEncryptionKey() {
|
|
1711
|
-
const keyPath =
|
|
1706
|
+
const keyPath = path6__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
|
|
1712
1707
|
try {
|
|
1713
1708
|
if (fsSync__namespace.existsSync(keyPath)) {
|
|
1714
1709
|
const keyBase64 = fsSync__namespace.readFileSync(keyPath, "utf-8").trim();
|
|
@@ -1718,7 +1713,7 @@ function getOrCreateEncryptionKey() {
|
|
|
1718
1713
|
}
|
|
1719
1714
|
const key = crypto__namespace.randomBytes(32);
|
|
1720
1715
|
try {
|
|
1721
|
-
const keyDir =
|
|
1716
|
+
const keyDir = path6__namespace.dirname(keyPath);
|
|
1722
1717
|
if (!fsSync__namespace.existsSync(keyDir)) {
|
|
1723
1718
|
fsSync__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
|
|
1724
1719
|
}
|
|
@@ -1749,9 +1744,9 @@ var ConfigManager = class {
|
|
|
1749
1744
|
}
|
|
1750
1745
|
async load(projectPath) {
|
|
1751
1746
|
this.projectPath = projectPath;
|
|
1752
|
-
this.configPath =
|
|
1747
|
+
this.configPath = path6__namespace.join(projectPath, ".sf-cli", "config.json");
|
|
1753
1748
|
try {
|
|
1754
|
-
const content = await
|
|
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
|
|
1774
|
-
await
|
|
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((
|
|
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 =
|
|
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 =
|
|
2827
|
-
const totalPath =
|
|
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
|
-
|
|
2830
|
-
|
|
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
|
|
2844
|
-
const dailyPath =
|
|
2845
|
-
const totalPath =
|
|
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
|
-
|
|
2848
|
-
|
|
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,10 @@ function createSpinner(message) {
|
|
|
3086
3081
|
stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
|
|
3087
3082
|
};
|
|
3088
3083
|
}
|
|
3089
|
-
var
|
|
3090
|
-
var
|
|
3084
|
+
var packageJsonPath = path6__namespace.resolve(__dirname, "../../package.json");
|
|
3085
|
+
var packageJson = JSON.parse(fsSync__namespace.readFileSync(packageJsonPath, "utf-8"));
|
|
3086
|
+
var CURRENT_VERSION = packageJson.version;
|
|
3087
|
+
var PACKAGE_NAME = packageJson.name;
|
|
3091
3088
|
async function handleUpdate(args, ctx) {
|
|
3092
3089
|
const options = {
|
|
3093
3090
|
check: args.includes("--check") || args.includes("-c"),
|
|
@@ -3114,6 +3111,9 @@ async function checkForUpdates() {
|
|
|
3114
3111
|
const latestVersion = await getLatestVersion();
|
|
3115
3112
|
if (!latestVersion) {
|
|
3116
3113
|
lines.push(chalk9__default.default.yellow("\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
|
|
3114
|
+
lines.push(chalk9__default.default.gray("\u53EF\u80FD\u539F\u56E0:"));
|
|
3115
|
+
lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
|
|
3116
|
+
lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
|
|
3117
3117
|
return { output: lines.join("\n") };
|
|
3118
3118
|
}
|
|
3119
3119
|
lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
|
|
@@ -3132,43 +3132,70 @@ async function checkForUpdates() {
|
|
|
3132
3132
|
async function performUpdate(targetVersion) {
|
|
3133
3133
|
const lines = [];
|
|
3134
3134
|
lines.push(chalk9__default.default.cyan("\u6B63\u5728\u66F4\u65B0 sf-cli..."));
|
|
3135
|
+
lines.push(chalk9__default.default.gray(` \u5305\u540D: ${PACKAGE_NAME}`));
|
|
3136
|
+
lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
|
|
3135
3137
|
try {
|
|
3136
3138
|
const latestVersion = await getLatestVersion();
|
|
3139
|
+
if (!latestVersion && !targetVersion) {
|
|
3140
|
+
lines.push(chalk9__default.default.yellow("\n\u26A0 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
|
|
3141
|
+
lines.push(chalk9__default.default.gray("\n\u53EF\u80FD\u539F\u56E0:"));
|
|
3142
|
+
lines.push(chalk9__default.default.gray(" 1. \u5305\u5C1A\u672A\u53D1\u5E03\u5230 npm"));
|
|
3143
|
+
lines.push(chalk9__default.default.gray(" 2. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898"));
|
|
3144
|
+
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
3145
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
3146
|
+
return { output: lines.join("\n") };
|
|
3147
|
+
}
|
|
3137
3148
|
if (latestVersion === CURRENT_VERSION && !targetVersion) {
|
|
3138
|
-
lines.push(chalk9__default.default.green("\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
|
|
3149
|
+
lines.push(chalk9__default.default.green("\n\u2713 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF0C\u65E0\u9700\u66F4\u65B0"));
|
|
3139
3150
|
return { output: lines.join("\n") };
|
|
3140
3151
|
}
|
|
3141
3152
|
const packageSpec = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
|
|
3142
3153
|
lines.push(chalk9__default.default.gray(` \u5B89\u88C5: ${packageSpec}`));
|
|
3143
|
-
await new Promise((
|
|
3154
|
+
const installResult = await new Promise((resolve5) => {
|
|
3144
3155
|
const proc = child_process.spawn("npm", ["install", "-g", packageSpec], {
|
|
3145
3156
|
stdio: "pipe",
|
|
3146
3157
|
shell: true
|
|
3147
3158
|
});
|
|
3159
|
+
let output = "";
|
|
3160
|
+
proc.stdout?.on("data", (data) => {
|
|
3161
|
+
output += data.toString();
|
|
3162
|
+
});
|
|
3163
|
+
proc.stderr?.on("data", (data) => {
|
|
3164
|
+
output += data.toString();
|
|
3165
|
+
});
|
|
3148
3166
|
proc.on("close", (code) => {
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
}
|
|
3167
|
+
resolve5({
|
|
3168
|
+
success: code === 0,
|
|
3169
|
+
output
|
|
3170
|
+
});
|
|
3154
3171
|
});
|
|
3155
3172
|
proc.on("error", (err) => {
|
|
3156
|
-
|
|
3173
|
+
resolve5({
|
|
3174
|
+
success: false,
|
|
3175
|
+
output: err.message
|
|
3176
|
+
});
|
|
3157
3177
|
});
|
|
3158
3178
|
});
|
|
3159
|
-
|
|
3179
|
+
if (!installResult.success) {
|
|
3180
|
+
lines.push(chalk9__default.default.red("\n\u2717 \u66F4\u65B0\u5931\u8D25"));
|
|
3181
|
+
lines.push(chalk9__default.default.gray(installResult.output));
|
|
3182
|
+
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
3183
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
3184
|
+
return { output: lines.join("\n") };
|
|
3185
|
+
}
|
|
3186
|
+
lines.push(chalk9__default.default.green("\n\u2713 \u66F4\u65B0\u5B8C\u6210!"));
|
|
3160
3187
|
lines.push(chalk9__default.default.gray(` \u65B0\u7248\u672C: v${targetVersion || latestVersion}`));
|
|
3161
3188
|
lines.push(chalk9__default.default.gray("\n\u8BF7\u91CD\u542F CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"));
|
|
3162
3189
|
} catch (error) {
|
|
3163
3190
|
lines.push(chalk9__default.default.red("\u66F4\u65B0\u5931\u8D25: " + error.message));
|
|
3164
3191
|
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
3165
|
-
lines.push(chalk9__default.default.
|
|
3192
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
3166
3193
|
}
|
|
3167
3194
|
return { output: lines.join("\n") };
|
|
3168
3195
|
}
|
|
3169
3196
|
async function getLatestVersion() {
|
|
3170
3197
|
try {
|
|
3171
|
-
const result = await new Promise((
|
|
3198
|
+
const result = await new Promise((resolve5, reject) => {
|
|
3172
3199
|
const proc = child_process.spawn("npm", ["view", PACKAGE_NAME, "version"], {
|
|
3173
3200
|
stdio: "pipe",
|
|
3174
3201
|
shell: true
|
|
@@ -3178,13 +3205,17 @@ async function getLatestVersion() {
|
|
|
3178
3205
|
output += data.toString();
|
|
3179
3206
|
});
|
|
3180
3207
|
proc.on("close", (code) => {
|
|
3181
|
-
if (code === 0) {
|
|
3182
|
-
|
|
3208
|
+
if (code === 0 && output.trim()) {
|
|
3209
|
+
resolve5(output.trim());
|
|
3183
3210
|
} else {
|
|
3184
3211
|
reject(new Error("Failed to get version"));
|
|
3185
3212
|
}
|
|
3186
3213
|
});
|
|
3187
3214
|
proc.on("error", reject);
|
|
3215
|
+
setTimeout(() => {
|
|
3216
|
+
proc.kill();
|
|
3217
|
+
reject(new Error("Timeout"));
|
|
3218
|
+
}, 1e4);
|
|
3188
3219
|
});
|
|
3189
3220
|
return result || null;
|
|
3190
3221
|
} catch {
|
|
@@ -3468,7 +3499,7 @@ var WorkflowEngine = class {
|
|
|
3468
3499
|
*/
|
|
3469
3500
|
async initialize(projectPath) {
|
|
3470
3501
|
this.projectPath = projectPath;
|
|
3471
|
-
this.openspecPath =
|
|
3502
|
+
this.openspecPath = path6__namespace.join(projectPath, "openspec");
|
|
3472
3503
|
await this.ensureDirectories();
|
|
3473
3504
|
await this.loadProjectContext();
|
|
3474
3505
|
await this.restoreState();
|
|
@@ -3478,21 +3509,21 @@ var WorkflowEngine = class {
|
|
|
3478
3509
|
* 加载项目上下文(AGENTS.md 和 config.yaml)
|
|
3479
3510
|
*/
|
|
3480
3511
|
async loadProjectContext() {
|
|
3481
|
-
const agentsMdPath =
|
|
3512
|
+
const agentsMdPath = path6__namespace.join(this.projectPath, "AGENTS.md");
|
|
3482
3513
|
try {
|
|
3483
|
-
this.projectContext = await
|
|
3514
|
+
this.projectContext = await fs6__namespace.readFile(agentsMdPath, "utf-8");
|
|
3484
3515
|
} catch {
|
|
3485
3516
|
this.projectContext = "";
|
|
3486
3517
|
}
|
|
3487
|
-
const configPath =
|
|
3518
|
+
const configPath = path6__namespace.join(this.openspecPath, "config.yaml");
|
|
3488
3519
|
try {
|
|
3489
|
-
this.projectConfig = await
|
|
3520
|
+
this.projectConfig = await fs6__namespace.readFile(configPath, "utf-8");
|
|
3490
3521
|
} catch {
|
|
3491
3522
|
this.projectConfig = "";
|
|
3492
3523
|
}
|
|
3493
|
-
const devstandedPath =
|
|
3524
|
+
const devstandedPath = path6__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
|
|
3494
3525
|
try {
|
|
3495
|
-
this.devStandards = await
|
|
3526
|
+
this.devStandards = await fs6__namespace.readFile(devstandedPath, "utf-8");
|
|
3496
3527
|
} catch {
|
|
3497
3528
|
this.devStandards = "";
|
|
3498
3529
|
}
|
|
@@ -3778,12 +3809,12 @@ var WorkflowEngine = class {
|
|
|
3778
3809
|
await this.createSpecDocument(summary);
|
|
3779
3810
|
await this.updateChangeRecord("archived");
|
|
3780
3811
|
await this.saveState();
|
|
3781
|
-
const changesDir =
|
|
3782
|
-
const archiveDir =
|
|
3783
|
-
const changeFile =
|
|
3784
|
-
const archiveFile =
|
|
3785
|
-
await
|
|
3786
|
-
await
|
|
3812
|
+
const changesDir = path6__namespace.join(this.openspecPath, "changes");
|
|
3813
|
+
const archiveDir = path6__namespace.join(changesDir, "archive");
|
|
3814
|
+
const changeFile = path6__namespace.join(changesDir, `${changeId}.md`);
|
|
3815
|
+
const archiveFile = path6__namespace.join(archiveDir, `${changeId}.md`);
|
|
3816
|
+
await fs6__namespace.mkdir(archiveDir, { recursive: true });
|
|
3817
|
+
await fs6__namespace.rename(changeFile, archiveFile).catch(() => {
|
|
3787
3818
|
});
|
|
3788
3819
|
this.state = null;
|
|
3789
3820
|
this.snapshots.clear();
|
|
@@ -3805,16 +3836,16 @@ var WorkflowEngine = class {
|
|
|
3805
3836
|
}
|
|
3806
3837
|
// ==================== 私有方法 ====================
|
|
3807
3838
|
async ensureDirectories() {
|
|
3808
|
-
const changesDir =
|
|
3809
|
-
const archiveDir =
|
|
3810
|
-
const specDir =
|
|
3811
|
-
await
|
|
3812
|
-
await
|
|
3839
|
+
const changesDir = path6__namespace.join(this.openspecPath, "changes");
|
|
3840
|
+
const archiveDir = path6__namespace.join(changesDir, "archive");
|
|
3841
|
+
const specDir = path6__namespace.join(this.openspecPath, "spec");
|
|
3842
|
+
await fs6__namespace.mkdir(archiveDir, { recursive: true });
|
|
3843
|
+
await fs6__namespace.mkdir(specDir, { recursive: true });
|
|
3813
3844
|
}
|
|
3814
3845
|
async restoreState() {
|
|
3815
|
-
const statePath =
|
|
3846
|
+
const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
3816
3847
|
try {
|
|
3817
|
-
const content = await
|
|
3848
|
+
const content = await fs6__namespace.readFile(statePath, "utf-8");
|
|
3818
3849
|
this.state = JSON.parse(content, (key, value) => {
|
|
3819
3850
|
if (key.endsWith("At") && typeof value === "string") {
|
|
3820
3851
|
return new Date(value);
|
|
@@ -3825,20 +3856,20 @@ var WorkflowEngine = class {
|
|
|
3825
3856
|
const err = e;
|
|
3826
3857
|
if (err.code !== "ENOENT") {
|
|
3827
3858
|
console.warn("\u8B66\u544A: \u5DE5\u4F5C\u6D41\u72B6\u6001\u6587\u4EF6\u5DF2\u635F\u574F\uFF0C\u5C06\u91CD\u65B0\u5F00\u59CB");
|
|
3828
|
-
await
|
|
3859
|
+
await fs6__namespace.unlink(statePath).catch(() => {
|
|
3829
3860
|
});
|
|
3830
3861
|
}
|
|
3831
3862
|
this.state = null;
|
|
3832
3863
|
}
|
|
3833
3864
|
}
|
|
3834
3865
|
async saveState() {
|
|
3835
|
-
const statePath =
|
|
3836
|
-
await
|
|
3866
|
+
const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
3867
|
+
await fs6__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
|
|
3837
3868
|
}
|
|
3838
3869
|
async restoreSnapshots() {
|
|
3839
|
-
const snapshotsPath =
|
|
3870
|
+
const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
3840
3871
|
try {
|
|
3841
|
-
const content = await
|
|
3872
|
+
const content = await fs6__namespace.readFile(snapshotsPath, "utf-8");
|
|
3842
3873
|
const data = JSON.parse(content, (key, value) => {
|
|
3843
3874
|
if (key === "timestamp" && typeof value === "string") {
|
|
3844
3875
|
return new Date(value);
|
|
@@ -3853,9 +3884,9 @@ var WorkflowEngine = class {
|
|
|
3853
3884
|
}
|
|
3854
3885
|
}
|
|
3855
3886
|
async saveSnapshots() {
|
|
3856
|
-
const snapshotsPath =
|
|
3887
|
+
const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
3857
3888
|
const data = Array.from(this.snapshots.values());
|
|
3858
|
-
await
|
|
3889
|
+
await fs6__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
|
|
3859
3890
|
}
|
|
3860
3891
|
async createSnapshot() {
|
|
3861
3892
|
if (!this.state) return;
|
|
@@ -3875,16 +3906,16 @@ var WorkflowEngine = class {
|
|
|
3875
3906
|
}
|
|
3876
3907
|
async createChangeRecord() {
|
|
3877
3908
|
if (!this.state) return;
|
|
3878
|
-
const changePath =
|
|
3879
|
-
await
|
|
3909
|
+
const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
3910
|
+
await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
3880
3911
|
}
|
|
3881
3912
|
async updateChangeRecord(status) {
|
|
3882
3913
|
if (!this.state) return;
|
|
3883
3914
|
if (status) {
|
|
3884
3915
|
this.state.status = status;
|
|
3885
3916
|
}
|
|
3886
|
-
const changePath =
|
|
3887
|
-
await
|
|
3917
|
+
const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
3918
|
+
await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
3888
3919
|
}
|
|
3889
3920
|
formatChangeRecord() {
|
|
3890
3921
|
if (!this.state) return "";
|
|
@@ -3923,7 +3954,7 @@ ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
|
3923
3954
|
}
|
|
3924
3955
|
async createSpecDocument(summary) {
|
|
3925
3956
|
if (!this.state) return;
|
|
3926
|
-
const specPath =
|
|
3957
|
+
const specPath = path6__namespace.join(this.openspecPath, "spec", `${this.state.id}.md`);
|
|
3927
3958
|
const content = `# Spec: ${this.state.title}
|
|
3928
3959
|
|
|
3929
3960
|
> \u53D8\u66F4ID: ${this.state.id}
|
|
@@ -3948,7 +3979,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
|
|
|
3948
3979
|
|
|
3949
3980
|
${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
3950
3981
|
`;
|
|
3951
|
-
await
|
|
3982
|
+
await fs6__namespace.writeFile(specPath, content);
|
|
3952
3983
|
}
|
|
3953
3984
|
};
|
|
3954
3985
|
var ConfirmationRequiredError = class extends Error {
|
|
@@ -3993,7 +4024,7 @@ async function newFeature(options, workingDir, workflowEngine) {
|
|
|
3993
4024
|
const cwd = workingDir || process.cwd();
|
|
3994
4025
|
const { requirement, forceComplexity } = options;
|
|
3995
4026
|
try {
|
|
3996
|
-
const stats = await
|
|
4027
|
+
const stats = await fs6__namespace.stat(cwd);
|
|
3997
4028
|
if (!stats.isDirectory()) {
|
|
3998
4029
|
return {
|
|
3999
4030
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
@@ -4064,20 +4095,20 @@ function parseArgs(args) {
|
|
|
4064
4095
|
}
|
|
4065
4096
|
async function readProjectContext(cwd) {
|
|
4066
4097
|
const defaultContext = {
|
|
4067
|
-
name:
|
|
4098
|
+
name: path6__namespace.basename(cwd),
|
|
4068
4099
|
type: "unknown",
|
|
4069
4100
|
framework: null,
|
|
4070
4101
|
techStack: [],
|
|
4071
4102
|
description: ""
|
|
4072
4103
|
};
|
|
4073
|
-
const agentsPath =
|
|
4104
|
+
const agentsPath = path6__namespace.join(cwd, "AGENTS.md");
|
|
4074
4105
|
try {
|
|
4075
|
-
const stats = await
|
|
4106
|
+
const stats = await fs6__namespace.stat(agentsPath);
|
|
4076
4107
|
if (stats.size > MAX_FILE_SIZE2) {
|
|
4077
4108
|
console.warn(`\u8B66\u544A: AGENTS.md \u6587\u4EF6\u8FC7\u5927 (${stats.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
4078
4109
|
return defaultContext;
|
|
4079
4110
|
}
|
|
4080
|
-
const content = await
|
|
4111
|
+
const content = await fs6__namespace.readFile(agentsPath, "utf-8");
|
|
4081
4112
|
return parseAgentsMd(content, defaultContext);
|
|
4082
4113
|
} catch (e) {
|
|
4083
4114
|
const err = e;
|
|
@@ -4085,14 +4116,14 @@ async function readProjectContext(cwd) {
|
|
|
4085
4116
|
console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 AGENTS.md - ${err.message}`);
|
|
4086
4117
|
}
|
|
4087
4118
|
}
|
|
4088
|
-
const configPath =
|
|
4119
|
+
const configPath = path6__namespace.join(cwd, "openspec", "config.yaml");
|
|
4089
4120
|
try {
|
|
4090
|
-
const stats = await
|
|
4121
|
+
const stats = await fs6__namespace.stat(configPath);
|
|
4091
4122
|
if (stats.size > MAX_FILE_SIZE2) {
|
|
4092
4123
|
console.warn(`\u8B66\u544A: config.yaml \u6587\u4EF6\u8FC7\u5927\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
4093
4124
|
return defaultContext;
|
|
4094
4125
|
}
|
|
4095
|
-
const content = await
|
|
4126
|
+
const content = await fs6__namespace.readFile(configPath, "utf-8");
|
|
4096
4127
|
return parseConfigYaml(content, defaultContext);
|
|
4097
4128
|
} catch (e) {
|
|
4098
4129
|
const err = e;
|
|
@@ -4652,15 +4683,15 @@ async function loadProjectContext(workingDirectory) {
|
|
|
4652
4683
|
devStandards: ""
|
|
4653
4684
|
};
|
|
4654
4685
|
try {
|
|
4655
|
-
context.agentsMd = await
|
|
4686
|
+
context.agentsMd = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
|
|
4656
4687
|
} catch {
|
|
4657
4688
|
}
|
|
4658
4689
|
try {
|
|
4659
|
-
context.configYaml = await
|
|
4690
|
+
context.configYaml = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
|
|
4660
4691
|
} catch {
|
|
4661
4692
|
}
|
|
4662
4693
|
try {
|
|
4663
|
-
context.devStandards = await
|
|
4694
|
+
context.devStandards = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
|
|
4664
4695
|
} catch {
|
|
4665
4696
|
}
|
|
4666
4697
|
return context;
|
|
@@ -5181,9 +5212,11 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
|
|
|
5181
5212
|
throw e;
|
|
5182
5213
|
}
|
|
5183
5214
|
}
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
var
|
|
5215
|
+
|
|
5216
|
+
// src/commands/runner.ts
|
|
5217
|
+
var packageJsonPath2 = path6__namespace.resolve(__dirname, "../../package.json");
|
|
5218
|
+
var packageJson2 = JSON.parse(fsSync__namespace.readFileSync(packageJsonPath2, "utf-8"));
|
|
5219
|
+
var VERSION2 = packageJson2.version;
|
|
5187
5220
|
async function runSlashCommand(command, args, ctx) {
|
|
5188
5221
|
const normalizedCommand = normalizeCommand(command);
|
|
5189
5222
|
switch (normalizedCommand) {
|
|
@@ -5230,11 +5263,11 @@ function normalizeCommand(command) {
|
|
|
5230
5263
|
}
|
|
5231
5264
|
async function handleFileReference(filePath, ctx) {
|
|
5232
5265
|
const cwd = ctx.options.workingDirectory;
|
|
5233
|
-
const absolutePath =
|
|
5266
|
+
const absolutePath = path6__namespace.isAbsolute(filePath) ? filePath : path6__namespace.join(cwd, filePath);
|
|
5234
5267
|
try {
|
|
5235
|
-
const stats = await
|
|
5268
|
+
const stats = await fs6__namespace.stat(absolutePath);
|
|
5236
5269
|
if (stats.isDirectory()) {
|
|
5237
|
-
const files = await
|
|
5270
|
+
const files = await fs6__namespace.readdir(absolutePath);
|
|
5238
5271
|
return {
|
|
5239
5272
|
output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
|
|
5240
5273
|
${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
|
|
@@ -5242,7 +5275,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
|
|
|
5242
5275
|
contextUsed: 0
|
|
5243
5276
|
};
|
|
5244
5277
|
}
|
|
5245
|
-
const content = await
|
|
5278
|
+
const content = await fs6__namespace.readFile(absolutePath, "utf-8");
|
|
5246
5279
|
const lines = content.split("\n");
|
|
5247
5280
|
ctx.contextManager.addMessage({
|
|
5248
5281
|
role: "user",
|
|
@@ -5278,7 +5311,7 @@ async function executeShell(command, ctx) {
|
|
|
5278
5311
|
\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
5312
|
};
|
|
5280
5313
|
}
|
|
5281
|
-
return new Promise((
|
|
5314
|
+
return new Promise((resolve5) => {
|
|
5282
5315
|
const shell = child_process.spawn(command, [], {
|
|
5283
5316
|
shell: true,
|
|
5284
5317
|
cwd: ctx.options.workingDirectory
|
|
@@ -5303,11 +5336,11 @@ async function executeShell(command, ctx) {
|
|
|
5303
5336
|
output += chalk9__default.default.red(`
|
|
5304
5337
|
\u9000\u51FA\u7801: ${code}`);
|
|
5305
5338
|
}
|
|
5306
|
-
|
|
5339
|
+
resolve5({ output: output || chalk9__default.default.gray("(\u65E0\u8F93\u51FA)") });
|
|
5307
5340
|
});
|
|
5308
5341
|
setTimeout(() => {
|
|
5309
5342
|
shell.kill();
|
|
5310
|
-
|
|
5343
|
+
resolve5({
|
|
5311
5344
|
output: chalk9__default.default.yellow("\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0C\u5DF2\u7EC8\u6B62")
|
|
5312
5345
|
});
|
|
5313
5346
|
}, 6e4);
|
|
@@ -5533,7 +5566,7 @@ var ContextManager = class {
|
|
|
5533
5566
|
}
|
|
5534
5567
|
async initialize(projectPath) {
|
|
5535
5568
|
this.projectPath = projectPath;
|
|
5536
|
-
this.persistPath =
|
|
5569
|
+
this.persistPath = path6__namespace.join(projectPath, ".sf-cli", "cache", "context", "context.json");
|
|
5537
5570
|
await this.loadPersistedContext();
|
|
5538
5571
|
}
|
|
5539
5572
|
/**
|
|
@@ -5774,15 +5807,15 @@ ${summary}`,
|
|
|
5774
5807
|
*/
|
|
5775
5808
|
async persist() {
|
|
5776
5809
|
if (!this.persistPath) return;
|
|
5777
|
-
const dir =
|
|
5778
|
-
await
|
|
5810
|
+
const dir = path6__namespace.dirname(this.persistPath);
|
|
5811
|
+
await fs6__namespace.mkdir(dir, { recursive: true });
|
|
5779
5812
|
const data = {
|
|
5780
5813
|
messages: this.state.messages,
|
|
5781
5814
|
totalTokens: this.state.totalTokens,
|
|
5782
5815
|
limit: this.state.limit,
|
|
5783
5816
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5784
5817
|
};
|
|
5785
|
-
await
|
|
5818
|
+
await fs6__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
|
|
5786
5819
|
}
|
|
5787
5820
|
/**
|
|
5788
5821
|
* 加载持久化的上下文
|
|
@@ -5790,7 +5823,7 @@ ${summary}`,
|
|
|
5790
5823
|
async loadPersistedContext() {
|
|
5791
5824
|
if (!this.persistPath) return;
|
|
5792
5825
|
try {
|
|
5793
|
-
const content = await
|
|
5826
|
+
const content = await fs6__namespace.readFile(this.persistPath, "utf-8");
|
|
5794
5827
|
const data = JSON.parse(content);
|
|
5795
5828
|
this.state.messages = data.messages || [];
|
|
5796
5829
|
this.state.totalTokens = data.totalTokens || 0;
|
|
@@ -5960,17 +5993,17 @@ var Completer = class {
|
|
|
5960
5993
|
prefix = filePath;
|
|
5961
5994
|
} else {
|
|
5962
5995
|
const dir = filePath.slice(0, lastSlash);
|
|
5963
|
-
dirPath =
|
|
5996
|
+
dirPath = path6__namespace.resolve(this.workingDirectory, dir);
|
|
5964
5997
|
prefix = filePath.slice(lastSlash + 1);
|
|
5965
5998
|
}
|
|
5966
5999
|
try {
|
|
5967
|
-
const entries = await
|
|
6000
|
+
const entries = await fs6__namespace.readdir(dirPath, { withFileTypes: true });
|
|
5968
6001
|
const matches = [];
|
|
5969
6002
|
for (const entry of entries) {
|
|
5970
6003
|
if (entry.name.startsWith(prefix)) {
|
|
5971
6004
|
const isDir = entry.isDirectory();
|
|
5972
6005
|
matches.push({
|
|
5973
|
-
text: "@" +
|
|
6006
|
+
text: "@" + path6__namespace.relative(this.workingDirectory, path6__namespace.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
|
|
5974
6007
|
displayText: entry.name + (isDir ? "/" : ""),
|
|
5975
6008
|
description: isDir ? "\u76EE\u5F55" : "\u6587\u4EF6",
|
|
5976
6009
|
type: isDir ? "directory" : "file"
|
|
@@ -6042,10 +6075,10 @@ var Completer = class {
|
|
|
6042
6075
|
|
|
6043
6076
|
// src/cli/repl.ts
|
|
6044
6077
|
async function startInteractiveMode(options) {
|
|
6045
|
-
const historyFile =
|
|
6078
|
+
const historyFile = path6__namespace.join(options.workingDirectory, ".sf-cli", "history.json");
|
|
6046
6079
|
let history = [];
|
|
6047
6080
|
try {
|
|
6048
|
-
const historyData = await
|
|
6081
|
+
const historyData = await fs6__namespace.readFile(historyFile, "utf-8");
|
|
6049
6082
|
history = JSON.parse(historyData);
|
|
6050
6083
|
} catch {
|
|
6051
6084
|
}
|
|
@@ -6079,11 +6112,11 @@ async function startInteractiveMode(options) {
|
|
|
6079
6112
|
const workflowEngine = new WorkflowEngine();
|
|
6080
6113
|
const normsManager = new NormsManager({
|
|
6081
6114
|
projectPath: options.workingDirectory,
|
|
6082
|
-
normsDir:
|
|
6115
|
+
normsDir: path6__namespace.join(options.workingDirectory, ".sf-cli", "norms")
|
|
6083
6116
|
});
|
|
6084
6117
|
await configManager.load(options.workingDirectory);
|
|
6085
6118
|
await contextManager.initialize(options.workingDirectory);
|
|
6086
|
-
const statsDir =
|
|
6119
|
+
const statsDir = path6__namespace.join(options.workingDirectory, ".sf-cli");
|
|
6087
6120
|
await modelService.initialize(statsDir);
|
|
6088
6121
|
await workflowEngine.initialize(options.workingDirectory);
|
|
6089
6122
|
await normsManager.initialize();
|
|
@@ -6114,8 +6147,8 @@ async function startInteractiveMode(options) {
|
|
|
6114
6147
|
}
|
|
6115
6148
|
const saveHistory = async () => {
|
|
6116
6149
|
try {
|
|
6117
|
-
await
|
|
6118
|
-
await
|
|
6150
|
+
await fs6__namespace.mkdir(path6__namespace.dirname(historyFile), { recursive: true });
|
|
6151
|
+
await fs6__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
|
|
6119
6152
|
} catch {
|
|
6120
6153
|
}
|
|
6121
6154
|
};
|
|
@@ -6187,9 +6220,11 @@ async function startInteractiveMode(options) {
|
|
|
6187
6220
|
rl.prompt();
|
|
6188
6221
|
}
|
|
6189
6222
|
}
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
var
|
|
6223
|
+
|
|
6224
|
+
// src/cli/index.ts
|
|
6225
|
+
var packageJsonPath3 = path6__namespace.resolve(__dirname, "../package.json");
|
|
6226
|
+
var packageJson3 = JSON.parse(fsSync__namespace.readFileSync(packageJsonPath3, "utf-8"));
|
|
6227
|
+
var VERSION3 = packageJson3.version;
|
|
6193
6228
|
var NAME = "sf-cli";
|
|
6194
6229
|
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
6230
|
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) => {
|