thatgfsj-code 0.3.0 → 0.4.0

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.
Files changed (43) hide show
  1. package/dist/cmd/index.js +1 -1
  2. package/dist/config/index.d.ts +5 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/index.js +22 -4
  5. package/dist/config/index.js.map +1 -1
  6. package/dist/config/providers.d.ts +5 -10
  7. package/dist/config/providers.d.ts.map +1 -1
  8. package/dist/config/providers.js +152 -78
  9. package/dist/config/providers.js.map +1 -1
  10. package/dist/config/types.d.ts +1 -1
  11. package/dist/config/types.d.ts.map +1 -1
  12. package/dist/llm/anthropic.d.ts +34 -3
  13. package/dist/llm/anthropic.d.ts.map +1 -1
  14. package/dist/llm/anthropic.js +83 -35
  15. package/dist/llm/anthropic.js.map +1 -1
  16. package/dist/llm/gemini.d.ts +14 -1
  17. package/dist/llm/gemini.d.ts.map +1 -1
  18. package/dist/llm/gemini.js +56 -23
  19. package/dist/llm/gemini.js.map +1 -1
  20. package/dist/llm/index.d.ts +9 -8
  21. package/dist/llm/index.d.ts.map +1 -1
  22. package/dist/llm/index.js +75 -80
  23. package/dist/llm/index.js.map +1 -1
  24. package/dist/llm/openai.d.ts +30 -3
  25. package/dist/llm/openai.d.ts.map +1 -1
  26. package/dist/llm/openai.js +45 -28
  27. package/dist/llm/openai.js.map +1 -1
  28. package/dist/tui/output.js +1 -1
  29. package/dist/tui/welcome.d.ts +5 -1
  30. package/dist/tui/welcome.d.ts.map +1 -1
  31. package/dist/tui/welcome.js +75 -29
  32. package/dist/tui/welcome.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/cmd/index.ts +1 -1
  35. package/src/config/index.ts +21 -4
  36. package/src/config/providers.ts +153 -79
  37. package/src/config/types.ts +11 -5
  38. package/src/llm/anthropic.ts +90 -39
  39. package/src/llm/gemini.ts +65 -30
  40. package/src/llm/index.ts +77 -87
  41. package/src/llm/openai.ts +46 -34
  42. package/src/tui/output.ts +1 -1
  43. package/src/tui/welcome.ts +86 -32
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Welcome / Setup Wizard
3
- * Migrated and simplified from old src/repl/welcome.ts
3
+ * Supports all providers + custom relay stations (中转站)
4
4
  */
5
5
 
6
6
  import chalk from 'chalk';
@@ -8,7 +8,7 @@ import readline from 'readline';
8
8
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
9
9
  import { join } from 'path';
10
10
  import { homedir } from 'os';
11
- import { PROVIDERS, getModelsForProvider, listProviders } from '../config/providers.js';
11
+ import { PROVIDERS, getModelsForProvider, listProviders, isCustomProvider } from '../config/providers.js';
12
12
  import type { ProviderName } from '../config/types.js';
13
13
 
14
14
  export class WelcomeScreen {
@@ -23,7 +23,7 @@ export class WelcomeScreen {
23
23
  console.log(chalk.cyan('|') + chalk.yellow(' 快速开始指南').padEnd(w) + chalk.cyan('|'));
24
24
  console.log(chalk.cyan('|') + ' '.repeat(w) + chalk.cyan('|'));
25
25
  console.log(chalk.cyan('|') + chalk.gray(' 运行 gfcode init 配置你的 API Key').padEnd(w) + chalk.cyan('|'));
26
- console.log(chalk.cyan('|') + chalk.gray(' 或设置环境变量: OPENAI_API_KEY, SILICONFLOW_API_KEY ').padEnd(w) + chalk.cyan('|'));
26
+ console.log(chalk.cyan('|') + chalk.gray(' 支持: OpenAI / Claude / DeepSeek / Kimi / 智谱 / 中转站').padEnd(w) + chalk.cyan('|'));
27
27
  console.log(chalk.cyan('+') + '-'.repeat(w) + '+');
28
28
  console.log();
29
29
  }
@@ -48,7 +48,8 @@ export class WelcomeScreen {
48
48
  console.log(chalk.white(' 步骤 1/3: 选择 AI 提供商\n'));
49
49
  const providers = listProviders();
50
50
  providers.forEach((p, i) => {
51
- console.log(chalk.green(` ${i + 1}. ${p.name}`));
51
+ const num = (i + 1).toString().padStart(2);
52
+ console.log(chalk.green(` ${num}. ${p.name}`));
52
53
  });
53
54
  console.log();
54
55
 
@@ -56,46 +57,99 @@ export class WelcomeScreen {
56
57
  const selected = providers[parseInt(choice) - 1] || providers[0];
57
58
  const providerName = selected.key;
58
59
 
59
- // Step 2: Enter API Key
60
- console.log(chalk.white('\n 步骤 2/3: 输入 API Key\n'));
61
- console.log(chalk.gray(` 获取地址: ${PROVIDERS[providerName].baseUrl.replace('/v1', '').replace('/v1beta', '')}`));
60
+ // Step 2: Enter API Key (and base URL for custom providers)
61
+ console.log(chalk.white('\n 步骤 2/3: 配置连接信息\n'));
62
+
63
+ let baseUrl: string | undefined;
64
+
65
+ if (isCustomProvider(providerName)) {
66
+ // Custom provider needs base URL
67
+ console.log(chalk.yellow(' 自定义 Provider (中转站) 模式'));
68
+ console.log(chalk.gray(' 支持 OpenAI 兼容 或 Anthropic 兼容 的中转站'));
69
+ console.log();
70
+ baseUrl = await question(chalk.green(' 请输入中转站 Base URL: '));
71
+ if (!baseUrl) {
72
+ console.log(chalk.red(' ❌ 中转站必须提供 Base URL'));
73
+ rl.close();
74
+ return;
75
+ }
76
+ // Remove trailing slash
77
+ baseUrl = baseUrl.replace(/\/+$/, '');
78
+ // Remove /v1 suffix if present (we'll add it in the provider)
79
+ // Actually keep it as-is since the user knows their endpoint
80
+ }
81
+
62
82
  const apiKey = await question(chalk.green(' 请输入 API Key: '));
63
83
 
64
84
  // Step 3: Choose model
65
85
  console.log(chalk.white('\n 步骤 3/3: 选择模型\n'));
66
- const models = getModelsForProvider(providerName);
67
- models.forEach((m, i) => {
68
- console.log(chalk.green(` ${i + 1}. ${m.name}`) + chalk.gray(` - ${m.desc}`));
69
- });
70
- console.log();
71
-
72
- const modelChoice = await question(chalk.green(' 请选择模型 (1-' + models.length + '): '));
73
- const selectedModel = models[parseInt(modelChoice) - 1] || models[0];
74
86
 
75
- // Save config
76
- const configDir = join(homedir(), '.thatgfsj');
77
- const configPath = join(configDir, 'config.json');
78
-
79
- if (!existsSync(configDir)) {
80
- mkdirSync(configDir, { recursive: true });
87
+ if (isCustomProvider(providerName)) {
88
+ // Custom provider: let user type model name
89
+ console.log(chalk.gray(' 输入中转站支持的模型名称'));
90
+ console.log(chalk.gray(' 例如: gpt-4o-mini, claude-sonnet-4-20250514, deepseek-chat'));
91
+ const model = await question(chalk.green(' 模型名称: '));
92
+ if (!model) {
93
+ console.log(chalk.red(' ❌ 必须指定模型'));
94
+ rl.close();
95
+ return;
96
+ }
97
+
98
+ // Save config
99
+ this.saveConfig(providerName, model, apiKey, baseUrl);
100
+ } else {
101
+ // Standard provider: show model list
102
+ const models = getModelsForProvider(providerName);
103
+ models.forEach((m, i) => {
104
+ const num = (i + 1).toString().padStart(2);
105
+ console.log(chalk.green(` ${num}. ${m.name}`) + chalk.gray(` - ${m.desc}`));
106
+ });
107
+ console.log();
108
+
109
+ const modelChoice = await question(chalk.green(' 请选择模型 (1-' + models.length + '): '));
110
+ const selectedModel = models[parseInt(modelChoice) - 1] || models[0];
111
+
112
+ this.saveConfig(providerName, selectedModel.id, apiKey, baseUrl);
81
113
  }
82
114
 
83
- writeFileSync(configPath, JSON.stringify({
84
- provider: providerName,
85
- model: selectedModel.id,
86
- apiKey,
87
- temperature: 0.7,
88
- maxTokens: 4096,
89
- }, null, 2));
90
-
91
115
  console.log(chalk.green('\n ✅ 配置已保存!'));
92
- console.log(chalk.gray(` 提供商: ${providerName}`));
93
- console.log(chalk.gray(` 模型: ${selectedModel.name}`));
94
- console.log(chalk.gray(` 配置文件: ${configPath}`));
116
+ console.log(chalk.gray(` 配置文件: ${join(homedir(), '.thatgfsj', 'config.json')}`));
95
117
  console.log(chalk.cyan('\n 运行 gfcode 开始使用\n'));
96
118
 
97
119
  } finally {
98
120
  rl.close();
99
121
  }
100
122
  }
123
+
124
+ /**
125
+ * Save config to file
126
+ */
127
+ private static saveConfig(provider: ProviderName, model: string, apiKey: string, baseUrl?: string): void {
128
+ const configDir = join(homedir(), '.thatgfsj');
129
+ const configPath = join(configDir, 'config.json');
130
+
131
+ if (!existsSync(configDir)) {
132
+ mkdirSync(configDir, { recursive: true });
133
+ }
134
+
135
+ const config: Record<string, any> = {
136
+ provider,
137
+ model,
138
+ apiKey,
139
+ temperature: 0.7,
140
+ maxTokens: 4096,
141
+ };
142
+
143
+ if (baseUrl) {
144
+ config.baseUrl = baseUrl;
145
+ }
146
+
147
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
148
+
149
+ console.log(chalk.gray(` 提供商: ${provider}`));
150
+ console.log(chalk.gray(` 模型: ${model}`));
151
+ if (baseUrl) {
152
+ console.log(chalk.gray(` Base URL: ${baseUrl}`));
153
+ }
154
+ }
101
155
  }