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.
- package/dist/cmd/index.js +1 -1
- package/dist/config/index.d.ts +5 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +22 -4
- package/dist/config/index.js.map +1 -1
- package/dist/config/providers.d.ts +5 -10
- package/dist/config/providers.d.ts.map +1 -1
- package/dist/config/providers.js +152 -78
- package/dist/config/providers.js.map +1 -1
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/llm/anthropic.d.ts +34 -3
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +83 -35
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/gemini.d.ts +14 -1
- package/dist/llm/gemini.d.ts.map +1 -1
- package/dist/llm/gemini.js +56 -23
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/index.d.ts +9 -8
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +75 -80
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/openai.d.ts +30 -3
- package/dist/llm/openai.d.ts.map +1 -1
- package/dist/llm/openai.js +45 -28
- package/dist/llm/openai.js.map +1 -1
- package/dist/tui/output.js +1 -1
- package/dist/tui/welcome.d.ts +5 -1
- package/dist/tui/welcome.d.ts.map +1 -1
- package/dist/tui/welcome.js +75 -29
- package/dist/tui/welcome.js.map +1 -1
- package/package.json +1 -1
- package/src/cmd/index.ts +1 -1
- package/src/config/index.ts +21 -4
- package/src/config/providers.ts +153 -79
- package/src/config/types.ts +11 -5
- package/src/llm/anthropic.ts +90 -39
- package/src/llm/gemini.ts +65 -30
- package/src/llm/index.ts +77 -87
- package/src/llm/openai.ts +46 -34
- package/src/tui/output.ts +1 -1
- package/src/tui/welcome.ts +86 -32
package/src/tui/welcome.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Welcome / Setup Wizard
|
|
3
|
-
*
|
|
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('
|
|
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
|
-
|
|
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:
|
|
61
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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(`
|
|
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
|
}
|