@nick848/sf-cli 1.0.12 → 1.0.13

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 CHANGED
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## v1.0.12 (2026-03-22)
9
+
10
+ **交互优化 - API Key 配置引导**
11
+
12
+ - ✨ 启动时检查 API Key 配置状态,未配置时显示引导信息
13
+ - ✨ 自然语言处理功能实现 - 可直接与 AI 对话
14
+ - 🔧 简化权限逻辑:
15
+ - `/model` 等基础命令始终可用
16
+ - `/new` 需要先配置 API Key
17
+ - 自然语言输入始终可用(内部检查 API Key)
18
+
19
+ **引导流程**
20
+
21
+ ```
22
+ 启动 CLI
23
+
24
+ 检查 API Key
25
+ ↓ 未配置
26
+ ━━━━━━━━━━━━━━━━━━━
27
+ ⚠️ 未配置 API Key
28
+
29
+ 请先配置模型以启用 AI 功能:
30
+ /model - 交互式选择模型并配置 API Key
31
+ /model list - 查看可用模型列表
32
+
33
+ 支持: GLM-5, GPT-4o, Claude
34
+ ━━━━━━━━━━━━━━━━━━━
35
+ ↓ 配置完成
36
+ ✓ 已配置模型: GLM-5
37
+ 💡 使用 /new <需求描述> 启动新工作流
38
+ 或直接输入自然语言与 AI 交互
39
+ ```
40
+
8
41
  ## v1.0.11 (2026-03-22)
9
42
 
10
43
  **重大更新 - 规格确认后自动执行开发流程**
package/dist/cli/index.js CHANGED
@@ -6936,7 +6936,7 @@ async function executeShell(command, ctx) {
6936
6936
  init_cjs_shims();
6937
6937
  init_new();
6938
6938
  async function handleNaturalLanguage(input, ctx) {
6939
- input.trim().toLowerCase();
6939
+ const trimmedInput = input.trim();
6940
6940
  const session = getActiveSession();
6941
6941
  if (session) {
6942
6942
  const result = await handleWorkflowInput(input, ctx);
@@ -6947,81 +6947,163 @@ async function handleNaturalLanguage(input, ctx) {
6947
6947
  };
6948
6948
  }
6949
6949
  }
6950
- ctx.contextManager.addMessage({
6951
- role: "user",
6952
- content: input
6953
- });
6954
- return {
6955
- output: chalk9__default.default.cyan("\u6B63\u5728\u601D\u8003...") + chalk9__default.default.yellow("\n\n\u81EA\u7136\u8BED\u8A00\u5904\u7406\u529F\u80FD\u5F00\u53D1\u4E2D...") + chalk9__default.default.gray(`
6956
- \u8F93\u5165: ${input}`),
6957
- contextUsed: input.length
6958
- };
6950
+ const apiKey = ctx.configManager.get("apiKey");
6951
+ if (!apiKey) {
6952
+ return {
6953
+ output: chalk9__default.default.yellow("\u26A0\uFE0F \u672A\u914D\u7F6E API Key\uFF0C\u65E0\u6CD5\u4F7F\u7528 AI \u529F\u80FD") + chalk9__default.default.gray("\n\n\u8BF7\u5148\u6267\u884C /model \u914D\u7F6E\u6A21\u578B") + chalk9__default.default.gray("\n\u652F\u6301: GLM-5, GPT-4o, Claude"),
6954
+ contextUsed: 0
6955
+ };
6956
+ }
6957
+ try {
6958
+ const response = await ctx.modelService.sendMessage(
6959
+ [
6960
+ {
6961
+ role: "system",
6962
+ content: buildSystemPrompt(ctx)
6963
+ },
6964
+ {
6965
+ role: "user",
6966
+ content: trimmedInput
6967
+ }
6968
+ ],
6969
+ {
6970
+ temperature: 0.7,
6971
+ maxTokens: 2e3
6972
+ }
6973
+ );
6974
+ ctx.contextManager.addMessage({
6975
+ role: "user",
6976
+ content: trimmedInput
6977
+ });
6978
+ ctx.contextManager.addMessage({
6979
+ role: "assistant",
6980
+ content: response.content
6981
+ });
6982
+ return {
6983
+ output: response.content,
6984
+ contextUsed: response.usage?.totalTokens || 0
6985
+ };
6986
+ } catch (error) {
6987
+ const errorMessage = error.message;
6988
+ if (errorMessage.includes("\u672A\u914D\u7F6E") || errorMessage.includes("\u672A\u521D\u59CB\u5316")) {
6989
+ return {
6990
+ output: chalk9__default.default.yellow("\u26A0\uFE0F \u6A21\u578B\u672A\u6B63\u786E\u914D\u7F6E") + chalk9__default.default.gray("\n\n\u8BF7\u6267\u884C /model \u91CD\u65B0\u914D\u7F6E"),
6991
+ contextUsed: 0
6992
+ };
6993
+ }
6994
+ if (errorMessage.includes("timeout") || errorMessage.includes("\u8D85\u65F6")) {
6995
+ return {
6996
+ output: chalk9__default.default.red("\u2717 \u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"),
6997
+ contextUsed: 0
6998
+ };
6999
+ }
7000
+ return {
7001
+ output: chalk9__default.default.red(`\u2717 \u5904\u7406\u5931\u8D25: ${errorMessage}`),
7002
+ contextUsed: 0
7003
+ };
7004
+ }
7005
+ }
7006
+ function buildSystemPrompt(ctx) {
7007
+ const parts = [
7008
+ "\u4F60\u662F sf-cli \u7684 AI \u52A9\u624B\uFF0C\u4E00\u4E2A\u4E13\u4E1A\u7684\u8F6F\u4EF6\u5F00\u53D1\u52A9\u624B\u3002",
7009
+ "",
7010
+ "\u4F60\u53EF\u4EE5\u5E2E\u52A9\u7528\u6237\uFF1A",
7011
+ "1. \u7406\u89E3\u548C\u5206\u6790\u9700\u6C42",
7012
+ "2. \u63D0\u4F9B\u4EE3\u7801\u5EFA\u8BAE\u548C\u5B9E\u73B0\u65B9\u6848",
7013
+ "3. \u56DE\u7B54\u6280\u672F\u95EE\u9898",
7014
+ "4. \u8F85\u52A9\u8FDB\u884C\u4EE3\u7801\u5BA1\u67E5",
7015
+ "",
7016
+ "\u5F53\u524D\u9879\u76EE\u4FE1\u606F\uFF1A",
7017
+ `- \u5DE5\u4F5C\u76EE\u5F55: ${ctx.options.workingDirectory}`,
7018
+ `- \u6A21\u578B: ${ctx.modelService.getCurrentModel() || "\u672A\u6307\u5B9A"}`
7019
+ ];
7020
+ return parts.join("\n");
6959
7021
  }
6960
7022
 
6961
7023
  // src/cli/executor.ts
6962
7024
  init_new();
6963
- var BASIC_COMMANDS = [
7025
+ var ALWAYS_ALLOWED = [
6964
7026
  "help",
6965
7027
  "h",
6966
7028
  "?",
6967
- "init",
6968
- "i",
6969
7029
  "model",
6970
7030
  "m",
6971
- "new",
6972
- "n",
6973
7031
  "exit",
6974
7032
  "e",
6975
7033
  "q",
6976
7034
  "quit",
6977
7035
  "clear",
6978
7036
  "c",
6979
- "update",
6980
- "u",
6981
7037
  "version",
6982
7038
  "v"
6983
7039
  ];
7040
+ var REQUIRES_API_KEY = [
7041
+ "new",
7042
+ "n",
7043
+ "init",
7044
+ "i",
7045
+ "update",
7046
+ "u"
7047
+ ];
6984
7048
  var CommandExecutor = class {
6985
7049
  async execute(parseResult, ctx) {
6986
7050
  if (!parseResult.success || !parseResult.command) {
6987
7051
  return { output: chalk9__default.default.red(`\u9519\u8BEF: ${parseResult.error}`) };
6988
7052
  }
6989
7053
  const { command } = parseResult;
7054
+ const hasApiKey = !!ctx.configManager.get("apiKey");
6990
7055
  const hasActiveWorkflow = getActiveSession() !== null;
6991
- if (!hasActiveWorkflow) {
6992
- if (command.type === "slash" /* SLASH */) {
6993
- const cmd = command.command?.toLowerCase() || "";
6994
- if (!BASIC_COMMANDS.includes(cmd)) {
7056
+ if (command.type === "slash" /* SLASH */) {
7057
+ const cmd = command.command?.toLowerCase() || "";
7058
+ if (ALWAYS_ALLOWED.includes(cmd)) {
7059
+ return this.executeSlashCommand(command, ctx);
7060
+ }
7061
+ if (REQUIRES_API_KEY.includes(cmd)) {
7062
+ if (!hasApiKey) {
6995
7063
  return {
6996
- output: 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")
7064
+ output: chalk9__default.default.yellow("\u26A0\uFE0F \u8BF7\u5148\u914D\u7F6E API Key") + chalk9__default.default.gray("\n\n\u6267\u884C /model \u9009\u62E9\u6A21\u578B\u5E76\u914D\u7F6E API Key")
6997
7065
  };
6998
7066
  }
6999
- } else if (command.type === "dollar" /* DOLLAR */) {
7067
+ return this.executeSlashCommand(command, ctx);
7068
+ }
7069
+ if (!hasActiveWorkflow) {
7070
+ return {
7071
+ output: 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")
7072
+ };
7073
+ }
7074
+ return this.executeSlashCommand(command, ctx);
7075
+ }
7076
+ if (command.type === "dollar" /* DOLLAR */) {
7077
+ if (!hasActiveWorkflow) {
7000
7078
  return {
7001
7079
  output: 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")
7002
7080
  };
7003
- } else if (command.type === "shell" /* SHELL */) {
7081
+ }
7082
+ if (!hasApiKey) {
7083
+ return {
7084
+ output: chalk9__default.default.yellow("\u26A0\uFE0F \u8BF7\u5148\u914D\u7F6E API Key") + chalk9__default.default.gray("\n\n\u6267\u884C /model \u914D\u7F6E\u6A21\u578B")
7085
+ };
7086
+ }
7087
+ return this.executeAgent(command, ctx);
7088
+ }
7089
+ if (command.type === "shell" /* SHELL */) {
7090
+ if (!hasActiveWorkflow) {
7004
7091
  return {
7005
7092
  output: 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")
7006
7093
  };
7007
7094
  }
7095
+ return this.executeShell(command, ctx);
7008
7096
  }
7009
- switch (command.type) {
7010
- case "slash" /* SLASH */:
7011
- return this.executeSlashCommand(command, ctx);
7012
- case "at" /* AT */:
7013
- return this.executeFileReference(command, ctx);
7014
- case "dollar" /* DOLLAR */:
7015
- return this.executeAgent(command, ctx);
7016
- case "shell" /* SHELL */:
7017
- return this.executeShell(command, ctx);
7018
- case "natural" /* NATURAL */:
7019
- return this.executeNaturalLanguage(command, ctx);
7020
- case "yolo" /* YOLO */:
7021
- return this.executeYolo(ctx);
7022
- default:
7023
- return { output: chalk9__default.default.red("\u672A\u77E5\u7684\u547D\u4EE4\u7C7B\u578B") };
7097
+ if (command.type === "at" /* AT */) {
7098
+ return this.executeFileReference(command, ctx);
7099
+ }
7100
+ if (command.type === "natural" /* NATURAL */) {
7101
+ return this.executeNaturalLanguage(command, ctx);
7024
7102
  }
7103
+ if (command.type === "yolo" /* YOLO */) {
7104
+ return this.executeYolo(ctx);
7105
+ }
7106
+ return { output: chalk9__default.default.red("\u672A\u77E5\u7684\u547D\u4EE4\u7C7B\u578B") };
7025
7107
  }
7026
7108
  async executeSlashCommand(command, ctx) {
7027
7109
  const result = await runSlashCommand(
@@ -7670,6 +7752,7 @@ async function startInteractiveMode(options) {
7670
7752
  contextLimit: 512 * 1024
7671
7753
  };
7672
7754
  const currentModel = modelService.getCurrentModel() || "GLM-5";
7755
+ const hasApiKey = !!configManager.get("apiKey");
7673
7756
  const activeSession2 = getActiveSession();
7674
7757
  displayStatus({
7675
7758
  directory: options.workingDirectory,
@@ -7678,14 +7761,34 @@ async function startInteractiveMode(options) {
7678
7761
  services: [],
7679
7762
  workflowStep: activeSession2?.phase
7680
7763
  });
7681
- if (activeSession2) {
7682
- console.log(chalk9__default.default.cyan(`
7764
+ if (!hasApiKey) {
7765
+ console.log("");
7766
+ console.log(chalk9__default.default.yellow.bold("\u26A0\uFE0F \u672A\u914D\u7F6E API Key"));
7767
+ console.log("");
7768
+ console.log(chalk9__default.default.gray("\u8BF7\u5148\u914D\u7F6E\u6A21\u578B\u4EE5\u542F\u7528 AI \u529F\u80FD:"));
7769
+ console.log("");
7770
+ console.log(chalk9__default.default.cyan(" /model ") + chalk9__default.default.gray("- \u4EA4\u4E92\u5F0F\u9009\u62E9\u6A21\u578B\u5E76\u914D\u7F6E API Key"));
7771
+ console.log(chalk9__default.default.cyan(" /model list ") + chalk9__default.default.gray("- \u67E5\u770B\u53EF\u7528\u6A21\u578B\u5217\u8868"));
7772
+ console.log(chalk9__default.default.cyan(" /model set <model-id> ") + chalk9__default.default.gray("- \u76F4\u63A5\u8BBE\u7F6E\u6A21\u578B"));
7773
+ console.log("");
7774
+ console.log(chalk9__default.default.gray("\u652F\u6301\u7684\u6A21\u578B:"));
7775
+ console.log(chalk9__default.default.gray(" \u2022 GLM-5 (\u667A\u8C31AI) - \u63A8\u8350"));
7776
+ console.log(chalk9__default.default.gray(" \u2022 GPT-4o (OpenAI)"));
7777
+ console.log(chalk9__default.default.gray(" \u2022 Claude (Anthropic)"));
7778
+ console.log("");
7779
+ console.log(chalk9__default.default.gray("\u2500".repeat(50)));
7780
+ } else {
7781
+ if (activeSession2) {
7782
+ console.log(chalk9__default.default.cyan(`
7683
7783
  \u{1F4CB} \u6D3B\u8DC3\u5DE5\u4F5C\u6D41: ${activeSession2.requirement.slice(0, 40)}...`));
7684
- console.log(chalk9__default.default.gray(` \u9636\u6BB5: ${activeSession2.phase}`));
7685
- console.log(chalk9__default.default.gray(` \u8F93\u5165\u4EFB\u610F\u5185\u5BB9\u7EE7\u7EED
7784
+ console.log(chalk9__default.default.gray(` \u9636\u6BB5: ${activeSession2.phase}`));
7785
+ console.log(chalk9__default.default.gray(` \u8F93\u5165\u4EFB\u610F\u5185\u5BB9\u7EE7\u7EED
7686
7786
  `));
7687
- } else {
7688
- console.log(chalk9__default.default.gray("\n\u{1F4A1} \u4F7F\u7528 /new <\u9700\u6C42\u63CF\u8FF0> \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41\n"));
7787
+ } else {
7788
+ console.log(chalk9__default.default.green("\n\u2713 \u5DF2\u914D\u7F6E\u6A21\u578B: ") + chalk9__default.default.white(currentModel));
7789
+ console.log(chalk9__default.default.gray("\n\u{1F4A1} \u4F7F\u7528 /new <\u9700\u6C42\u63CF\u8FF0> \u542F\u52A8\u65B0\u5DE5\u4F5C\u6D41"));
7790
+ console.log(chalk9__default.default.gray(" \u6216\u76F4\u63A5\u8F93\u5165\u81EA\u7136\u8BED\u8A00\u4E0E AI \u4EA4\u4E92\n"));
7791
+ }
7689
7792
  }
7690
7793
  const saveHistory = async () => {
7691
7794
  try {