@nick848/sf-cli 1.0.15 → 1.0.17
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/CHANGELOG.md +24 -0
- package/dist/cli/index.js +843 -656
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +250 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +250 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -59,6 +59,7 @@ async function handleNew(args, ctx) {
|
|
|
59
59
|
context: null,
|
|
60
60
|
clarityScore: 0,
|
|
61
61
|
clarificationQuestions: [],
|
|
62
|
+
referenceResources: [],
|
|
62
63
|
complexity: 0,
|
|
63
64
|
bddScenarios: [],
|
|
64
65
|
specItems: [],
|
|
@@ -101,7 +102,7 @@ async function executeWorkflow(ctx) {
|
|
|
101
102
|
const lines = [];
|
|
102
103
|
try {
|
|
103
104
|
if (activeSession.phase === "context") {
|
|
104
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/
|
|
105
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 1/9: \u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6 \u2501\u2501\u2501"));
|
|
105
106
|
lines.push("");
|
|
106
107
|
activeSession.context = await readProjectContext(ctx.options.workingDirectory);
|
|
107
108
|
lines.push(chalk9.gray(` \u9879\u76EE: ${activeSession.context.name}`));
|
|
@@ -115,7 +116,7 @@ async function executeWorkflow(ctx) {
|
|
|
115
116
|
}
|
|
116
117
|
if (activeSession.phase === "clarify") {
|
|
117
118
|
lines.push("");
|
|
118
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/
|
|
119
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 2/9: \u9700\u6C42\u6F84\u6E05 \u2501\u2501\u2501"));
|
|
119
120
|
lines.push("");
|
|
120
121
|
const clarityResult = analyzeRequirementClarity(
|
|
121
122
|
activeSession.requirement,
|
|
@@ -141,11 +142,40 @@ async function executeWorkflow(ctx) {
|
|
|
141
142
|
return { output: lines.join("\n") };
|
|
142
143
|
}
|
|
143
144
|
lines.push(chalk9.green(" \u2713 \u9700\u6C42\u6E05\u6670\uFF0C\u7EE7\u7EED\u4E0B\u4E00\u6B65"));
|
|
145
|
+
activeSession.phase = "reference";
|
|
146
|
+
}
|
|
147
|
+
if (activeSession.phase === "reference") {
|
|
148
|
+
lines.push("");
|
|
149
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 3/9: \u53C2\u8003\u8D44\u6E90\u5206\u6790 \u2501\u2501\u2501"));
|
|
150
|
+
lines.push("");
|
|
151
|
+
const urls = extractUrls(activeSession.refinedRequirement);
|
|
152
|
+
if (urls.length > 0) {
|
|
153
|
+
lines.push(chalk9.gray(` \u53D1\u73B0 ${urls.length} \u4E2A\u53C2\u8003\u94FE\u63A5`));
|
|
154
|
+
lines.push("");
|
|
155
|
+
for (const url of urls) {
|
|
156
|
+
lines.push(chalk9.gray(` \u{1F4CE} ${url}`));
|
|
157
|
+
try {
|
|
158
|
+
const resource = await fetchAndAnalyzeReference(url, ctx);
|
|
159
|
+
activeSession.referenceResources.push(resource);
|
|
160
|
+
lines.push(chalk9.green(` \u2713 \u5DF2\u5206\u6790`));
|
|
161
|
+
activeSession.refinedRequirement += `
|
|
162
|
+
|
|
163
|
+
\u3010\u53C2\u8003\u8D44\u6E90\u5206\u6790 - ${url}\u3011
|
|
164
|
+
${resource.analysis}`;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
lines.push(chalk9.yellow(` \u26A0 \u83B7\u53D6\u5931\u8D25: ${error.message}`));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
lines.push(chalk9.green(" \u2713 \u53C2\u8003\u8D44\u6E90\u5206\u6790\u5B8C\u6210"));
|
|
171
|
+
} else {
|
|
172
|
+
lines.push(chalk9.gray(" \u65E0\u5916\u90E8\u53C2\u8003\u94FE\u63A5"));
|
|
173
|
+
}
|
|
144
174
|
activeSession.phase = "analysis";
|
|
145
175
|
}
|
|
146
176
|
if (activeSession.phase === "analysis") {
|
|
147
177
|
lines.push("");
|
|
148
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
178
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 4/9: \u590D\u6742\u5EA6\u8BC4\u4F30 \u2501\u2501\u2501"));
|
|
149
179
|
lines.push("");
|
|
150
180
|
activeSession.complexity = analyzeComplexity(
|
|
151
181
|
activeSession.refinedRequirement,
|
|
@@ -162,12 +192,13 @@ async function executeWorkflow(ctx) {
|
|
|
162
192
|
}
|
|
163
193
|
if (activeSession.phase === "bdd") {
|
|
164
194
|
lines.push("");
|
|
165
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
195
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 5/9: BDD \u573A\u666F\u62C6\u89E3 \u2501\u2501\u2501"));
|
|
166
196
|
lines.push("");
|
|
167
197
|
activeSession.bddScenarios = generateBDDScenarios(
|
|
168
198
|
activeSession.refinedRequirement,
|
|
169
199
|
activeSession.context,
|
|
170
|
-
activeSession.clarificationQuestions
|
|
200
|
+
activeSession.clarificationQuestions,
|
|
201
|
+
activeSession.referenceResources
|
|
171
202
|
);
|
|
172
203
|
for (const scenario of activeSession.bddScenarios) {
|
|
173
204
|
lines.push(chalk9.white(` Feature: ${scenario.feature}`));
|
|
@@ -182,13 +213,14 @@ async function executeWorkflow(ctx) {
|
|
|
182
213
|
}
|
|
183
214
|
if (activeSession.phase === "spec") {
|
|
184
215
|
lines.push("");
|
|
185
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
216
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 6/9: OpenSpec \u89C4\u683C \u2501\u2501\u2501"));
|
|
186
217
|
lines.push("");
|
|
187
218
|
activeSession.specItems = generateSpecItems(
|
|
188
219
|
activeSession.refinedRequirement,
|
|
189
220
|
activeSession.context,
|
|
190
221
|
activeSession.bddScenarios,
|
|
191
|
-
activeSession.clarificationQuestions
|
|
222
|
+
activeSession.clarificationQuestions,
|
|
223
|
+
activeSession.referenceResources
|
|
192
224
|
);
|
|
193
225
|
const specPath = await saveSpecFile(ctx.options.workingDirectory, activeSession);
|
|
194
226
|
lines.push(chalk9.green(" \u2713 \u89C4\u683C\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
@@ -212,7 +244,7 @@ async function executeWorkflow(ctx) {
|
|
|
212
244
|
}
|
|
213
245
|
if (activeSession.phase === "tdd") {
|
|
214
246
|
lines.push("");
|
|
215
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
247
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 7/9: TDD \u6D4B\u8BD5\u751F\u6210 \u2501\u2501\u2501"));
|
|
216
248
|
lines.push("");
|
|
217
249
|
activeSession.testFiles = await generateTests(ctx.options.workingDirectory, activeSession);
|
|
218
250
|
lines.push(chalk9.green(" \u2713 \u6D4B\u8BD5\u6587\u4EF6\u5DF2\u751F\u6210"));
|
|
@@ -223,7 +255,7 @@ async function executeWorkflow(ctx) {
|
|
|
223
255
|
}
|
|
224
256
|
if (activeSession.phase === "develop") {
|
|
225
257
|
lines.push("");
|
|
226
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
258
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 8/9: \u5F00\u53D1\u5B9E\u73B0 \u2501\u2501\u2501"));
|
|
227
259
|
lines.push("");
|
|
228
260
|
lines.push(chalk9.yellow(" \u{1F680} \u6B63\u5728\u8C03\u7528 AI \u751F\u6210\u4EE3\u7801..."));
|
|
229
261
|
try {
|
|
@@ -248,7 +280,7 @@ async function executeWorkflow(ctx) {
|
|
|
248
280
|
}
|
|
249
281
|
if (activeSession.phase === "review") {
|
|
250
282
|
lines.push("");
|
|
251
|
-
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5
|
|
283
|
+
lines.push(chalk9.cyan("\u2501\u2501\u2501 \u9636\u6BB5 9/9: \u4EE3\u7801\u5BA1\u6838 \u2501\u2501\u2501"));
|
|
252
284
|
lines.push("");
|
|
253
285
|
lines.push(chalk9.yellow(" \u{1F50D} \u6B63\u5728\u8FDB\u884C\u4EE3\u7801\u5BA1\u6838..."));
|
|
254
286
|
try {
|
|
@@ -790,13 +822,41 @@ function analyzeComplexity(requirement, context) {
|
|
|
790
822
|
if (!context.framework) score += 0.5;
|
|
791
823
|
return Math.max(1, Math.min(10, Math.round(score)));
|
|
792
824
|
}
|
|
793
|
-
function generateBDDScenarios(requirement, context, questions) {
|
|
825
|
+
function generateBDDScenarios(requirement, context, questions, references = []) {
|
|
794
826
|
const scenarios = [];
|
|
795
827
|
questions.find((q) => q.category === "ui" && q.answered)?.answer;
|
|
796
828
|
const interactionAnswer = questions.find((q) => q.category === "interaction" && q.answered)?.answer;
|
|
797
829
|
const edgeAnswer = questions.find((q) => q.category === "edge" && q.answered)?.answer;
|
|
830
|
+
if (references.length > 0) {
|
|
831
|
+
for (const ref of references) {
|
|
832
|
+
const refFeatures = extractFeaturesFromReference(ref);
|
|
833
|
+
for (const feature of refFeatures) {
|
|
834
|
+
const scenario = {
|
|
835
|
+
feature: feature.title,
|
|
836
|
+
description: feature.description,
|
|
837
|
+
scenarios: []
|
|
838
|
+
};
|
|
839
|
+
scenario.scenarios.push({
|
|
840
|
+
name: `\u6B63\u5E38\u6D41\u7A0B: ${feature.title}`,
|
|
841
|
+
given: [`\u7528\u6237\u8FDB\u5165\u76F8\u5173\u9875\u9762`],
|
|
842
|
+
when: [`\u7528\u6237\u6267\u884C "${feature.title}" \u64CD\u4F5C`],
|
|
843
|
+
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u5E76\u8FD4\u56DE\u9884\u671F\u7ED3\u679C`]
|
|
844
|
+
});
|
|
845
|
+
if (feature.hasInput) {
|
|
846
|
+
scenario.scenarios.push({
|
|
847
|
+
name: `\u8FB9\u754C\u60C5\u51B5: \u8F93\u5165\u9A8C\u8BC1`,
|
|
848
|
+
given: [`\u7528\u6237\u8FDB\u5165\u8F93\u5165\u754C\u9762`],
|
|
849
|
+
when: [`\u7528\u6237\u8F93\u5165\u8FB9\u754C\u503C\u6216\u7A7A\u503C`],
|
|
850
|
+
then: [`\u7CFB\u7EDF\u5E94\u6B63\u786E\u5904\u7406\u8FB9\u754C\u60C5\u51B5`]
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
scenarios.push(scenario);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
798
857
|
const features = extractFeatures(requirement);
|
|
799
858
|
for (const feature of features) {
|
|
859
|
+
if (scenarios.some((s) => s.feature === feature.title)) continue;
|
|
800
860
|
const scenario = {
|
|
801
861
|
feature: feature.title,
|
|
802
862
|
description: feature.description,
|
|
@@ -828,6 +888,46 @@ function generateBDDScenarios(requirement, context, questions) {
|
|
|
828
888
|
}
|
|
829
889
|
return scenarios;
|
|
830
890
|
}
|
|
891
|
+
function extractFeaturesFromReference(ref) {
|
|
892
|
+
const features = [];
|
|
893
|
+
const analysis = ref.analysis.toLowerCase();
|
|
894
|
+
if (analysis.includes("\u8F93\u5165") || analysis.includes("\u8868\u5355")) {
|
|
895
|
+
features.push({
|
|
896
|
+
title: "\u8F93\u5165\u8868\u5355",
|
|
897
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u8F93\u5165\u8868\u5355\u529F\u80FD",
|
|
898
|
+
hasInput: true
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
if (analysis.includes("\u6309\u94AE") || analysis.includes("\u64CD\u4F5C")) {
|
|
902
|
+
features.push({
|
|
903
|
+
title: "\u4EA4\u4E92\u6309\u94AE",
|
|
904
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6309\u94AE\u4EA4\u4E92",
|
|
905
|
+
hasInput: false
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
if (analysis.includes("\u8868\u683C") || analysis.includes("\u5217\u8868")) {
|
|
909
|
+
features.push({
|
|
910
|
+
title: "\u6570\u636E\u5217\u8868",
|
|
911
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u6570\u636E\u5C55\u793A",
|
|
912
|
+
hasInput: false
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
if (analysis.includes("\u56FE\u8868") || analysis.includes("\u53EF\u89C6\u5316")) {
|
|
916
|
+
features.push({
|
|
917
|
+
title: "\u56FE\u8868\u5C55\u793A",
|
|
918
|
+
description: "\u53C2\u8003\u754C\u9762\u4E2D\u7684\u56FE\u8868\u53EF\u89C6\u5316",
|
|
919
|
+
hasInput: false
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
if (features.length === 0) {
|
|
923
|
+
features.push({
|
|
924
|
+
title: "\u53C2\u8003\u529F\u80FD\u5B9E\u73B0",
|
|
925
|
+
description: `\u57FA\u4E8E\u53C2\u8003\u8D44\u6E90 ${ref.url} \u5B9E\u73B0\u7684\u529F\u80FD`,
|
|
926
|
+
hasInput: true
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
return features;
|
|
930
|
+
}
|
|
831
931
|
function extractFeatures(requirement) {
|
|
832
932
|
const features = [];
|
|
833
933
|
const urlMatch = requirement.match(/https?:\/\/[^\s]+/);
|
|
@@ -868,15 +968,26 @@ function extractFeatures(requirement) {
|
|
|
868
968
|
}
|
|
869
969
|
return features;
|
|
870
970
|
}
|
|
871
|
-
function generateSpecItems(requirement, context, bddScenarios, questions) {
|
|
971
|
+
function generateSpecItems(requirement, context, bddScenarios, questions, references = []) {
|
|
872
972
|
const items = [];
|
|
873
973
|
let id = 1;
|
|
974
|
+
for (const ref of references) {
|
|
975
|
+
items.push({
|
|
976
|
+
id: `T${id.toString().padStart(3, "0")}`,
|
|
977
|
+
title: `\u53C2\u8003\u5206\u6790: ${ref.type}`,
|
|
978
|
+
description: `\u5206\u6790\u53C2\u8003\u8D44\u6E90 ${ref.url}`,
|
|
979
|
+
priority: "high",
|
|
980
|
+
files: [],
|
|
981
|
+
tests: []
|
|
982
|
+
});
|
|
983
|
+
id++;
|
|
984
|
+
}
|
|
874
985
|
for (const scenario of bddScenarios) {
|
|
875
986
|
items.push({
|
|
876
987
|
id: `T${id.toString().padStart(3, "0")}`,
|
|
877
988
|
title: scenario.feature,
|
|
878
989
|
description: scenario.description,
|
|
879
|
-
priority: id <=
|
|
990
|
+
priority: id <= 3 ? "high" : "medium",
|
|
880
991
|
files: [],
|
|
881
992
|
tests: []
|
|
882
993
|
});
|
|
@@ -919,6 +1030,19 @@ function formatSpecFile(session) {
|
|
|
919
1030
|
lines.push("---");
|
|
920
1031
|
lines.push("");
|
|
921
1032
|
}
|
|
1033
|
+
if (session.referenceResources.length > 0) {
|
|
1034
|
+
lines.push("## \u53C2\u8003\u8D44\u6E90");
|
|
1035
|
+
lines.push("");
|
|
1036
|
+
for (const ref of session.referenceResources) {
|
|
1037
|
+
lines.push(`### ${ref.url}`);
|
|
1038
|
+
lines.push(`> \u7C7B\u578B: ${ref.type}`);
|
|
1039
|
+
lines.push("");
|
|
1040
|
+
lines.push(ref.analysis);
|
|
1041
|
+
lines.push("");
|
|
1042
|
+
}
|
|
1043
|
+
lines.push("---");
|
|
1044
|
+
lines.push("");
|
|
1045
|
+
}
|
|
922
1046
|
if (session.clarificationQuestions.some((q) => q.answered)) {
|
|
923
1047
|
lines.push("## \u9700\u6C42\u6F84\u6E05");
|
|
924
1048
|
lines.push("");
|
|
@@ -1024,6 +1148,96 @@ function generateSessionId() {
|
|
|
1024
1148
|
const random = Math.random().toString(36).slice(2, 6);
|
|
1025
1149
|
return `WF-${timestamp}-${random}`.toUpperCase();
|
|
1026
1150
|
}
|
|
1151
|
+
function extractUrls(text) {
|
|
1152
|
+
const urlRegex = /https?:\/\/[^\s<>"{}|\\^`\[\]]+/gi;
|
|
1153
|
+
const matches = text.match(urlRegex);
|
|
1154
|
+
return matches ? [...new Set(matches)] : [];
|
|
1155
|
+
}
|
|
1156
|
+
async function fetchAndAnalyzeReference(url, ctx) {
|
|
1157
|
+
const type = detectResourceType(url);
|
|
1158
|
+
let content = "";
|
|
1159
|
+
let analysis = "";
|
|
1160
|
+
try {
|
|
1161
|
+
const response = await fetch(url, {
|
|
1162
|
+
headers: {
|
|
1163
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
if (!response.ok) {
|
|
1167
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1168
|
+
}
|
|
1169
|
+
content = await response.text();
|
|
1170
|
+
if (ctx.modelService.getCurrentModel()) {
|
|
1171
|
+
analysis = await analyzeReferenceContent(url, content, type, ctx);
|
|
1172
|
+
} else {
|
|
1173
|
+
analysis = extractBasicInfo(content, type);
|
|
1174
|
+
}
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
throw new Error(`\u65E0\u6CD5\u83B7\u53D6\u53C2\u8003\u8D44\u6E90: ${error.message}`);
|
|
1177
|
+
}
|
|
1178
|
+
return { url, type, content: content.slice(0, 1e4), analysis };
|
|
1179
|
+
}
|
|
1180
|
+
function detectResourceType(url) {
|
|
1181
|
+
if (url.includes("figma.com") || url.includes("lanhuapp.com")) {
|
|
1182
|
+
return "design";
|
|
1183
|
+
}
|
|
1184
|
+
if (/\.(png|jpg|jpeg|gif|webp|svg)$/i.test(url)) {
|
|
1185
|
+
return "image";
|
|
1186
|
+
}
|
|
1187
|
+
if (/api\//i.test(url)) {
|
|
1188
|
+
return "api";
|
|
1189
|
+
}
|
|
1190
|
+
return "webpage";
|
|
1191
|
+
}
|
|
1192
|
+
async function analyzeReferenceContent(url, content, type, ctx) {
|
|
1193
|
+
const typePrompts = {
|
|
1194
|
+
webpage: "\u5206\u6790\u8FD9\u4E2A\u7F51\u9875\u7684\u529F\u80FD\u3001UI\u7EC4\u4EF6\u548C\u4EA4\u4E92\u65B9\u5F0F",
|
|
1195
|
+
design: "\u5206\u6790\u8FD9\u4E2A\u8BBE\u8BA1\u7A3F\u7684\u5E03\u5C40\u3001\u7EC4\u4EF6\u548C\u6837\u5F0F",
|
|
1196
|
+
image: "\u63CF\u8FF0\u8FD9\u4E2A\u56FE\u7247\u7684\u5185\u5BB9\u548C\u8BBE\u8BA1\u5143\u7D20",
|
|
1197
|
+
api: "\u5206\u6790\u8FD9\u4E2AAPI\u7684\u7ED3\u6784\u548C\u53C2\u6570"
|
|
1198
|
+
};
|
|
1199
|
+
const prompt2 = `
|
|
1200
|
+
\u8BF7\u5206\u6790\u4EE5\u4E0B\u53C2\u8003\u8D44\u6E90\u7684 URL\uFF0C\u63D0\u53D6\u5BF9\u5F00\u53D1\u6709\u7528\u7684\u4FE1\u606F\uFF1A
|
|
1201
|
+
|
|
1202
|
+
URL: ${url}
|
|
1203
|
+
\u7C7B\u578B: ${type}
|
|
1204
|
+
|
|
1205
|
+
\u5185\u5BB9\u6458\u8981:
|
|
1206
|
+
${content.slice(0, 5e3)}
|
|
1207
|
+
|
|
1208
|
+
${typePrompts[type]}
|
|
1209
|
+
|
|
1210
|
+
\u8BF7\u63D0\u53D6\uFF1A
|
|
1211
|
+
1. \u4E3B\u8981\u529F\u80FD\u70B9
|
|
1212
|
+
2. UI\u7EC4\u4EF6\u7ED3\u6784
|
|
1213
|
+
3. \u4EA4\u4E92\u65B9\u5F0F
|
|
1214
|
+
4. \u6570\u636E\u7ED3\u6784\uFF08\u5982\u679C\u6709\uFF09
|
|
1215
|
+
5. \u6280\u672F\u5B9E\u73B0\u5EFA\u8BAE
|
|
1216
|
+
|
|
1217
|
+
\u4EE5\u7B80\u6D01\u7684\u8981\u70B9\u5F62\u5F0F\u8F93\u51FA\u3002
|
|
1218
|
+
`;
|
|
1219
|
+
try {
|
|
1220
|
+
const response = await ctx.modelService.sendMessage([
|
|
1221
|
+
{ role: "user", content: prompt2 }
|
|
1222
|
+
], { temperature: 0.3, maxTokens: 2e3 });
|
|
1223
|
+
return response.content;
|
|
1224
|
+
} catch {
|
|
1225
|
+
return extractBasicInfo(content, type);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function extractBasicInfo(content, type) {
|
|
1229
|
+
const titleMatch = content.match(/<title[^>]*>([^<]+)<\/title>/i);
|
|
1230
|
+
const descMatch = content.match(/<meta[^>]*name=["']description["'][^>]*content=["']([^"']+)["']/i);
|
|
1231
|
+
const parts = [];
|
|
1232
|
+
if (titleMatch) {
|
|
1233
|
+
parts.push(`\u6807\u9898: ${titleMatch[1]}`);
|
|
1234
|
+
}
|
|
1235
|
+
if (descMatch) {
|
|
1236
|
+
parts.push(`\u63CF\u8FF0: ${descMatch[1]}`);
|
|
1237
|
+
}
|
|
1238
|
+
parts.push(`\u8D44\u6E90\u7C7B\u578B: ${type}`);
|
|
1239
|
+
return parts.join("\n");
|
|
1240
|
+
}
|
|
1027
1241
|
function generateComplexityBar(score) {
|
|
1028
1242
|
const filled = Math.round(score / 2);
|
|
1029
1243
|
const empty = 5 - filled;
|
|
@@ -1033,6 +1247,7 @@ function getPhaseLabel(phase) {
|
|
|
1033
1247
|
const labels = {
|
|
1034
1248
|
context: "\u9879\u76EE\u4E0A\u4E0B\u6587\u83B7\u53D6",
|
|
1035
1249
|
clarify: "\u9700\u6C42\u6F84\u6E05",
|
|
1250
|
+
reference: "\u53C2\u8003\u8D44\u6E90\u5206\u6790",
|
|
1036
1251
|
analysis: "\u590D\u6742\u5EA6\u8BC4\u4F30",
|
|
1037
1252
|
bdd: "BDD \u573A\u666F\u62C6\u89E3",
|
|
1038
1253
|
spec: "OpenSpec \u89C4\u683C",
|
|
@@ -7576,25 +7791,21 @@ ${chalk9.yellow("\u793A\u4F8B:")}
|
|
|
7576
7791
|
|
|
7577
7792
|
// src/commands/model.ts
|
|
7578
7793
|
init_esm_shims();
|
|
7579
|
-
|
|
7580
|
-
// src/services/index.ts
|
|
7581
|
-
init_esm_shims();
|
|
7582
|
-
|
|
7583
|
-
// src/commands/model.ts
|
|
7584
7794
|
async function handleModel(args, ctx) {
|
|
7585
7795
|
const subCommand = args[0];
|
|
7586
7796
|
const configManager = ctx.configManager;
|
|
7797
|
+
const modelService = ctx.modelService;
|
|
7587
7798
|
switch (subCommand) {
|
|
7588
7799
|
case "list":
|
|
7589
7800
|
return listModels();
|
|
7590
7801
|
case "current":
|
|
7591
7802
|
return showCurrentModel(configManager);
|
|
7592
7803
|
case "set":
|
|
7593
|
-
return setModelDirectly(args[1], configManager);
|
|
7804
|
+
return setModelDirectly(args[1], configManager, modelService);
|
|
7594
7805
|
case "verify":
|
|
7595
7806
|
return verifyCurrentModel(configManager);
|
|
7596
7807
|
default:
|
|
7597
|
-
return selectModel(configManager);
|
|
7808
|
+
return selectModel(configManager, modelService);
|
|
7598
7809
|
}
|
|
7599
7810
|
}
|
|
7600
7811
|
async function listModels() {
|
|
@@ -7635,7 +7846,7 @@ async function showCurrentModel(configManager) {
|
|
|
7635
7846
|
];
|
|
7636
7847
|
return { output: lines.join("\n") };
|
|
7637
7848
|
}
|
|
7638
|
-
async function setModelDirectly(modelId, configManager) {
|
|
7849
|
+
async function setModelDirectly(modelId, configManager, modelService) {
|
|
7639
7850
|
if (!modelId) {
|
|
7640
7851
|
return {
|
|
7641
7852
|
output: chalk9.red("\u8BF7\u6307\u5B9A\u6A21\u578BID\uFF0C\u4F8B\u5982: /model set gpt-4o")
|
|
@@ -7650,11 +7861,22 @@ async function setModelDirectly(modelId, configManager) {
|
|
|
7650
7861
|
}
|
|
7651
7862
|
configManager.set("model", modelId);
|
|
7652
7863
|
await configManager.save();
|
|
7864
|
+
const apiKey = configManager.get("apiKey");
|
|
7865
|
+
if (apiKey) {
|
|
7866
|
+
try {
|
|
7867
|
+
await modelService.configureModel({
|
|
7868
|
+
provider: modelInfo.provider,
|
|
7869
|
+
model: modelId,
|
|
7870
|
+
apiKey
|
|
7871
|
+
});
|
|
7872
|
+
} catch {
|
|
7873
|
+
}
|
|
7874
|
+
}
|
|
7653
7875
|
return {
|
|
7654
7876
|
output: chalk9.green(`\u2713 \u5DF2\u5207\u6362\u5230\u6A21\u578B: ${modelInfo.name} (${modelInfo.provider})`)
|
|
7655
7877
|
};
|
|
7656
7878
|
}
|
|
7657
|
-
async function verifyCurrentModel(configManager) {
|
|
7879
|
+
async function verifyCurrentModel(configManager, modelService) {
|
|
7658
7880
|
const currentModel = configManager.get("model");
|
|
7659
7881
|
const apiKey = configManager.get("apiKey");
|
|
7660
7882
|
if (!apiKey) {
|
|
@@ -7687,7 +7909,7 @@ async function verifyCurrentModel(configManager) {
|
|
|
7687
7909
|
};
|
|
7688
7910
|
}
|
|
7689
7911
|
}
|
|
7690
|
-
async function selectModel(configManager) {
|
|
7912
|
+
async function selectModel(configManager, modelService) {
|
|
7691
7913
|
try {
|
|
7692
7914
|
const currentModel = configManager.get("model");
|
|
7693
7915
|
const currentApiKey = configManager.get("apiKey");
|
|
@@ -7751,6 +7973,11 @@ async function selectModel(configManager) {
|
|
|
7751
7973
|
configManager.set("model", modelResponse.model);
|
|
7752
7974
|
configManager.set("apiKey", apiKeyResponse.apiKey);
|
|
7753
7975
|
await configManager.save();
|
|
7976
|
+
await modelService.configureModel({
|
|
7977
|
+
provider: selectedModel.provider,
|
|
7978
|
+
model: modelResponse.model,
|
|
7979
|
+
apiKey: apiKeyResponse.apiKey
|
|
7980
|
+
});
|
|
7754
7981
|
return {
|
|
7755
7982
|
output: chalk9.green(`
|
|
7756
7983
|
\u2713 \u6A21\u578B\u914D\u7F6E\u5B8C\u6210
|