thatgfsj-code 0.3.0 → 0.4.1

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 (60) hide show
  1. package/dist/cmd/index.js +56 -8
  2. package/dist/cmd/index.js.map +1 -1
  3. package/dist/config/index.d.ts +5 -1
  4. package/dist/config/index.d.ts.map +1 -1
  5. package/dist/config/index.js +22 -4
  6. package/dist/config/index.js.map +1 -1
  7. package/dist/config/providers.d.ts +5 -10
  8. package/dist/config/providers.d.ts.map +1 -1
  9. package/dist/config/providers.js +152 -78
  10. package/dist/config/providers.js.map +1 -1
  11. package/dist/config/types.d.ts +1 -1
  12. package/dist/config/types.d.ts.map +1 -1
  13. package/dist/llm/anthropic.d.ts +24 -6
  14. package/dist/llm/anthropic.d.ts.map +1 -1
  15. package/dist/llm/anthropic.js +136 -46
  16. package/dist/llm/anthropic.js.map +1 -1
  17. package/dist/llm/gemini.d.ts +4 -4
  18. package/dist/llm/gemini.d.ts.map +1 -1
  19. package/dist/llm/gemini.js +67 -30
  20. package/dist/llm/gemini.js.map +1 -1
  21. package/dist/llm/index.d.ts +10 -23
  22. package/dist/llm/index.d.ts.map +1 -1
  23. package/dist/llm/index.js +73 -78
  24. package/dist/llm/index.js.map +1 -1
  25. package/dist/llm/openai.d.ts +19 -6
  26. package/dist/llm/openai.d.ts.map +1 -1
  27. package/dist/llm/openai.js +86 -35
  28. package/dist/llm/openai.js.map +1 -1
  29. package/dist/llm/provider.d.ts +11 -16
  30. package/dist/llm/provider.d.ts.map +1 -1
  31. package/dist/tui/input.d.ts +0 -1
  32. package/dist/tui/input.d.ts.map +1 -1
  33. package/dist/tui/input.js +2 -5
  34. package/dist/tui/input.js.map +1 -1
  35. package/dist/tui/output.d.ts +27 -12
  36. package/dist/tui/output.d.ts.map +1 -1
  37. package/dist/tui/output.js +176 -40
  38. package/dist/tui/output.js.map +1 -1
  39. package/dist/tui/repl.d.ts +0 -10
  40. package/dist/tui/repl.d.ts.map +1 -1
  41. package/dist/tui/repl.js +76 -42
  42. package/dist/tui/repl.js.map +1 -1
  43. package/dist/tui/welcome.d.ts +2 -8
  44. package/dist/tui/welcome.d.ts.map +1 -1
  45. package/dist/tui/welcome.js +101 -51
  46. package/dist/tui/welcome.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/cmd/index.ts +49 -8
  49. package/src/config/index.ts +21 -4
  50. package/src/config/providers.ts +153 -79
  51. package/src/config/types.ts +11 -5
  52. package/src/llm/anthropic.ts +148 -51
  53. package/src/llm/gemini.ts +81 -39
  54. package/src/llm/index.ts +75 -83
  55. package/src/llm/openai.ts +96 -41
  56. package/src/llm/provider.ts +12 -16
  57. package/src/tui/input.ts +2 -5
  58. package/src/tui/output.ts +193 -40
  59. package/src/tui/repl.ts +82 -43
  60. package/src/tui/welcome.ts +110 -53
@@ -1,86 +1,136 @@
1
1
  /**
2
- * Welcome / Setup Wizard
3
- * Migrated and simplified from old src/repl/welcome.ts
2
+ * Welcome / Setup Wizard - Clean UI
4
3
  */
5
4
  import chalk from 'chalk';
6
5
  import readline from 'readline';
7
6
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
8
7
  import { join } from 'path';
9
8
  import { homedir } from 'os';
10
- import { PROVIDERS, getModelsForProvider, listProviders } from '../config/providers.js';
9
+ import { getModelsForProvider, listProviders, isCustomProvider } from '../config/providers.js';
10
+ const line = chalk.gray('─'.repeat(52));
11
11
  export class WelcomeScreen {
12
- /**
13
- * Show welcome if no API key is configured
14
- */
15
12
  static show(hasApiKey) {
16
13
  if (hasApiKey)
17
14
  return;
18
- const w = 62;
19
- console.log(chalk.cyan('+') + chalk.white.bold(' Thatgfsj Code ') + chalk.cyan('-'.repeat(w - 16)) + '+');
20
- console.log(chalk.cyan('|') + chalk.yellow(' 快速开始指南').padEnd(w) + chalk.cyan('|'));
21
- console.log(chalk.cyan('|') + ' '.repeat(w) + chalk.cyan('|'));
22
- console.log(chalk.cyan('|') + chalk.gray(' 运行 gfcode init 配置你的 API Key').padEnd(w) + chalk.cyan('|'));
23
- console.log(chalk.cyan('|') + chalk.gray(' 或设置环境变量: OPENAI_API_KEY, SILICONFLOW_API_KEY 等').padEnd(w) + chalk.cyan('|'));
24
- console.log(chalk.cyan('+') + '-'.repeat(w) + '+');
15
+ console.log();
16
+ console.log(chalk.cyan.bold(' Thatgfsj Code') + chalk.gray(' v0.4.1'));
17
+ console.log(chalk.gray(' AI Coding Assistant'));
18
+ console.log(line);
19
+ console.log();
20
+ console.log(chalk.yellow(' ⚠ No API key configured'));
21
+ console.log();
22
+ console.log(chalk.gray(' Run ') + chalk.cyan.bold('gfcode init') + chalk.gray(' to set up your provider.'));
23
+ console.log();
24
+ console.log(chalk.gray(' Supported providers:'));
25
+ console.log(chalk.gray(' OpenAI · Claude · DeepSeek · Kimi · GLM · Gemini · 中转站'));
26
+ console.log(line);
25
27
  console.log();
26
28
  }
27
- /**
28
- * Interactive setup wizard
29
- */
30
29
  static async interactiveSetup() {
31
30
  console.clear();
32
- console.log(chalk.cyan('\n 🤖 Thatgfsj Code 配置向导\n'));
31
+ console.log();
32
+ console.log(chalk.cyan.bold(' ⚡ Thatgfsj Code') + chalk.gray(' - Setup'));
33
+ console.log(line);
34
+ console.log();
33
35
  const rl = readline.createInterface({
34
36
  input: process.stdin,
35
37
  output: process.stdout,
36
38
  });
37
- const question = (prompt) => new Promise(resolve => rl.question(prompt, answer => resolve(answer.trim())));
39
+ const ask = (prompt) => new Promise(resolve => rl.question(prompt, answer => resolve(answer.trim())));
38
40
  try {
39
- // Step 1: Choose provider
40
- console.log(chalk.white(' 步骤 1/3: 选择 AI 提供商\n'));
41
+ // ── Step 1: Provider ────────────────────────────────
42
+ console.log(chalk.bold(' 1. Choose Provider'));
43
+ console.log();
41
44
  const providers = listProviders();
42
45
  providers.forEach((p, i) => {
43
- console.log(chalk.green(` ${i + 1}. ${p.name}`));
46
+ const num = chalk.cyan((i + 1).toString().padStart(2));
47
+ console.log(` ${num} ${p.name}`);
44
48
  });
45
49
  console.log();
46
- const choice = await question(chalk.green(' 请选择 (1-' + providers.length + '): '));
50
+ const choice = await ask(chalk.cyan(' '));
47
51
  const selected = providers[parseInt(choice) - 1] || providers[0];
48
52
  const providerName = selected.key;
49
- // Step 2: Enter API Key
50
- console.log(chalk.white('\n 步骤 2/3: 输入 API Key\n'));
51
- console.log(chalk.gray(` 获取地址: ${PROVIDERS[providerName].baseUrl.replace('/v1', '').replace('/v1beta', '')}`));
52
- const apiKey = await question(chalk.green(' 请输入 API Key: '));
53
- // Step 3: Choose model
54
- console.log(chalk.white('\n 步骤 3/3: 选择模型\n'));
55
- const models = getModelsForProvider(providerName);
56
- models.forEach((m, i) => {
57
- console.log(chalk.green(` ${i + 1}. ${m.name}`) + chalk.gray(` - ${m.desc}`));
58
- });
53
+ // ── Step 2: API Key ─────────────────────────────────
54
+ console.log();
55
+ console.log(chalk.bold(' 2. API Key'));
56
+ console.log();
57
+ let baseUrl;
58
+ if (isCustomProvider(providerName)) {
59
+ console.log(chalk.yellow(' Custom Provider (Relay Station)'));
60
+ console.log(chalk.gray(' OpenAI-compatible or Anthropic-compatible'));
61
+ console.log();
62
+ baseUrl = await ask(chalk.cyan(' Base URL ❯ '));
63
+ if (!baseUrl) {
64
+ console.log(chalk.red(' ❌ Base URL required'));
65
+ rl.close();
66
+ return;
67
+ }
68
+ baseUrl = baseUrl.replace(/\/+$/, '');
69
+ }
70
+ const apiKey = await ask(chalk.cyan(' API Key ❯ '));
71
+ // ── Step 3: Model ───────────────────────────────────
72
+ console.log();
73
+ console.log(chalk.bold(' 3. Choose Model'));
59
74
  console.log();
60
- const modelChoice = await question(chalk.green(' 请选择模型 (1-' + models.length + '): '));
61
- const selectedModel = models[parseInt(modelChoice) - 1] || models[0];
62
- // Save config
63
- const configDir = join(homedir(), '.thatgfsj');
64
- const configPath = join(configDir, 'config.json');
65
- if (!existsSync(configDir)) {
66
- mkdirSync(configDir, { recursive: true });
75
+ if (isCustomProvider(providerName)) {
76
+ console.log(chalk.gray(' Enter model name for your relay station'));
77
+ console.log(chalk.gray(' e.g. gpt-4o-mini, claude-sonnet-4-20250514'));
78
+ console.log();
79
+ const model = await ask(chalk.cyan(' Model '));
80
+ if (!model) {
81
+ console.log(chalk.red(' ❌ Model name required'));
82
+ rl.close();
83
+ return;
84
+ }
85
+ this.saveConfig(providerName, model, apiKey, baseUrl);
86
+ }
87
+ else {
88
+ const models = getModelsForProvider(providerName);
89
+ models.forEach((m, i) => {
90
+ const num = chalk.cyan((i + 1).toString().padStart(2));
91
+ console.log(` ${num} ${chalk.white(m.name)} ${chalk.gray(m.desc)}`);
92
+ });
93
+ console.log();
94
+ const modelChoice = await ask(chalk.cyan(' ❯ '));
95
+ const selectedModel = models[parseInt(modelChoice) - 1] || models[0];
96
+ this.saveConfig(providerName, selectedModel.id, apiKey, baseUrl);
67
97
  }
68
- writeFileSync(configPath, JSON.stringify({
69
- provider: providerName,
70
- model: selectedModel.id,
71
- apiKey,
72
- temperature: 0.7,
73
- maxTokens: 4096,
74
- }, null, 2));
75
- console.log(chalk.green('\n ✅ 配置已保存!'));
76
- console.log(chalk.gray(` 提供商: ${providerName}`));
77
- console.log(chalk.gray(` 模型: ${selectedModel.name}`));
78
- console.log(chalk.gray(` 配置文件: ${configPath}`));
79
- console.log(chalk.cyan('\n 运行 gfcode 开始使用\n'));
98
+ // ── Done ────────────────────────────────────────────
99
+ console.log();
100
+ console.log(line);
101
+ console.log(chalk.green.bold(' ✅ Configuration saved!'));
102
+ console.log();
103
+ console.log(chalk.gray(' Config: ') + chalk.white(join(homedir(), '.thatgfsj', 'config.json')));
104
+ console.log(chalk.gray(' Run ') + chalk.cyan.bold('gfcode') + chalk.gray(' to start.'));
105
+ console.log(line);
106
+ console.log();
80
107
  }
81
108
  finally {
82
109
  rl.close();
83
110
  }
84
111
  }
112
+ static saveConfig(provider, model, apiKey, baseUrl) {
113
+ const configDir = join(homedir(), '.thatgfsj');
114
+ const configPath = join(configDir, 'config.json');
115
+ if (!existsSync(configDir)) {
116
+ mkdirSync(configDir, { recursive: true });
117
+ }
118
+ const config = {
119
+ provider,
120
+ model,
121
+ apiKey,
122
+ temperature: 0.7,
123
+ maxTokens: 4096,
124
+ };
125
+ if (baseUrl)
126
+ config.baseUrl = baseUrl;
127
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
128
+ console.log();
129
+ console.log(chalk.gray(' Provider: ') + chalk.white(provider));
130
+ console.log(chalk.gray(' Model: ') + chalk.white(model));
131
+ if (baseUrl) {
132
+ console.log(chalk.gray(' URL: ') + chalk.white(baseUrl));
133
+ }
134
+ }
85
135
  }
86
136
  //# sourceMappingURL=welcome.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"welcome.js","sourceRoot":"","sources":["../../src/tui/welcome.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"welcome.js","sourceRoot":"","sources":["../../src/tui/welcome.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thatgfsj-code",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Thatgfsj Code - AI Coding Assistant",
5
5
  "main": "dist/cmd/index.js",
6
6
  "type": "module",
package/src/cmd/index.ts CHANGED
@@ -22,7 +22,6 @@ import chalk from 'chalk';
22
22
  import { App } from '../app/index.js';
23
23
  import { REPL } from '../tui/repl.js';
24
24
  import { WelcomeScreen } from '../tui/welcome.js';
25
- import { ProjectContext } from '../utils/project.js';
26
25
 
27
26
  // ==================== Error Handling ====================
28
27
 
@@ -41,7 +40,7 @@ process.on('unhandledRejection', (reason) => {
41
40
  program
42
41
  .name('gfcode')
43
42
  .description('🤖 Thatgfsj Code - AI Coding Assistant')
44
- .version('0.3.0')
43
+ .version('0.4.1')
45
44
  .argument('[prompt]', 'Task to execute (omit to start interactive mode)')
46
45
  .option('-m, --model <model>', 'Specify model')
47
46
  .option('-i, --interactive', 'Force interactive mode')
@@ -70,13 +69,55 @@ program
70
69
  const repl = new REPL(app);
71
70
  await repl.start();
72
71
  } else {
73
- // Single prompt mode
74
- console.log(chalk.cyan('\n🤖 Thatgfsj Code\n'));
75
- console.log(chalk.gray(ProjectContext.getSummary()));
76
- console.log(chalk.gray('─'.repeat(40)));
77
- console.log(chalk.cyan('\n> ') + prompt + '\n');
72
+ // Single prompt mode - use same UI as REPL
73
+ const { REPLOutput } = await import('../tui/output.js');
74
+ const out = new REPLOutput();
78
75
 
79
- await app.runPrompt(prompt);
76
+ out.printBanner();
77
+ out.printUserInput(prompt);
78
+ out.startThinking();
79
+
80
+ app.session.addMessage('user', prompt);
81
+ let fullResponse = '';
82
+ let hasStarted = false;
83
+
84
+ try {
85
+ const stream = app.getAgent().run(app.session.getMessages());
86
+ for await (const chunk of stream) {
87
+ out.stopThinking();
88
+
89
+ const parts = chunk.split('\n');
90
+ for (const part of parts) {
91
+ if (part.startsWith('@@TOOL@@')) {
92
+ try {
93
+ const data = JSON.parse(part.slice(8));
94
+ if (data.action === 'call') {
95
+ if (hasStarted) { out.endAssistant(); hasStarted = false; }
96
+ out.printToolCall(data.name, data.args || '');
97
+ out.startExecuting(data.name);
98
+ } else if (data.action === 'result') {
99
+ out.stopThinking();
100
+ out.printToolResult(data.output || data.error || '', !!data.error);
101
+ out.printToolEnd();
102
+ }
103
+ } catch {}
104
+ continue;
105
+ }
106
+ if (part) {
107
+ if (!hasStarted) { out.beginAssistant(); hasStarted = true; }
108
+ out.writeChunk(part + '\n');
109
+ }
110
+ }
111
+ fullResponse += chunk;
112
+ }
113
+ if (hasStarted) out.endAssistant();
114
+ } catch (error: any) {
115
+ if (hasStarted) out.endAssistant();
116
+ out.stopThinkingFail(error.message);
117
+ out.error(error.message);
118
+ }
119
+
120
+ app.session.addMessage('assistant', fullResponse);
80
121
  }
81
122
  } catch (error: any) {
82
123
  console.error(chalk.red(`\n❌ ${error.message}`));
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Config Manager - Handles configuration loading and saving
3
- * Migrated from old src/core/config.ts
3
+ * Supports custom providers (relay stations / 中转站)
4
4
  */
5
5
 
6
6
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
7
7
  import { join, dirname } from 'path';
8
8
  import { homedir } from 'os';
9
9
  import type { Config, AIConfig, ProviderName } from './types.js';
10
- import { PROVIDERS, getApiKeyFromEnv } from './providers.js';
10
+ import { PROVIDERS, getApiKeyFromEnv, isCustomProvider } from './providers.js';
11
11
 
12
12
  const DEFAULT_CONFIG: Config = {
13
13
  model: 'Qwen/Qwen2.5-7B-Instruct',
@@ -73,8 +73,18 @@ export class ConfigManager {
73
73
  apiKey = getApiKeyFromEnv(provider);
74
74
  }
75
75
 
76
- // Base URL: config > provider default
77
- const baseUrl = config.baseUrl || providerConfig.baseUrl;
76
+ // Base URL: config > env > provider default
77
+ let baseUrl = config.baseUrl;
78
+ if (!baseUrl) {
79
+ // Check env for custom base URL
80
+ if (provider === 'custom_openai') {
81
+ baseUrl = process.env.CUSTOM_BASE_URL || '';
82
+ } else if (provider === 'custom_anthropic') {
83
+ baseUrl = process.env.CUSTOM_BASE_URL || '';
84
+ } else {
85
+ baseUrl = providerConfig.baseUrl;
86
+ }
87
+ }
78
88
 
79
89
  return { ...config, provider, baseUrl, model, apiKey: apiKey || '' };
80
90
  }
@@ -127,4 +137,11 @@ export class ConfigManager {
127
137
  hasApiKey(): boolean {
128
138
  return !!this.config.apiKey;
129
139
  }
140
+
141
+ /**
142
+ * Check if using a custom provider
143
+ */
144
+ isCustomProvider(): boolean {
145
+ return isCustomProvider(this.config.provider);
146
+ }
130
147
  }