@nick848/sf-cli 1.0.0 → 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/README.md +61 -0
- package/dist/cli/index.js +398 -166
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +254 -245
- package/dist/index.d.ts +254 -245
- package/dist/index.js +215 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +287 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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');
|
|
@@ -37,10 +37,10 @@ function _interopNamespace(e) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
var chalk9__default = /*#__PURE__*/_interopDefault(chalk9);
|
|
40
|
-
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
41
|
-
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
42
|
-
var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
|
|
43
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);
|
|
44
44
|
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
45
45
|
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
46
46
|
|
|
@@ -125,8 +125,8 @@ var CommandParser = class {
|
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
parseAtPath(input) {
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
128
|
+
const path15 = input.slice(1).trim();
|
|
129
|
+
if (!path15) {
|
|
130
130
|
return { success: false, error: "\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84" };
|
|
131
131
|
}
|
|
132
132
|
return {
|
|
@@ -134,7 +134,7 @@ var CommandParser = class {
|
|
|
134
134
|
command: {
|
|
135
135
|
type: "at" /* AT */,
|
|
136
136
|
raw: input,
|
|
137
|
-
path:
|
|
137
|
+
path: path15
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
140
|
}
|
|
@@ -206,11 +206,11 @@ var NormsManager = class {
|
|
|
206
206
|
const files = await this.collectProjectFiles(projectPath);
|
|
207
207
|
for (const filePath of files.slice(0, MAX_FILES_TO_SCAN)) {
|
|
208
208
|
try {
|
|
209
|
-
const stats = await
|
|
209
|
+
const stats = await fs6__namespace.stat(filePath);
|
|
210
210
|
if (stats.size > MAX_FILE_SIZE) {
|
|
211
211
|
continue;
|
|
212
212
|
}
|
|
213
|
-
const content = await
|
|
213
|
+
const content = await fs6__namespace.readFile(filePath, "utf-8");
|
|
214
214
|
const patterns = await this.learnFromFile(filePath, content);
|
|
215
215
|
result.patternsFound += patterns.length;
|
|
216
216
|
result.filesScanned++;
|
|
@@ -233,7 +233,7 @@ var NormsManager = class {
|
|
|
233
233
|
* 从单个文件学习规范
|
|
234
234
|
*/
|
|
235
235
|
async learnFromFile(filePath, content) {
|
|
236
|
-
const ext =
|
|
236
|
+
const ext = path6__namespace.extname(filePath);
|
|
237
237
|
const patterns = this.extractPatterns(filePath, content, ext);
|
|
238
238
|
for (const pattern of patterns) {
|
|
239
239
|
await this.recordOccurrence({
|
|
@@ -836,16 +836,16 @@ ${response}`;
|
|
|
836
836
|
const files = [];
|
|
837
837
|
async function scan(dir) {
|
|
838
838
|
try {
|
|
839
|
-
const entries = await
|
|
839
|
+
const entries = await fs6__namespace.readdir(dir, { withFileTypes: true });
|
|
840
840
|
for (const entry of entries) {
|
|
841
841
|
if (entry.isDirectory()) {
|
|
842
842
|
if (!IGNORED_DIRS.includes(entry.name)) {
|
|
843
|
-
await scan(
|
|
843
|
+
await scan(path6__namespace.join(dir, entry.name));
|
|
844
844
|
}
|
|
845
845
|
} else if (entry.isFile()) {
|
|
846
|
-
const ext =
|
|
846
|
+
const ext = path6__namespace.extname(entry.name);
|
|
847
847
|
if (SCAN_EXTENSIONS.includes(ext)) {
|
|
848
|
-
files.push(
|
|
848
|
+
files.push(path6__namespace.join(dir, entry.name));
|
|
849
849
|
}
|
|
850
850
|
}
|
|
851
851
|
}
|
|
@@ -879,16 +879,16 @@ ${response}`;
|
|
|
879
879
|
* 确保规范目录存在
|
|
880
880
|
*/
|
|
881
881
|
async ensureNormsDir() {
|
|
882
|
-
await
|
|
883
|
-
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 });
|
|
884
884
|
}
|
|
885
885
|
/**
|
|
886
886
|
* 加载已有规范
|
|
887
887
|
*/
|
|
888
888
|
async loadStandards() {
|
|
889
|
-
const standardsPath =
|
|
889
|
+
const standardsPath = path6__namespace.join(this.config.normsDir, "patterns.json");
|
|
890
890
|
try {
|
|
891
|
-
const content = await
|
|
891
|
+
const content = await fs6__namespace.readFile(standardsPath, "utf-8");
|
|
892
892
|
const data = JSON.parse(content);
|
|
893
893
|
for (const standard of data) {
|
|
894
894
|
this.standards.set(standard.id, {
|
|
@@ -904,9 +904,9 @@ ${response}`;
|
|
|
904
904
|
* 加载权重数据
|
|
905
905
|
*/
|
|
906
906
|
async loadWeights() {
|
|
907
|
-
const weightsPath =
|
|
907
|
+
const weightsPath = path6__namespace.join(this.config.normsDir, "weights.json");
|
|
908
908
|
try {
|
|
909
|
-
const content = await
|
|
909
|
+
const content = await fs6__namespace.readFile(weightsPath, "utf-8");
|
|
910
910
|
const data = JSON.parse(content);
|
|
911
911
|
for (const weight of data) {
|
|
912
912
|
this.weights.set(weight.standardId, {
|
|
@@ -921,8 +921,8 @@ ${response}`;
|
|
|
921
921
|
* 保存规范
|
|
922
922
|
*/
|
|
923
923
|
async saveStandards() {
|
|
924
|
-
const standardsPath =
|
|
925
|
-
await
|
|
924
|
+
const standardsPath = path6__namespace.join(this.config.normsDir, "patterns.json");
|
|
925
|
+
await fs6__namespace.writeFile(
|
|
926
926
|
standardsPath,
|
|
927
927
|
JSON.stringify(Array.from(this.standards.values()), null, 2),
|
|
928
928
|
"utf-8"
|
|
@@ -932,8 +932,8 @@ ${response}`;
|
|
|
932
932
|
* 保存权重
|
|
933
933
|
*/
|
|
934
934
|
async saveWeights() {
|
|
935
|
-
const weightsPath =
|
|
936
|
-
await
|
|
935
|
+
const weightsPath = path6__namespace.join(this.config.normsDir, "weights.json");
|
|
936
|
+
await fs6__namespace.writeFile(
|
|
937
937
|
weightsPath,
|
|
938
938
|
JSON.stringify(Array.from(this.weights.values()), null, 2),
|
|
939
939
|
"utf-8"
|
|
@@ -960,8 +960,8 @@ ${response}`;
|
|
|
960
960
|
* 保存周报
|
|
961
961
|
*/
|
|
962
962
|
async saveWeeklyReport(weekId, report) {
|
|
963
|
-
const reportPath =
|
|
964
|
-
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");
|
|
965
965
|
}
|
|
966
966
|
/**
|
|
967
967
|
* 更新 devstanded.md
|
|
@@ -969,8 +969,8 @@ ${response}`;
|
|
|
969
969
|
async updateDevStandedMd() {
|
|
970
970
|
const standards = this.getEffectiveStandards();
|
|
971
971
|
const content = this.generateDevStandedMd(standards);
|
|
972
|
-
const mdPath =
|
|
973
|
-
await
|
|
972
|
+
const mdPath = path6__namespace.join(this.config.normsDir, "devstanded.md");
|
|
973
|
+
await fs6__namespace.writeFile(mdPath, content, "utf-8");
|
|
974
974
|
}
|
|
975
975
|
/**
|
|
976
976
|
* 生成 devstanded.md 内容
|
|
@@ -1109,7 +1109,7 @@ async function handleInit(args, ctx) {
|
|
|
1109
1109
|
async function initProject(options = {}, workingDir) {
|
|
1110
1110
|
const cwd = workingDir || process.cwd();
|
|
1111
1111
|
try {
|
|
1112
|
-
const stats = await
|
|
1112
|
+
const stats = await fs6__namespace.stat(cwd);
|
|
1113
1113
|
if (!stats.isDirectory()) {
|
|
1114
1114
|
return {
|
|
1115
1115
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
@@ -1120,9 +1120,9 @@ async function initProject(options = {}, workingDir) {
|
|
|
1120
1120
|
output: chalk9__default.default.red(`\u9519\u8BEF: \u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6743\u9650\u8BBF\u95EE ${cwd}`)
|
|
1121
1121
|
};
|
|
1122
1122
|
}
|
|
1123
|
-
const sfCliDir =
|
|
1124
|
-
const openspecDir =
|
|
1125
|
-
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");
|
|
1126
1126
|
try {
|
|
1127
1127
|
const agentsExists = await fileExists(agentsMdPath);
|
|
1128
1128
|
if (agentsExists && !options.force) {
|
|
@@ -1141,7 +1141,7 @@ async function initProject(options = {}, workingDir) {
|
|
|
1141
1141
|
await normsManager.initialize();
|
|
1142
1142
|
const scanResult = await normsManager.scanProject(cwd);
|
|
1143
1143
|
const agentsContent = generateAgentsMd(projectInfo, scanResult);
|
|
1144
|
-
await
|
|
1144
|
+
await fs6__namespace.writeFile(agentsMdPath, agentsContent, "utf-8");
|
|
1145
1145
|
await generateOpenSpecConfig(openspecDir, projectInfo);
|
|
1146
1146
|
return {
|
|
1147
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}
|
|
@@ -1182,7 +1182,7 @@ async function createSfCliDirectory(basePath) {
|
|
|
1182
1182
|
"logs"
|
|
1183
1183
|
];
|
|
1184
1184
|
for (const dir of dirs) {
|
|
1185
|
-
await
|
|
1185
|
+
await fs6__namespace.mkdir(path6__namespace.join(basePath, dir), { recursive: true });
|
|
1186
1186
|
}
|
|
1187
1187
|
const config = {
|
|
1188
1188
|
version: "1.0.0",
|
|
@@ -1190,37 +1190,37 @@ async function createSfCliDirectory(basePath) {
|
|
|
1190
1190
|
yolo: false,
|
|
1191
1191
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1192
1192
|
};
|
|
1193
|
-
await
|
|
1194
|
-
|
|
1193
|
+
await fs6__namespace.writeFile(
|
|
1194
|
+
path6__namespace.join(basePath, "config.json"),
|
|
1195
1195
|
JSON.stringify(config, null, 2),
|
|
1196
1196
|
"utf-8"
|
|
1197
1197
|
);
|
|
1198
|
-
await
|
|
1199
|
-
|
|
1198
|
+
await fs6__namespace.writeFile(
|
|
1199
|
+
path6__namespace.join(basePath, "agents", "registry.json"),
|
|
1200
1200
|
JSON.stringify({ version: "1.0.0", agents: {} }, null, 2),
|
|
1201
1201
|
"utf-8"
|
|
1202
1202
|
);
|
|
1203
|
-
await
|
|
1204
|
-
|
|
1203
|
+
await fs6__namespace.writeFile(
|
|
1204
|
+
path6__namespace.join(basePath, "skills", "registry.json"),
|
|
1205
1205
|
JSON.stringify({ version: "1.0.0", skills: {} }, null, 2),
|
|
1206
1206
|
"utf-8"
|
|
1207
1207
|
);
|
|
1208
|
-
await
|
|
1209
|
-
|
|
1208
|
+
await fs6__namespace.writeFile(
|
|
1209
|
+
path6__namespace.join(basePath, "health", "health.md"),
|
|
1210
1210
|
generateHealthTemplate(),
|
|
1211
1211
|
"utf-8"
|
|
1212
1212
|
);
|
|
1213
1213
|
}
|
|
1214
1214
|
async function createOpenSpecDirectory(basePath) {
|
|
1215
|
-
const changesDir =
|
|
1216
|
-
const archiveDir =
|
|
1217
|
-
const specDir =
|
|
1218
|
-
await
|
|
1219
|
-
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 });
|
|
1220
1220
|
}
|
|
1221
1221
|
async function analyzeProject(cwd) {
|
|
1222
1222
|
const result = {
|
|
1223
|
-
name:
|
|
1223
|
+
name: path6__namespace.basename(cwd),
|
|
1224
1224
|
type: "unknown",
|
|
1225
1225
|
framework: null,
|
|
1226
1226
|
techStack: [],
|
|
@@ -1239,9 +1239,9 @@ async function analyzeProject(cwd) {
|
|
|
1239
1239
|
hasEslint: false,
|
|
1240
1240
|
hasPrettier: false
|
|
1241
1241
|
};
|
|
1242
|
-
const pkgPath =
|
|
1242
|
+
const pkgPath = path6__namespace.join(cwd, "package.json");
|
|
1243
1243
|
try {
|
|
1244
|
-
const pkgContent = await
|
|
1244
|
+
const pkgContent = await fs6__namespace.readFile(pkgPath, "utf-8");
|
|
1245
1245
|
const pkg = JSON.parse(pkgContent);
|
|
1246
1246
|
result.name = pkg.name || result.name;
|
|
1247
1247
|
result.dependencies = pkg.dependencies || {};
|
|
@@ -1324,7 +1324,7 @@ async function analyzeDirectoryStructure(cwd) {
|
|
|
1324
1324
|
others: []
|
|
1325
1325
|
};
|
|
1326
1326
|
try {
|
|
1327
|
-
const entries = await
|
|
1327
|
+
const entries = await fs6__namespace.readdir(cwd, { withFileTypes: true });
|
|
1328
1328
|
for (const entry of entries) {
|
|
1329
1329
|
if (!entry.isDirectory()) continue;
|
|
1330
1330
|
const name = entry.name;
|
|
@@ -1360,7 +1360,7 @@ async function findEntryPoints(cwd) {
|
|
|
1360
1360
|
"index.js"
|
|
1361
1361
|
];
|
|
1362
1362
|
for (const entry of possibleEntries) {
|
|
1363
|
-
const fullPath =
|
|
1363
|
+
const fullPath = path6__namespace.join(cwd, entry);
|
|
1364
1364
|
if (await fileExists(fullPath)) {
|
|
1365
1365
|
entryPoints.push(entry);
|
|
1366
1366
|
}
|
|
@@ -1368,15 +1368,15 @@ async function findEntryPoints(cwd) {
|
|
|
1368
1368
|
return entryPoints;
|
|
1369
1369
|
}
|
|
1370
1370
|
async function saveProjectAnalysis(sfCliDir, analysis) {
|
|
1371
|
-
const analysisPath =
|
|
1372
|
-
await
|
|
1371
|
+
const analysisPath = path6__namespace.join(sfCliDir, "cache", "analysis", "project-analysis.json");
|
|
1372
|
+
await fs6__namespace.writeFile(
|
|
1373
1373
|
analysisPath,
|
|
1374
1374
|
JSON.stringify(analysis, null, 2),
|
|
1375
1375
|
"utf-8"
|
|
1376
1376
|
);
|
|
1377
1377
|
}
|
|
1378
1378
|
async function generateOpenSpecConfig(openspecDir, analysis) {
|
|
1379
|
-
const configPath =
|
|
1379
|
+
const configPath = path6__namespace.join(openspecDir, "config.yaml");
|
|
1380
1380
|
const content = `# OpenSpec \u9879\u76EE\u914D\u7F6E
|
|
1381
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
|
|
1382
1382
|
|
|
@@ -1410,7 +1410,7 @@ architecture:
|
|
|
1410
1410
|
# \u5F00\u53D1\u89C4\u8303 (\u4ECE\u4EE3\u7801\u4E2D\u5B66\u4E60)
|
|
1411
1411
|
standards: []
|
|
1412
1412
|
`;
|
|
1413
|
-
await
|
|
1413
|
+
await fs6__namespace.writeFile(configPath, content, "utf-8");
|
|
1414
1414
|
}
|
|
1415
1415
|
function generateAgentsMd(info, scanResult) {
|
|
1416
1416
|
const techStackList = info.techStack.length > 0 ? info.techStack.map((t) => `| ${t} | \u2713 |`).join("\n") : "| \u5F85\u8BC6\u522B | - |";
|
|
@@ -1532,7 +1532,7 @@ function generateHealthTemplate() {
|
|
|
1532
1532
|
}
|
|
1533
1533
|
async function fileExists(filePath) {
|
|
1534
1534
|
try {
|
|
1535
|
-
await
|
|
1535
|
+
await fs6__namespace.access(filePath);
|
|
1536
1536
|
return true;
|
|
1537
1537
|
} catch {
|
|
1538
1538
|
return false;
|
|
@@ -1703,7 +1703,7 @@ var IV_LENGTH = 16;
|
|
|
1703
1703
|
var KEY_DIR = ".sf-cli";
|
|
1704
1704
|
var KEY_FILE = ".key";
|
|
1705
1705
|
function getOrCreateEncryptionKey() {
|
|
1706
|
-
const keyPath =
|
|
1706
|
+
const keyPath = path6__namespace.join(os__namespace.homedir(), KEY_DIR, KEY_FILE);
|
|
1707
1707
|
try {
|
|
1708
1708
|
if (fsSync__namespace.existsSync(keyPath)) {
|
|
1709
1709
|
const keyBase64 = fsSync__namespace.readFileSync(keyPath, "utf-8").trim();
|
|
@@ -1713,7 +1713,7 @@ function getOrCreateEncryptionKey() {
|
|
|
1713
1713
|
}
|
|
1714
1714
|
const key = crypto__namespace.randomBytes(32);
|
|
1715
1715
|
try {
|
|
1716
|
-
const keyDir =
|
|
1716
|
+
const keyDir = path6__namespace.dirname(keyPath);
|
|
1717
1717
|
if (!fsSync__namespace.existsSync(keyDir)) {
|
|
1718
1718
|
fsSync__namespace.mkdirSync(keyDir, { recursive: true, mode: 448 });
|
|
1719
1719
|
}
|
|
@@ -1744,9 +1744,9 @@ var ConfigManager = class {
|
|
|
1744
1744
|
}
|
|
1745
1745
|
async load(projectPath) {
|
|
1746
1746
|
this.projectPath = projectPath;
|
|
1747
|
-
this.configPath =
|
|
1747
|
+
this.configPath = path6__namespace.join(projectPath, ".sf-cli", "config.json");
|
|
1748
1748
|
try {
|
|
1749
|
-
const content = await
|
|
1749
|
+
const content = await fs6__namespace.readFile(this.configPath, "utf-8");
|
|
1750
1750
|
const loaded = JSON.parse(content);
|
|
1751
1751
|
if (loaded.apiKey && loaded.apiKeyEncrypted) {
|
|
1752
1752
|
loaded.apiKey = this.decrypt(loaded.apiKey);
|
|
@@ -1765,8 +1765,8 @@ var ConfigManager = class {
|
|
|
1765
1765
|
configToSave.apiKey = encrypted;
|
|
1766
1766
|
configToSave.apiKeyEncrypted = true;
|
|
1767
1767
|
}
|
|
1768
|
-
await
|
|
1769
|
-
await
|
|
1768
|
+
await fs6__namespace.mkdir(path6__namespace.dirname(this.configPath), { recursive: true });
|
|
1769
|
+
await fs6__namespace.writeFile(
|
|
1770
1770
|
this.configPath,
|
|
1771
1771
|
JSON.stringify(configToSave, null, 2),
|
|
1772
1772
|
"utf-8"
|
|
@@ -2024,7 +2024,7 @@ var BaseAdapter = class {
|
|
|
2024
2024
|
* 延迟工具函数
|
|
2025
2025
|
*/
|
|
2026
2026
|
delay(ms) {
|
|
2027
|
-
return new Promise((
|
|
2027
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2028
2028
|
}
|
|
2029
2029
|
};
|
|
2030
2030
|
|
|
@@ -2645,7 +2645,7 @@ var ModelService = class {
|
|
|
2645
2645
|
* 初始化服务
|
|
2646
2646
|
*/
|
|
2647
2647
|
async initialize(statsDir) {
|
|
2648
|
-
this.statsPath =
|
|
2648
|
+
this.statsPath = path6__namespace.join(statsDir, "tokens");
|
|
2649
2649
|
await this.loadStats();
|
|
2650
2650
|
const model = this.configManager.get("model");
|
|
2651
2651
|
const apiKey = this.configManager.get("apiKey");
|
|
@@ -2818,11 +2818,11 @@ var ModelService = class {
|
|
|
2818
2818
|
async loadStats() {
|
|
2819
2819
|
if (!this.statsPath) return;
|
|
2820
2820
|
try {
|
|
2821
|
-
const dailyPath =
|
|
2822
|
-
const totalPath =
|
|
2821
|
+
const dailyPath = path6__namespace.join(this.statsPath, "daily.json");
|
|
2822
|
+
const totalPath = path6__namespace.join(this.statsPath, "total.json");
|
|
2823
2823
|
const [daily, total] = await Promise.all([
|
|
2824
|
-
|
|
2825
|
-
|
|
2824
|
+
fs6__namespace.readFile(dailyPath, "utf-8").catch(() => "{}"),
|
|
2825
|
+
fs6__namespace.readFile(totalPath, "utf-8").catch(() => '{"totalInput":0,"totalOutput":0}')
|
|
2826
2826
|
]);
|
|
2827
2827
|
const dailyData = JSON.parse(daily);
|
|
2828
2828
|
const totalData = JSON.parse(total);
|
|
@@ -2835,12 +2835,12 @@ var ModelService = class {
|
|
|
2835
2835
|
async saveStats() {
|
|
2836
2836
|
if (!this.statsPath) return;
|
|
2837
2837
|
try {
|
|
2838
|
-
await
|
|
2839
|
-
const dailyPath =
|
|
2840
|
-
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");
|
|
2841
2841
|
await Promise.all([
|
|
2842
|
-
|
|
2843
|
-
|
|
2842
|
+
fs6__namespace.writeFile(dailyPath, JSON.stringify(this.stats.byDate, null, 2)),
|
|
2843
|
+
fs6__namespace.writeFile(totalPath, JSON.stringify({
|
|
2844
2844
|
totalInput: this.stats.totalInput,
|
|
2845
2845
|
totalOutput: this.stats.totalOutput
|
|
2846
2846
|
}))
|
|
@@ -3081,8 +3081,10 @@ function createSpinner(message) {
|
|
|
3081
3081
|
stop: () => process.stdout.write(" ".repeat(message.length + 10) + "\r")
|
|
3082
3082
|
};
|
|
3083
3083
|
}
|
|
3084
|
-
var
|
|
3085
|
-
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;
|
|
3086
3088
|
async function handleUpdate(args, ctx) {
|
|
3087
3089
|
const options = {
|
|
3088
3090
|
check: args.includes("--check") || args.includes("-c"),
|
|
@@ -3109,6 +3111,9 @@ async function checkForUpdates() {
|
|
|
3109
3111
|
const latestVersion = await getLatestVersion();
|
|
3110
3112
|
if (!latestVersion) {
|
|
3111
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"));
|
|
3112
3117
|
return { output: lines.join("\n") };
|
|
3113
3118
|
}
|
|
3114
3119
|
lines.push(chalk9__default.default.gray(` \u5F53\u524D\u7248\u672C: v${CURRENT_VERSION}`));
|
|
@@ -3127,43 +3132,70 @@ async function checkForUpdates() {
|
|
|
3127
3132
|
async function performUpdate(targetVersion) {
|
|
3128
3133
|
const lines = [];
|
|
3129
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}`));
|
|
3130
3137
|
try {
|
|
3131
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
|
+
}
|
|
3132
3148
|
if (latestVersion === CURRENT_VERSION && !targetVersion) {
|
|
3133
|
-
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"));
|
|
3134
3150
|
return { output: lines.join("\n") };
|
|
3135
3151
|
}
|
|
3136
3152
|
const packageSpec = targetVersion ? `${PACKAGE_NAME}@${targetVersion}` : `${PACKAGE_NAME}@latest`;
|
|
3137
3153
|
lines.push(chalk9__default.default.gray(` \u5B89\u88C5: ${packageSpec}`));
|
|
3138
|
-
await new Promise((
|
|
3154
|
+
const installResult = await new Promise((resolve5) => {
|
|
3139
3155
|
const proc = child_process.spawn("npm", ["install", "-g", packageSpec], {
|
|
3140
3156
|
stdio: "pipe",
|
|
3141
3157
|
shell: true
|
|
3142
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
|
+
});
|
|
3143
3166
|
proc.on("close", (code) => {
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
}
|
|
3167
|
+
resolve5({
|
|
3168
|
+
success: code === 0,
|
|
3169
|
+
output
|
|
3170
|
+
});
|
|
3149
3171
|
});
|
|
3150
3172
|
proc.on("error", (err) => {
|
|
3151
|
-
|
|
3173
|
+
resolve5({
|
|
3174
|
+
success: false,
|
|
3175
|
+
output: err.message
|
|
3176
|
+
});
|
|
3152
3177
|
});
|
|
3153
3178
|
});
|
|
3154
|
-
|
|
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!"));
|
|
3155
3187
|
lines.push(chalk9__default.default.gray(` \u65B0\u7248\u672C: v${targetVersion || latestVersion}`));
|
|
3156
3188
|
lines.push(chalk9__default.default.gray("\n\u8BF7\u91CD\u542F CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"));
|
|
3157
3189
|
} catch (error) {
|
|
3158
3190
|
lines.push(chalk9__default.default.red("\u66F4\u65B0\u5931\u8D25: " + error.message));
|
|
3159
3191
|
lines.push(chalk9__default.default.gray("\n\u60A8\u53EF\u4EE5\u5C1D\u8BD5\u624B\u52A8\u66F4\u65B0:"));
|
|
3160
|
-
lines.push(chalk9__default.default.
|
|
3192
|
+
lines.push(chalk9__default.default.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
3161
3193
|
}
|
|
3162
3194
|
return { output: lines.join("\n") };
|
|
3163
3195
|
}
|
|
3164
3196
|
async function getLatestVersion() {
|
|
3165
3197
|
try {
|
|
3166
|
-
const result = await new Promise((
|
|
3198
|
+
const result = await new Promise((resolve5, reject) => {
|
|
3167
3199
|
const proc = child_process.spawn("npm", ["view", PACKAGE_NAME, "version"], {
|
|
3168
3200
|
stdio: "pipe",
|
|
3169
3201
|
shell: true
|
|
@@ -3173,13 +3205,17 @@ async function getLatestVersion() {
|
|
|
3173
3205
|
output += data.toString();
|
|
3174
3206
|
});
|
|
3175
3207
|
proc.on("close", (code) => {
|
|
3176
|
-
if (code === 0) {
|
|
3177
|
-
|
|
3208
|
+
if (code === 0 && output.trim()) {
|
|
3209
|
+
resolve5(output.trim());
|
|
3178
3210
|
} else {
|
|
3179
3211
|
reject(new Error("Failed to get version"));
|
|
3180
3212
|
}
|
|
3181
3213
|
});
|
|
3182
3214
|
proc.on("error", reject);
|
|
3215
|
+
setTimeout(() => {
|
|
3216
|
+
proc.kill();
|
|
3217
|
+
reject(new Error("Timeout"));
|
|
3218
|
+
}, 1e4);
|
|
3183
3219
|
});
|
|
3184
3220
|
return result || null;
|
|
3185
3221
|
} catch {
|
|
@@ -3463,7 +3499,7 @@ var WorkflowEngine = class {
|
|
|
3463
3499
|
*/
|
|
3464
3500
|
async initialize(projectPath) {
|
|
3465
3501
|
this.projectPath = projectPath;
|
|
3466
|
-
this.openspecPath =
|
|
3502
|
+
this.openspecPath = path6__namespace.join(projectPath, "openspec");
|
|
3467
3503
|
await this.ensureDirectories();
|
|
3468
3504
|
await this.loadProjectContext();
|
|
3469
3505
|
await this.restoreState();
|
|
@@ -3473,21 +3509,21 @@ var WorkflowEngine = class {
|
|
|
3473
3509
|
* 加载项目上下文(AGENTS.md 和 config.yaml)
|
|
3474
3510
|
*/
|
|
3475
3511
|
async loadProjectContext() {
|
|
3476
|
-
const agentsMdPath =
|
|
3512
|
+
const agentsMdPath = path6__namespace.join(this.projectPath, "AGENTS.md");
|
|
3477
3513
|
try {
|
|
3478
|
-
this.projectContext = await
|
|
3514
|
+
this.projectContext = await fs6__namespace.readFile(agentsMdPath, "utf-8");
|
|
3479
3515
|
} catch {
|
|
3480
3516
|
this.projectContext = "";
|
|
3481
3517
|
}
|
|
3482
|
-
const configPath =
|
|
3518
|
+
const configPath = path6__namespace.join(this.openspecPath, "config.yaml");
|
|
3483
3519
|
try {
|
|
3484
|
-
this.projectConfig = await
|
|
3520
|
+
this.projectConfig = await fs6__namespace.readFile(configPath, "utf-8");
|
|
3485
3521
|
} catch {
|
|
3486
3522
|
this.projectConfig = "";
|
|
3487
3523
|
}
|
|
3488
|
-
const devstandedPath =
|
|
3524
|
+
const devstandedPath = path6__namespace.join(this.projectPath, ".sf-cli", "norms", "devstanded.md");
|
|
3489
3525
|
try {
|
|
3490
|
-
this.devStandards = await
|
|
3526
|
+
this.devStandards = await fs6__namespace.readFile(devstandedPath, "utf-8");
|
|
3491
3527
|
} catch {
|
|
3492
3528
|
this.devStandards = "";
|
|
3493
3529
|
}
|
|
@@ -3773,12 +3809,12 @@ var WorkflowEngine = class {
|
|
|
3773
3809
|
await this.createSpecDocument(summary);
|
|
3774
3810
|
await this.updateChangeRecord("archived");
|
|
3775
3811
|
await this.saveState();
|
|
3776
|
-
const changesDir =
|
|
3777
|
-
const archiveDir =
|
|
3778
|
-
const changeFile =
|
|
3779
|
-
const archiveFile =
|
|
3780
|
-
await
|
|
3781
|
-
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(() => {
|
|
3782
3818
|
});
|
|
3783
3819
|
this.state = null;
|
|
3784
3820
|
this.snapshots.clear();
|
|
@@ -3800,16 +3836,16 @@ var WorkflowEngine = class {
|
|
|
3800
3836
|
}
|
|
3801
3837
|
// ==================== 私有方法 ====================
|
|
3802
3838
|
async ensureDirectories() {
|
|
3803
|
-
const changesDir =
|
|
3804
|
-
const archiveDir =
|
|
3805
|
-
const specDir =
|
|
3806
|
-
await
|
|
3807
|
-
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 });
|
|
3808
3844
|
}
|
|
3809
3845
|
async restoreState() {
|
|
3810
|
-
const statePath =
|
|
3846
|
+
const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
3811
3847
|
try {
|
|
3812
|
-
const content = await
|
|
3848
|
+
const content = await fs6__namespace.readFile(statePath, "utf-8");
|
|
3813
3849
|
this.state = JSON.parse(content, (key, value) => {
|
|
3814
3850
|
if (key.endsWith("At") && typeof value === "string") {
|
|
3815
3851
|
return new Date(value);
|
|
@@ -3820,20 +3856,20 @@ var WorkflowEngine = class {
|
|
|
3820
3856
|
const err = e;
|
|
3821
3857
|
if (err.code !== "ENOENT") {
|
|
3822
3858
|
console.warn("\u8B66\u544A: \u5DE5\u4F5C\u6D41\u72B6\u6001\u6587\u4EF6\u5DF2\u635F\u574F\uFF0C\u5C06\u91CD\u65B0\u5F00\u59CB");
|
|
3823
|
-
await
|
|
3859
|
+
await fs6__namespace.unlink(statePath).catch(() => {
|
|
3824
3860
|
});
|
|
3825
3861
|
}
|
|
3826
3862
|
this.state = null;
|
|
3827
3863
|
}
|
|
3828
3864
|
}
|
|
3829
3865
|
async saveState() {
|
|
3830
|
-
const statePath =
|
|
3831
|
-
await
|
|
3866
|
+
const statePath = path6__namespace.join(this.openspecPath, ".workflow-state.json");
|
|
3867
|
+
await fs6__namespace.writeFile(statePath, JSON.stringify(this.state, null, 2));
|
|
3832
3868
|
}
|
|
3833
3869
|
async restoreSnapshots() {
|
|
3834
|
-
const snapshotsPath =
|
|
3870
|
+
const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
3835
3871
|
try {
|
|
3836
|
-
const content = await
|
|
3872
|
+
const content = await fs6__namespace.readFile(snapshotsPath, "utf-8");
|
|
3837
3873
|
const data = JSON.parse(content, (key, value) => {
|
|
3838
3874
|
if (key === "timestamp" && typeof value === "string") {
|
|
3839
3875
|
return new Date(value);
|
|
@@ -3848,9 +3884,9 @@ var WorkflowEngine = class {
|
|
|
3848
3884
|
}
|
|
3849
3885
|
}
|
|
3850
3886
|
async saveSnapshots() {
|
|
3851
|
-
const snapshotsPath =
|
|
3887
|
+
const snapshotsPath = path6__namespace.join(this.openspecPath, ".workflow-snapshots.json");
|
|
3852
3888
|
const data = Array.from(this.snapshots.values());
|
|
3853
|
-
await
|
|
3889
|
+
await fs6__namespace.writeFile(snapshotsPath, JSON.stringify(data, null, 2));
|
|
3854
3890
|
}
|
|
3855
3891
|
async createSnapshot() {
|
|
3856
3892
|
if (!this.state) return;
|
|
@@ -3870,16 +3906,16 @@ var WorkflowEngine = class {
|
|
|
3870
3906
|
}
|
|
3871
3907
|
async createChangeRecord() {
|
|
3872
3908
|
if (!this.state) return;
|
|
3873
|
-
const changePath =
|
|
3874
|
-
await
|
|
3909
|
+
const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
3910
|
+
await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
3875
3911
|
}
|
|
3876
3912
|
async updateChangeRecord(status) {
|
|
3877
3913
|
if (!this.state) return;
|
|
3878
3914
|
if (status) {
|
|
3879
3915
|
this.state.status = status;
|
|
3880
3916
|
}
|
|
3881
|
-
const changePath =
|
|
3882
|
-
await
|
|
3917
|
+
const changePath = path6__namespace.join(this.openspecPath, "changes", `${this.state.id}.md`);
|
|
3918
|
+
await fs6__namespace.writeFile(changePath, this.formatChangeRecord());
|
|
3883
3919
|
}
|
|
3884
3920
|
formatChangeRecord() {
|
|
3885
3921
|
if (!this.state) return "";
|
|
@@ -3918,7 +3954,7 @@ ${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
|
3918
3954
|
}
|
|
3919
3955
|
async createSpecDocument(summary) {
|
|
3920
3956
|
if (!this.state) return;
|
|
3921
|
-
const specPath =
|
|
3957
|
+
const specPath = path6__namespace.join(this.openspecPath, "spec", `${this.state.id}.md`);
|
|
3922
3958
|
const content = `# Spec: ${this.state.title}
|
|
3923
3959
|
|
|
3924
3960
|
> \u53D8\u66F4ID: ${this.state.id}
|
|
@@ -3943,7 +3979,7 @@ ${this.state.steps.map((s) => `- [${s.status === "completed" ? "x" : " "}] ${s.s
|
|
|
3943
3979
|
|
|
3944
3980
|
${this.state.artifacts.map((a) => `- ${a}`).join("\n") || "\u6682\u65E0"}
|
|
3945
3981
|
`;
|
|
3946
|
-
await
|
|
3982
|
+
await fs6__namespace.writeFile(specPath, content);
|
|
3947
3983
|
}
|
|
3948
3984
|
};
|
|
3949
3985
|
var ConfirmationRequiredError = class extends Error {
|
|
@@ -3959,19 +3995,36 @@ var MAX_FILE_SIZE2 = 1024 * 1024;
|
|
|
3959
3995
|
var COMPLEXITY_THRESHOLD = 6;
|
|
3960
3996
|
async function handleNew(args, ctx) {
|
|
3961
3997
|
const workingDir = ctx.options.workingDirectory;
|
|
3998
|
+
const workflowEngine = ctx.workflowEngine;
|
|
3999
|
+
if (workflowEngine) {
|
|
4000
|
+
const existingState = workflowEngine.getState();
|
|
4001
|
+
if (existingState && existingState.status === "running") {
|
|
4002
|
+
return {
|
|
4003
|
+
output: chalk9__default.default.yellow("\u5F53\u524D\u5DF2\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41") + chalk9__default.default.gray(`
|
|
4004
|
+
|
|
4005
|
+
\u5DE5\u4F5C\u6D41: ${existingState.title}`) + chalk9__default.default.gray(`
|
|
4006
|
+
\u5F53\u524D\u9636\u6BB5: ${existingState.currentStep}`) + chalk9__default.default.gray(`
|
|
4007
|
+
|
|
4008
|
+
\u9009\u9879:`) + chalk9__default.default.gray(`
|
|
4009
|
+
1. \u7EE7\u7EED\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:${existingState.currentStep}`) + chalk9__default.default.gray(`
|
|
4010
|
+
2. \u53D6\u6D88\u5F53\u524D\u5DE5\u4F5C\u6D41: /opsx:cancel`) + chalk9__default.default.gray(`
|
|
4011
|
+
3. \u67E5\u770B\u5DE5\u4F5C\u6D41\u72B6\u6001: /opsx:status`)
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
3962
4015
|
const { requirement, forceComplexity } = parseArgs(args);
|
|
3963
4016
|
if (!requirement) {
|
|
3964
4017
|
return {
|
|
3965
4018
|
output: chalk9__default.default.red("\u8BF7\u8F93\u5165\u9700\u6C42\u63CF\u8FF0") + chalk9__default.default.gray("\n\u7528\u6CD5: /new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray("\n\u9009\u9879:") + chalk9__default.default.gray("\n --simple \u5F3A\u5236\u4F7F\u7528\u7B80\u5355\u6D41\u7A0B") + chalk9__default.default.gray("\n --complex \u5F3A\u5236\u4F7F\u7528\u590D\u6742\u6D41\u7A0B")
|
|
3966
4019
|
};
|
|
3967
4020
|
}
|
|
3968
|
-
return newFeature({ requirement, forceComplexity }, workingDir);
|
|
4021
|
+
return newFeature({ requirement, forceComplexity }, workingDir, workflowEngine);
|
|
3969
4022
|
}
|
|
3970
|
-
async function newFeature(options, workingDir) {
|
|
4023
|
+
async function newFeature(options, workingDir, workflowEngine) {
|
|
3971
4024
|
const cwd = workingDir || process.cwd();
|
|
3972
4025
|
const { requirement, forceComplexity } = options;
|
|
3973
4026
|
try {
|
|
3974
|
-
const stats = await
|
|
4027
|
+
const stats = await fs6__namespace.stat(cwd);
|
|
3975
4028
|
if (!stats.isDirectory()) {
|
|
3976
4029
|
return {
|
|
3977
4030
|
output: chalk9__default.default.red(`\u9519\u8BEF: ${cwd} \u4E0D\u662F\u6709\u6548\u76EE\u5F55`)
|
|
@@ -3985,8 +4038,10 @@ async function newFeature(options, workingDir) {
|
|
|
3985
4038
|
try {
|
|
3986
4039
|
const context = await readProjectContext(cwd);
|
|
3987
4040
|
const analysis = forceComplexity ? createForcedAnalysis(forceComplexity) : analyzeComplexity(requirement, context);
|
|
3988
|
-
const workflow = new WorkflowEngine();
|
|
3989
|
-
|
|
4041
|
+
const workflow = workflowEngine || new WorkflowEngine();
|
|
4042
|
+
if (!workflowEngine) {
|
|
4043
|
+
await workflow.initialize(cwd);
|
|
4044
|
+
}
|
|
3990
4045
|
const state = await workflow.start(requirement, analysis.score, {
|
|
3991
4046
|
title: extractTitle(requirement)
|
|
3992
4047
|
});
|
|
@@ -4040,20 +4095,20 @@ function parseArgs(args) {
|
|
|
4040
4095
|
}
|
|
4041
4096
|
async function readProjectContext(cwd) {
|
|
4042
4097
|
const defaultContext = {
|
|
4043
|
-
name:
|
|
4098
|
+
name: path6__namespace.basename(cwd),
|
|
4044
4099
|
type: "unknown",
|
|
4045
4100
|
framework: null,
|
|
4046
4101
|
techStack: [],
|
|
4047
4102
|
description: ""
|
|
4048
4103
|
};
|
|
4049
|
-
const agentsPath =
|
|
4104
|
+
const agentsPath = path6__namespace.join(cwd, "AGENTS.md");
|
|
4050
4105
|
try {
|
|
4051
|
-
const stats = await
|
|
4106
|
+
const stats = await fs6__namespace.stat(agentsPath);
|
|
4052
4107
|
if (stats.size > MAX_FILE_SIZE2) {
|
|
4053
4108
|
console.warn(`\u8B66\u544A: AGENTS.md \u6587\u4EF6\u8FC7\u5927 (${stats.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
4054
4109
|
return defaultContext;
|
|
4055
4110
|
}
|
|
4056
|
-
const content = await
|
|
4111
|
+
const content = await fs6__namespace.readFile(agentsPath, "utf-8");
|
|
4057
4112
|
return parseAgentsMd(content, defaultContext);
|
|
4058
4113
|
} catch (e) {
|
|
4059
4114
|
const err = e;
|
|
@@ -4061,14 +4116,14 @@ async function readProjectContext(cwd) {
|
|
|
4061
4116
|
console.warn(`\u8B66\u544A: \u65E0\u6CD5\u8BFB\u53D6 AGENTS.md - ${err.message}`);
|
|
4062
4117
|
}
|
|
4063
4118
|
}
|
|
4064
|
-
const configPath =
|
|
4119
|
+
const configPath = path6__namespace.join(cwd, "openspec", "config.yaml");
|
|
4065
4120
|
try {
|
|
4066
|
-
const stats = await
|
|
4121
|
+
const stats = await fs6__namespace.stat(configPath);
|
|
4067
4122
|
if (stats.size > MAX_FILE_SIZE2) {
|
|
4068
4123
|
console.warn(`\u8B66\u544A: config.yaml \u6587\u4EF6\u8FC7\u5927\uFF0C\u8DF3\u8FC7\u8BFB\u53D6`);
|
|
4069
4124
|
return defaultContext;
|
|
4070
4125
|
}
|
|
4071
|
-
const content = await
|
|
4126
|
+
const content = await fs6__namespace.readFile(configPath, "utf-8");
|
|
4072
4127
|
return parseConfigYaml(content, defaultContext);
|
|
4073
4128
|
} catch (e) {
|
|
4074
4129
|
const err = e;
|
|
@@ -4628,15 +4683,15 @@ async function loadProjectContext(workingDirectory) {
|
|
|
4628
4683
|
devStandards: ""
|
|
4629
4684
|
};
|
|
4630
4685
|
try {
|
|
4631
|
-
context.agentsMd = await
|
|
4686
|
+
context.agentsMd = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "AGENTS.md"), "utf-8");
|
|
4632
4687
|
} catch {
|
|
4633
4688
|
}
|
|
4634
4689
|
try {
|
|
4635
|
-
context.configYaml = await
|
|
4690
|
+
context.configYaml = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, "openspec", "config.yaml"), "utf-8");
|
|
4636
4691
|
} catch {
|
|
4637
4692
|
}
|
|
4638
4693
|
try {
|
|
4639
|
-
context.devStandards = await
|
|
4694
|
+
context.devStandards = await fs6__namespace.readFile(path6__namespace.join(workingDirectory, ".sf-cli", "norms", "devstanded.md"), "utf-8");
|
|
4640
4695
|
} catch {
|
|
4641
4696
|
}
|
|
4642
4697
|
return context;
|
|
@@ -5159,6 +5214,9 @@ ${generateConfirmationPrompt(e.point)}`) + chalk9__default.default.cyan(`
|
|
|
5159
5214
|
}
|
|
5160
5215
|
|
|
5161
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;
|
|
5162
5220
|
async function runSlashCommand(command, args, ctx) {
|
|
5163
5221
|
const normalizedCommand = normalizeCommand(command);
|
|
5164
5222
|
switch (normalizedCommand) {
|
|
@@ -5186,6 +5244,11 @@ async function runSlashCommand(command, args, ctx) {
|
|
|
5186
5244
|
case "new":
|
|
5187
5245
|
case "n":
|
|
5188
5246
|
return handleNew(args, ctx);
|
|
5247
|
+
case "version":
|
|
5248
|
+
case "v":
|
|
5249
|
+
return {
|
|
5250
|
+
output: chalk9__default.default.cyan(`sf-cli v${VERSION2}`)
|
|
5251
|
+
};
|
|
5189
5252
|
default:
|
|
5190
5253
|
if (normalizedCommand.startsWith("opsx:")) {
|
|
5191
5254
|
return handleOpsx(normalizedCommand, args, ctx);
|
|
@@ -5200,11 +5263,11 @@ function normalizeCommand(command) {
|
|
|
5200
5263
|
}
|
|
5201
5264
|
async function handleFileReference(filePath, ctx) {
|
|
5202
5265
|
const cwd = ctx.options.workingDirectory;
|
|
5203
|
-
const absolutePath =
|
|
5266
|
+
const absolutePath = path6__namespace.isAbsolute(filePath) ? filePath : path6__namespace.join(cwd, filePath);
|
|
5204
5267
|
try {
|
|
5205
|
-
const stats = await
|
|
5268
|
+
const stats = await fs6__namespace.stat(absolutePath);
|
|
5206
5269
|
if (stats.isDirectory()) {
|
|
5207
|
-
const files = await
|
|
5270
|
+
const files = await fs6__namespace.readdir(absolutePath);
|
|
5208
5271
|
return {
|
|
5209
5272
|
output: chalk9__default.default.cyan(`\u{1F4C1} ${filePath}/`) + chalk9__default.default.gray(`
|
|
5210
5273
|
${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.default.gray(`
|
|
@@ -5212,7 +5275,7 @@ ${files.slice(0, 20).join("\n")}`) + (files.length > 20 ? chalk9__default.defaul
|
|
|
5212
5275
|
contextUsed: 0
|
|
5213
5276
|
};
|
|
5214
5277
|
}
|
|
5215
|
-
const content = await
|
|
5278
|
+
const content = await fs6__namespace.readFile(absolutePath, "utf-8");
|
|
5216
5279
|
const lines = content.split("\n");
|
|
5217
5280
|
ctx.contextManager.addMessage({
|
|
5218
5281
|
role: "user",
|
|
@@ -5248,7 +5311,7 @@ async function executeShell(command, ctx) {
|
|
|
5248
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")
|
|
5249
5312
|
};
|
|
5250
5313
|
}
|
|
5251
|
-
return new Promise((
|
|
5314
|
+
return new Promise((resolve5) => {
|
|
5252
5315
|
const shell = child_process.spawn(command, [], {
|
|
5253
5316
|
shell: true,
|
|
5254
5317
|
cwd: ctx.options.workingDirectory
|
|
@@ -5273,11 +5336,11 @@ async function executeShell(command, ctx) {
|
|
|
5273
5336
|
output += chalk9__default.default.red(`
|
|
5274
5337
|
\u9000\u51FA\u7801: ${code}`);
|
|
5275
5338
|
}
|
|
5276
|
-
|
|
5339
|
+
resolve5({ output: output || chalk9__default.default.gray("(\u65E0\u8F93\u51FA)") });
|
|
5277
5340
|
});
|
|
5278
5341
|
setTimeout(() => {
|
|
5279
5342
|
shell.kill();
|
|
5280
|
-
|
|
5343
|
+
resolve5({
|
|
5281
5344
|
output: chalk9__default.default.yellow("\u547D\u4EE4\u6267\u884C\u8D85\u65F6\uFF0C\u5DF2\u7EC8\u6B62")
|
|
5282
5345
|
});
|
|
5283
5346
|
}, 6e4);
|
|
@@ -5296,12 +5359,75 @@ async function handleNaturalLanguage(input, ctx) {
|
|
|
5296
5359
|
}
|
|
5297
5360
|
|
|
5298
5361
|
// src/cli/executor.ts
|
|
5362
|
+
var ALLOWED_COMMANDS_WITHOUT_WORKFLOW = [
|
|
5363
|
+
"help",
|
|
5364
|
+
"h",
|
|
5365
|
+
"?",
|
|
5366
|
+
"init",
|
|
5367
|
+
"i",
|
|
5368
|
+
"model",
|
|
5369
|
+
"m",
|
|
5370
|
+
"new",
|
|
5371
|
+
"n",
|
|
5372
|
+
"exit",
|
|
5373
|
+
"e",
|
|
5374
|
+
"q",
|
|
5375
|
+
"quit",
|
|
5376
|
+
"clear",
|
|
5377
|
+
"c",
|
|
5378
|
+
"update",
|
|
5379
|
+
"u",
|
|
5380
|
+
"version",
|
|
5381
|
+
"v"
|
|
5382
|
+
];
|
|
5383
|
+
var STAGE_PERMISSIONS = {
|
|
5384
|
+
"explore": {
|
|
5385
|
+
canRead: true,
|
|
5386
|
+
canWrite: false,
|
|
5387
|
+
canRunShell: false,
|
|
5388
|
+
allowedAgents: ["architect"]
|
|
5389
|
+
},
|
|
5390
|
+
"new": {
|
|
5391
|
+
canRead: true,
|
|
5392
|
+
canWrite: true,
|
|
5393
|
+
canRunShell: false,
|
|
5394
|
+
allowedAgents: ["frontend-dev", "architect"]
|
|
5395
|
+
},
|
|
5396
|
+
"continue": {
|
|
5397
|
+
canRead: true,
|
|
5398
|
+
canWrite: true,
|
|
5399
|
+
canRunShell: true,
|
|
5400
|
+
allowedAgents: ["frontend-dev", "tester"]
|
|
5401
|
+
},
|
|
5402
|
+
"propose": {
|
|
5403
|
+
canRead: true,
|
|
5404
|
+
canWrite: true,
|
|
5405
|
+
canRunShell: true,
|
|
5406
|
+
allowedAgents: ["frontend-dev"]
|
|
5407
|
+
},
|
|
5408
|
+
"apply": {
|
|
5409
|
+
canRead: true,
|
|
5410
|
+
canWrite: true,
|
|
5411
|
+
canRunShell: true,
|
|
5412
|
+
allowedAgents: ["code-reviewer"]
|
|
5413
|
+
},
|
|
5414
|
+
"archive": {
|
|
5415
|
+
canRead: true,
|
|
5416
|
+
canWrite: false,
|
|
5417
|
+
canRunShell: false,
|
|
5418
|
+
allowedAgents: []
|
|
5419
|
+
}
|
|
5420
|
+
};
|
|
5299
5421
|
var CommandExecutor = class {
|
|
5300
5422
|
async execute(parseResult, ctx) {
|
|
5301
5423
|
if (!parseResult.success || !parseResult.command) {
|
|
5302
5424
|
return { output: chalk9__default.default.red(`\u9519\u8BEF: ${parseResult.error}`) };
|
|
5303
5425
|
}
|
|
5304
5426
|
const { command } = parseResult;
|
|
5427
|
+
const workflowCheck = this.checkWorkflowPermission(command, ctx);
|
|
5428
|
+
if (!workflowCheck.allowed) {
|
|
5429
|
+
return { output: workflowCheck.message };
|
|
5430
|
+
}
|
|
5305
5431
|
switch (command.type) {
|
|
5306
5432
|
case "slash" /* SLASH */:
|
|
5307
5433
|
return this.executeSlashCommand(command, ctx);
|
|
@@ -5319,13 +5445,75 @@ var CommandExecutor = class {
|
|
|
5319
5445
|
return { output: chalk9__default.default.red("\u672A\u77E5\u7684\u547D\u4EE4\u7C7B\u578B") };
|
|
5320
5446
|
}
|
|
5321
5447
|
}
|
|
5448
|
+
/**
|
|
5449
|
+
* 检查工作流权限
|
|
5450
|
+
*/
|
|
5451
|
+
checkWorkflowPermission(command, ctx) {
|
|
5452
|
+
const workflowEngine = ctx.workflowEngine;
|
|
5453
|
+
const workflowState = workflowEngine?.getState();
|
|
5454
|
+
if (!workflowState) {
|
|
5455
|
+
if (command.type === "slash" /* SLASH */) {
|
|
5456
|
+
const cmd = command.command?.toLowerCase();
|
|
5457
|
+
if (!ALLOWED_COMMANDS_WITHOUT_WORKFLOW.includes(cmd)) {
|
|
5458
|
+
return {
|
|
5459
|
+
allowed: false,
|
|
5460
|
+
message: chalk9__default.default.yellow("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41") + chalk9__default.default.gray("\n\u8BF7\u5148\u4F7F\u7528 ") + chalk9__default.default.cyan("/new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray(" \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41")
|
|
5461
|
+
};
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
if (command.type === "natural" /* NATURAL */) {
|
|
5465
|
+
return {
|
|
5466
|
+
allowed: false,
|
|
5467
|
+
message: chalk9__default.default.yellow("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41") + chalk9__default.default.gray("\n\u8BF7\u5148\u4F7F\u7528 ") + chalk9__default.default.cyan("/new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray(" \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41")
|
|
5468
|
+
};
|
|
5469
|
+
}
|
|
5470
|
+
if (command.type === "dollar" /* DOLLAR */) {
|
|
5471
|
+
return {
|
|
5472
|
+
allowed: false,
|
|
5473
|
+
message: chalk9__default.default.yellow("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41\uFF0C\u65E0\u6CD5\u8C03\u7528 Agent") + chalk9__default.default.gray("\n\u8BF7\u5148\u4F7F\u7528 ") + chalk9__default.default.cyan("/new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray(" \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41")
|
|
5474
|
+
};
|
|
5475
|
+
}
|
|
5476
|
+
if (command.type === "shell" /* SHELL */) {
|
|
5477
|
+
return {
|
|
5478
|
+
allowed: false,
|
|
5479
|
+
message: chalk9__default.default.yellow("\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u7684\u5DE5\u4F5C\u6D41\uFF0C\u65E0\u6CD5\u6267\u884C Shell \u547D\u4EE4") + chalk9__default.default.gray("\n\u8BF7\u5148\u4F7F\u7528 ") + chalk9__default.default.cyan("/new <\u9700\u6C42\u63CF\u8FF0>") + chalk9__default.default.gray(" \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41")
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
return { allowed: true };
|
|
5483
|
+
}
|
|
5484
|
+
const currentStep = workflowState.currentStep;
|
|
5485
|
+
const permissions = STAGE_PERMISSIONS[currentStep];
|
|
5486
|
+
if (command.type === "at" /* AT */ && !permissions.canRead) {
|
|
5487
|
+
return {
|
|
5488
|
+
allowed: false,
|
|
5489
|
+
message: chalk9__default.default.yellow(`\u5F53\u524D\u9636\u6BB5 [${currentStep}] \u4E0D\u5141\u8BB8\u8BFB\u53D6\u6587\u4EF6`)
|
|
5490
|
+
};
|
|
5491
|
+
}
|
|
5492
|
+
if (command.type === "dollar" /* DOLLAR */) {
|
|
5493
|
+
const agentId = command.agent?.toLowerCase().replace("$", "");
|
|
5494
|
+
if (!permissions.allowedAgents.includes(agentId)) {
|
|
5495
|
+
return {
|
|
5496
|
+
allowed: false,
|
|
5497
|
+
message: chalk9__default.default.yellow(`\u5F53\u524D\u9636\u6BB5 [${currentStep}] \u4E0D\u5141\u8BB8\u8C03\u7528 $${agentId} Agent`) + chalk9__default.default.gray(`
|
|
5498
|
+
\u5F53\u524D\u9636\u6BB5\u5141\u8BB8\u7684 Agent: ${permissions.allowedAgents.map((a) => `$${a}`).join(", ") || "\u65E0"}`)
|
|
5499
|
+
};
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
if (command.type === "shell" /* SHELL */ && !permissions.canRunShell) {
|
|
5503
|
+
return {
|
|
5504
|
+
allowed: false,
|
|
5505
|
+
message: chalk9__default.default.yellow(`\u5F53\u524D\u9636\u6BB5 [${currentStep}] \u4E0D\u5141\u8BB8\u6267\u884C Shell \u547D\u4EE4`)
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5508
|
+
return { allowed: true };
|
|
5509
|
+
}
|
|
5322
5510
|
async executeSlashCommand(command, ctx) {
|
|
5323
5511
|
const result = await runSlashCommand(
|
|
5324
5512
|
command.command,
|
|
5325
5513
|
command.args || [],
|
|
5326
5514
|
ctx
|
|
5327
5515
|
);
|
|
5328
|
-
return { output: result.output };
|
|
5516
|
+
return { output: result.output, exit: result.exit };
|
|
5329
5517
|
}
|
|
5330
5518
|
async executeFileReference(command, ctx) {
|
|
5331
5519
|
const result = await handleFileReference(command.path, ctx);
|
|
@@ -5378,7 +5566,7 @@ var ContextManager = class {
|
|
|
5378
5566
|
}
|
|
5379
5567
|
async initialize(projectPath) {
|
|
5380
5568
|
this.projectPath = projectPath;
|
|
5381
|
-
this.persistPath =
|
|
5569
|
+
this.persistPath = path6__namespace.join(projectPath, ".sf-cli", "cache", "context", "context.json");
|
|
5382
5570
|
await this.loadPersistedContext();
|
|
5383
5571
|
}
|
|
5384
5572
|
/**
|
|
@@ -5619,15 +5807,15 @@ ${summary}`,
|
|
|
5619
5807
|
*/
|
|
5620
5808
|
async persist() {
|
|
5621
5809
|
if (!this.persistPath) return;
|
|
5622
|
-
const dir =
|
|
5623
|
-
await
|
|
5810
|
+
const dir = path6__namespace.dirname(this.persistPath);
|
|
5811
|
+
await fs6__namespace.mkdir(dir, { recursive: true });
|
|
5624
5812
|
const data = {
|
|
5625
5813
|
messages: this.state.messages,
|
|
5626
5814
|
totalTokens: this.state.totalTokens,
|
|
5627
5815
|
limit: this.state.limit,
|
|
5628
5816
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5629
5817
|
};
|
|
5630
|
-
await
|
|
5818
|
+
await fs6__namespace.writeFile(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
|
|
5631
5819
|
}
|
|
5632
5820
|
/**
|
|
5633
5821
|
* 加载持久化的上下文
|
|
@@ -5635,7 +5823,7 @@ ${summary}`,
|
|
|
5635
5823
|
async loadPersistedContext() {
|
|
5636
5824
|
if (!this.persistPath) return;
|
|
5637
5825
|
try {
|
|
5638
|
-
const content = await
|
|
5826
|
+
const content = await fs6__namespace.readFile(this.persistPath, "utf-8");
|
|
5639
5827
|
const data = JSON.parse(content);
|
|
5640
5828
|
this.state.messages = data.messages || [];
|
|
5641
5829
|
this.state.totalTokens = data.totalTokens || 0;
|
|
@@ -5663,11 +5851,28 @@ ${summary}`,
|
|
|
5663
5851
|
return tokens.toString();
|
|
5664
5852
|
}
|
|
5665
5853
|
};
|
|
5854
|
+
var STEP_DISPLAY_NAMES = {
|
|
5855
|
+
"explore": "\u63A2\u7D22",
|
|
5856
|
+
"new": "\u8BBE\u8BA1",
|
|
5857
|
+
"continue": "\u5F00\u53D1",
|
|
5858
|
+
"propose": "\u63D0\u6848",
|
|
5859
|
+
"apply": "\u5BA1\u67E5",
|
|
5860
|
+
"archive": "\u5F52\u6863"
|
|
5861
|
+
};
|
|
5862
|
+
var STEP_COLORS = {
|
|
5863
|
+
"explore": chalk9__default.default.magenta,
|
|
5864
|
+
"new": chalk9__default.default.blue,
|
|
5865
|
+
"continue": chalk9__default.default.cyan,
|
|
5866
|
+
"propose": chalk9__default.default.green,
|
|
5867
|
+
"apply": chalk9__default.default.yellow,
|
|
5868
|
+
"archive": chalk9__default.default.gray
|
|
5869
|
+
};
|
|
5666
5870
|
function displayStatus(info) {
|
|
5667
5871
|
const dirDisplay = info.directory.length > 30 ? "..." + info.directory.slice(-27) : info.directory;
|
|
5668
5872
|
const contextKB = Math.round(info.contextLeft / 1024);
|
|
5669
5873
|
const contextDisplay = contextKB > 100 ? chalk9__default.default.green(`${contextKB}KB`) : contextKB > 50 ? chalk9__default.default.yellow(`${contextKB}KB`) : chalk9__default.default.red(`${contextKB}KB`);
|
|
5670
5874
|
const servicesDisplay = info.services.length > 0 ? info.services.map((s) => `${s.name}:${s.port}`).join(", ") : chalk9__default.default.gray("\u65E0");
|
|
5875
|
+
const workflowDisplay = info.workflowStep ? STEP_COLORS[info.workflowStep](`[${STEP_DISPLAY_NAMES[info.workflowStep]}]`) : chalk9__default.default.gray("[\u65E0\u5DE5\u4F5C\u6D41]");
|
|
5671
5876
|
console.log(chalk9__default.default.gray("\u2500".repeat(60)));
|
|
5672
5877
|
console.log(
|
|
5673
5878
|
chalk9__default.default.cyan("\u{1F4C1}"),
|
|
@@ -5677,7 +5882,10 @@ function displayStatus(info) {
|
|
|
5677
5882
|
chalk9__default.default.white(info.model),
|
|
5678
5883
|
chalk9__default.default.cyan("\u2502"),
|
|
5679
5884
|
chalk9__default.default.cyan("\u{1F4CA}"),
|
|
5680
|
-
contextDisplay
|
|
5885
|
+
contextDisplay,
|
|
5886
|
+
chalk9__default.default.cyan("\u2502"),
|
|
5887
|
+
chalk9__default.default.cyan("\u{1F504}"),
|
|
5888
|
+
workflowDisplay
|
|
5681
5889
|
);
|
|
5682
5890
|
console.log(
|
|
5683
5891
|
chalk9__default.default.cyan("\u{1F50C}"),
|
|
@@ -5785,17 +5993,17 @@ var Completer = class {
|
|
|
5785
5993
|
prefix = filePath;
|
|
5786
5994
|
} else {
|
|
5787
5995
|
const dir = filePath.slice(0, lastSlash);
|
|
5788
|
-
dirPath =
|
|
5996
|
+
dirPath = path6__namespace.resolve(this.workingDirectory, dir);
|
|
5789
5997
|
prefix = filePath.slice(lastSlash + 1);
|
|
5790
5998
|
}
|
|
5791
5999
|
try {
|
|
5792
|
-
const entries = await
|
|
6000
|
+
const entries = await fs6__namespace.readdir(dirPath, { withFileTypes: true });
|
|
5793
6001
|
const matches = [];
|
|
5794
6002
|
for (const entry of entries) {
|
|
5795
6003
|
if (entry.name.startsWith(prefix)) {
|
|
5796
6004
|
const isDir = entry.isDirectory();
|
|
5797
6005
|
matches.push({
|
|
5798
|
-
text: "@" +
|
|
6006
|
+
text: "@" + path6__namespace.relative(this.workingDirectory, path6__namespace.join(dirPath, entry.name)).replace(/\\/g, "/") + (isDir ? "/" : ""),
|
|
5799
6007
|
displayText: entry.name + (isDir ? "/" : ""),
|
|
5800
6008
|
description: isDir ? "\u76EE\u5F55" : "\u6587\u4EF6",
|
|
5801
6009
|
type: isDir ? "directory" : "file"
|
|
@@ -5867,10 +6075,10 @@ var Completer = class {
|
|
|
5867
6075
|
|
|
5868
6076
|
// src/cli/repl.ts
|
|
5869
6077
|
async function startInteractiveMode(options) {
|
|
5870
|
-
const historyFile =
|
|
6078
|
+
const historyFile = path6__namespace.join(options.workingDirectory, ".sf-cli", "history.json");
|
|
5871
6079
|
let history = [];
|
|
5872
6080
|
try {
|
|
5873
|
-
const historyData = await
|
|
6081
|
+
const historyData = await fs6__namespace.readFile(historyFile, "utf-8");
|
|
5874
6082
|
history = JSON.parse(historyData);
|
|
5875
6083
|
} catch {
|
|
5876
6084
|
}
|
|
@@ -5901,10 +6109,17 @@ async function startInteractiveMode(options) {
|
|
|
5901
6109
|
const contextManager = new ContextManager();
|
|
5902
6110
|
const configManager = new ConfigManager();
|
|
5903
6111
|
const modelService = new ModelService(configManager);
|
|
6112
|
+
const workflowEngine = new WorkflowEngine();
|
|
6113
|
+
const normsManager = new NormsManager({
|
|
6114
|
+
projectPath: options.workingDirectory,
|
|
6115
|
+
normsDir: path6__namespace.join(options.workingDirectory, ".sf-cli", "norms")
|
|
6116
|
+
});
|
|
5904
6117
|
await configManager.load(options.workingDirectory);
|
|
5905
6118
|
await contextManager.initialize(options.workingDirectory);
|
|
5906
|
-
const statsDir =
|
|
6119
|
+
const statsDir = path6__namespace.join(options.workingDirectory, ".sf-cli");
|
|
5907
6120
|
await modelService.initialize(statsDir);
|
|
6121
|
+
await workflowEngine.initialize(options.workingDirectory);
|
|
6122
|
+
await normsManager.initialize();
|
|
5908
6123
|
const state = {
|
|
5909
6124
|
isRunning: true,
|
|
5910
6125
|
currentTask: null,
|
|
@@ -5913,16 +6128,27 @@ async function startInteractiveMode(options) {
|
|
|
5913
6128
|
// 512K
|
|
5914
6129
|
};
|
|
5915
6130
|
const currentModel = modelService.getCurrentModel() || "GLM-5";
|
|
6131
|
+
const workflowState = workflowEngine.getState();
|
|
5916
6132
|
displayStatus({
|
|
5917
6133
|
directory: options.workingDirectory,
|
|
5918
6134
|
model: currentModel,
|
|
5919
6135
|
contextLeft: state.contextLimit - state.contextUsed,
|
|
5920
|
-
services: []
|
|
6136
|
+
services: [],
|
|
6137
|
+
workflowStep: workflowState?.currentStep
|
|
5921
6138
|
});
|
|
6139
|
+
if (workflowState) {
|
|
6140
|
+
console.log(chalk9__default.default.cyan(`
|
|
6141
|
+
\u{1F4CB} \u6D3B\u8DC3\u5DE5\u4F5C\u6D41: ${workflowState.title}`));
|
|
6142
|
+
console.log(chalk9__default.default.gray(` \u5F53\u524D\u9636\u6BB5: ${workflowState.currentStep} | \u72B6\u6001: ${workflowState.status}`));
|
|
6143
|
+
console.log(chalk9__default.default.gray(` \u8F93\u5165 /opsx:status \u67E5\u770B\u8BE6\u60C5
|
|
6144
|
+
`));
|
|
6145
|
+
} else {
|
|
6146
|
+
console.log(chalk9__default.default.gray("\n\u{1F4A1} \u4F7F\u7528 /new <\u9700\u6C42\u63CF\u8FF0> \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41\n"));
|
|
6147
|
+
}
|
|
5922
6148
|
const saveHistory = async () => {
|
|
5923
6149
|
try {
|
|
5924
|
-
await
|
|
5925
|
-
await
|
|
6150
|
+
await fs6__namespace.mkdir(path6__namespace.dirname(historyFile), { recursive: true });
|
|
6151
|
+
await fs6__namespace.writeFile(historyFile, JSON.stringify(history.slice(-500)));
|
|
5926
6152
|
} catch {
|
|
5927
6153
|
}
|
|
5928
6154
|
};
|
|
@@ -5963,6 +6189,8 @@ async function startInteractiveMode(options) {
|
|
|
5963
6189
|
contextManager,
|
|
5964
6190
|
configManager,
|
|
5965
6191
|
modelService,
|
|
6192
|
+
normsManager,
|
|
6193
|
+
workflowEngine,
|
|
5966
6194
|
state,
|
|
5967
6195
|
options
|
|
5968
6196
|
});
|
|
@@ -5981,23 +6209,27 @@ async function startInteractiveMode(options) {
|
|
|
5981
6209
|
console.log(chalk9__default.default.red(`\u9519\u8BEF: ${error.message}`));
|
|
5982
6210
|
}
|
|
5983
6211
|
const currentModel2 = modelService.getCurrentModel() || "GLM-5";
|
|
6212
|
+
const workflowState2 = workflowEngine.getState();
|
|
5984
6213
|
displayStatus({
|
|
5985
6214
|
directory: options.workingDirectory,
|
|
5986
6215
|
model: currentModel2,
|
|
5987
6216
|
contextLeft: state.contextLimit - state.contextUsed,
|
|
5988
|
-
services: []
|
|
6217
|
+
services: [],
|
|
6218
|
+
workflowStep: workflowState2?.currentStep
|
|
5989
6219
|
});
|
|
5990
6220
|
rl.prompt();
|
|
5991
6221
|
}
|
|
5992
6222
|
}
|
|
5993
6223
|
|
|
5994
6224
|
// src/cli/index.ts
|
|
5995
|
-
var
|
|
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;
|
|
5996
6228
|
var NAME = "sf-cli";
|
|
5997
|
-
commander.program.name(NAME).description("\u4E13\u4E3A\u524D\u7AEF\u5F00\u53D1\u8BBE\u8BA1\u7684AI\u9A71\u52A8CLI\u5DE5\u5177").version(
|
|
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");
|
|
5998
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) => {
|
|
5999
6231
|
console.log(chalk9__default.default.cyan.bold(`
|
|
6000
|
-
\u{1F680} ${NAME} v${
|
|
6232
|
+
\u{1F680} ${NAME} v${VERSION3}`));
|
|
6001
6233
|
console.log(chalk9__default.default.gray("\u4E13\u4E3A\u524D\u7AEF\u5F00\u53D1\u8BBE\u8BA1\u7684AI\u9A71\u52A8CLI\u5DE5\u5177\n"));
|
|
6002
6234
|
await startInteractiveMode({
|
|
6003
6235
|
workingDirectory: directory,
|