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.
- package/dist/cmd/index.js +56 -8
- package/dist/cmd/index.js.map +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 +24 -6
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +136 -46
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/gemini.d.ts +4 -4
- package/dist/llm/gemini.d.ts.map +1 -1
- package/dist/llm/gemini.js +67 -30
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/index.d.ts +10 -23
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +73 -78
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/openai.d.ts +19 -6
- package/dist/llm/openai.d.ts.map +1 -1
- package/dist/llm/openai.js +86 -35
- package/dist/llm/openai.js.map +1 -1
- package/dist/llm/provider.d.ts +11 -16
- package/dist/llm/provider.d.ts.map +1 -1
- package/dist/tui/input.d.ts +0 -1
- package/dist/tui/input.d.ts.map +1 -1
- package/dist/tui/input.js +2 -5
- package/dist/tui/input.js.map +1 -1
- package/dist/tui/output.d.ts +27 -12
- package/dist/tui/output.d.ts.map +1 -1
- package/dist/tui/output.js +176 -40
- package/dist/tui/output.js.map +1 -1
- package/dist/tui/repl.d.ts +0 -10
- package/dist/tui/repl.d.ts.map +1 -1
- package/dist/tui/repl.js +76 -42
- package/dist/tui/repl.js.map +1 -1
- package/dist/tui/welcome.d.ts +2 -8
- package/dist/tui/welcome.d.ts.map +1 -1
- package/dist/tui/welcome.js +101 -51
- package/dist/tui/welcome.js.map +1 -1
- package/package.json +1 -1
- package/src/cmd/index.ts +49 -8
- 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 +148 -51
- package/src/llm/gemini.ts +81 -39
- package/src/llm/index.ts +75 -83
- package/src/llm/openai.ts +96 -41
- package/src/llm/provider.ts +12 -16
- package/src/tui/input.ts +2 -5
- package/src/tui/output.ts +193 -40
- package/src/tui/repl.ts +82 -43
- package/src/tui/welcome.ts +110 -53
package/dist/tui/welcome.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
19
|
-
console.log(chalk.cyan
|
|
20
|
-
console.log(chalk.
|
|
21
|
-
console.log(
|
|
22
|
-
console.log(
|
|
23
|
-
console.log(chalk.
|
|
24
|
-
console.log(
|
|
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(
|
|
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
|
|
39
|
+
const ask = (prompt) => new Promise(resolve => rl.question(prompt, answer => resolve(answer.trim())));
|
|
38
40
|
try {
|
|
39
|
-
// Step 1:
|
|
40
|
-
console.log(chalk.
|
|
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
|
-
|
|
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
|
|
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:
|
|
50
|
-
console.log(
|
|
51
|
-
console.log(chalk.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
console.log(
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.log(
|
|
76
|
-
console.log(
|
|
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
|
package/dist/tui/welcome.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome.js","sourceRoot":"","sources":["../../src/tui/welcome.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"welcome.js","sourceRoot":"","sources":["../../src/tui/welcome.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
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.
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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}`));
|
package/src/config/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Config Manager - Handles configuration loading and saving
|
|
3
|
-
*
|
|
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
|
-
|
|
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
|
}
|