thatgfsj-code 0.3.0 → 0.3.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/CHANGELOG.md +229 -0
- package/DEVELOPMENT.md +286 -0
- package/README.md +144 -79
- package/dist/agent/core.d.ts +56 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +142 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/intent.d.ts +36 -0
- package/dist/agent/intent.d.ts.map +1 -0
- package/dist/agent/intent.js +146 -0
- package/dist/agent/intent.js.map +1 -0
- package/dist/agent/streaming.d.ts +50 -0
- package/dist/agent/streaming.d.ts.map +1 -0
- package/dist/agent/streaming.js +110 -0
- package/dist/agent/streaming.js.map +1 -0
- package/dist/core/ai-engine.d.ts +76 -0
- package/dist/core/ai-engine.d.ts.map +1 -0
- package/dist/core/ai-engine.js +394 -0
- package/dist/core/ai-engine.js.map +1 -0
- package/dist/core/cli.d.ts +21 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +143 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +55 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +162 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-compactor.d.ts +54 -0
- package/dist/core/context-compactor.d.ts.map +1 -0
- package/dist/core/context-compactor.js +197 -0
- package/dist/core/context-compactor.js.map +1 -0
- package/dist/core/hooks.d.ts +75 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +146 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/permissions.d.ts +52 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +237 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/session.d.ts +54 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +147 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +175 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +106 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/subagent.d.ts +68 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js +142 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/system-prompt.d.ts +40 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +138 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/tool-registry.d.ts +53 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +138 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/core/types.d.ts +206 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +127 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/{cmd/index.d.ts.map → index.d.ts.map} +1 -1
- package/dist/index.js +472 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +8 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/input.d.ts +69 -0
- package/dist/repl/input.d.ts.map +1 -0
- package/dist/repl/input.js +139 -0
- package/dist/repl/input.js.map +1 -0
- package/dist/repl/loop.d.ts +184 -0
- package/dist/repl/loop.d.ts.map +1 -0
- package/dist/repl/loop.js +932 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/output.d.ts +105 -0
- package/dist/repl/output.d.ts.map +1 -0
- package/dist/repl/output.js +199 -0
- package/dist/repl/output.js.map +1 -0
- package/dist/repl/welcome.d.ts +68 -0
- package/dist/repl/welcome.d.ts.map +1 -0
- package/dist/repl/welcome.js +254 -0
- package/dist/repl/welcome.js.map +1 -0
- package/dist/tools/file.d.ts +1 -1
- package/dist/tools/file.d.ts.map +1 -1
- package/dist/tools/git.d.ts +1 -1
- package/dist/tools/git.d.ts.map +1 -1
- package/dist/tools/index.d.ts +15 -35
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +31 -80
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/search.d.ts +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/shell.d.ts +11 -4
- package/dist/tools/shell.d.ts.map +1 -1
- package/dist/tools/shell.js +78 -42
- package/dist/tools/shell.js.map +1 -1
- package/dist/utils/diff-preview.d.ts +42 -0
- package/dist/utils/diff-preview.d.ts.map +1 -0
- package/dist/utils/diff-preview.js +174 -0
- package/dist/utils/diff-preview.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +81 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +186 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/project-context.d.ts +62 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +197 -0
- package/dist/utils/project-context.js.map +1 -0
- package/docs/API_KEY_GUIDE.md +6 -0
- package/docs/FAQ.md +25 -3
- package/package.json +41 -9
- package/ROADMAP.md +0 -61
- package/dist/app/agent.d.ts +0 -31
- package/dist/app/agent.d.ts.map +0 -1
- package/dist/app/agent.js +0 -106
- package/dist/app/agent.js.map +0 -1
- package/dist/app/index.d.ts +0 -39
- package/dist/app/index.d.ts.map +0 -1
- package/dist/app/index.js +0 -80
- package/dist/app/index.js.map +0 -1
- package/dist/cmd/index.d.ts +0 -12
- package/dist/cmd/index.js +0 -85
- package/dist/cmd/index.js.map +0 -1
- package/dist/config/index.d.ts +0 -39
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js +0 -110
- package/dist/config/index.js.map +0 -1
- package/dist/config/providers.d.ts +0 -23
- package/dist/config/providers.d.ts.map +0 -1
- package/dist/config/providers.js +0 -152
- package/dist/config/providers.js.map +0 -1
- package/dist/config/types.d.ts +0 -33
- package/dist/config/types.d.ts.map +0 -1
- package/dist/config/types.js +0 -5
- package/dist/config/types.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -31
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -71
- package/dist/hooks/index.js.map +0 -1
- package/dist/llm/anthropic.d.ts +0 -17
- package/dist/llm/anthropic.d.ts.map +0 -1
- package/dist/llm/anthropic.js +0 -126
- package/dist/llm/anthropic.js.map +0 -1
- package/dist/llm/gemini.d.ts +0 -16
- package/dist/llm/gemini.d.ts.map +0 -1
- package/dist/llm/gemini.js +0 -107
- package/dist/llm/gemini.js.map +0 -1
- package/dist/llm/index.d.ts +0 -48
- package/dist/llm/index.d.ts.map +0 -1
- package/dist/llm/index.js +0 -174
- package/dist/llm/index.js.map +0 -1
- package/dist/llm/openai.d.ts +0 -17
- package/dist/llm/openai.d.ts.map +0 -1
- package/dist/llm/openai.js +0 -113
- package/dist/llm/openai.js.map +0 -1
- package/dist/llm/provider.d.ts +0 -33
- package/dist/llm/provider.d.ts.map +0 -1
- package/dist/llm/provider.js +0 -6
- package/dist/llm/provider.js.map +0 -1
- package/dist/prompts/index.d.ts +0 -27
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/index.js +0 -102
- package/dist/prompts/index.js.map +0 -1
- package/dist/session/compactor.d.ts +0 -48
- package/dist/session/compactor.d.ts.map +0 -1
- package/dist/session/compactor.js +0 -77
- package/dist/session/compactor.js.map +0 -1
- package/dist/session/index.d.ts +0 -48
- package/dist/session/index.d.ts.map +0 -1
- package/dist/session/index.js +0 -69
- package/dist/session/index.js.map +0 -1
- package/dist/session/message.d.ts +0 -26
- package/dist/session/message.d.ts.map +0 -1
- package/dist/session/message.js +0 -34
- package/dist/session/message.js.map +0 -1
- package/dist/tools/types.d.ts +0 -68
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/types.js +0 -57
- package/dist/tools/types.js.map +0 -1
- package/dist/tui/index.d.ts +0 -8
- package/dist/tui/index.d.ts.map +0 -1
- package/dist/tui/index.js +0 -8
- package/dist/tui/index.js.map +0 -1
- package/dist/tui/input.d.ts +0 -14
- package/dist/tui/input.d.ts.map +0 -1
- package/dist/tui/input.js +0 -50
- package/dist/tui/input.js.map +0 -1
- package/dist/tui/output.d.ts +0 -20
- package/dist/tui/output.d.ts.map +0 -1
- package/dist/tui/output.js +0 -70
- package/dist/tui/output.js.map +0 -1
- package/dist/tui/repl.d.ts +0 -25
- package/dist/tui/repl.d.ts.map +0 -1
- package/dist/tui/repl.js +0 -114
- package/dist/tui/repl.js.map +0 -1
- package/dist/tui/welcome.d.ts +0 -15
- package/dist/tui/welcome.d.ts.map +0 -1
- package/dist/tui/welcome.js +0 -86
- package/dist/tui/welcome.js.map +0 -1
- package/dist/types.d.ts +0 -38
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
- package/dist/utils/diff.d.ts +0 -22
- package/dist/utils/diff.d.ts.map +0 -1
- package/dist/utils/diff.js +0 -60
- package/dist/utils/diff.js.map +0 -1
- package/dist/utils/project.d.ts +0 -32
- package/dist/utils/project.d.ts.map +0 -1
- package/dist/utils/project.js +0 -89
- package/dist/utils/project.js.map +0 -1
- package/src/app/agent.ts +0 -140
- package/src/app/index.ts +0 -101
- package/src/cmd/index.ts +0 -96
- package/src/config/index.ts +0 -130
- package/src/config/providers.ts +0 -160
- package/src/config/types.ts +0 -46
- package/src/hooks/index.ts +0 -111
- package/src/llm/anthropic.ts +0 -146
- package/src/llm/gemini.ts +0 -127
- package/src/llm/index.ts +0 -209
- package/src/llm/openai.ts +0 -132
- package/src/llm/provider.ts +0 -38
- package/src/mcp/client.ts +0 -330
- package/src/prompts/index.ts +0 -123
- package/src/session/compactor.ts +0 -103
- package/src/session/index.ts +0 -81
- package/src/session/message.ts +0 -42
- package/src/tools/file.ts +0 -117
- package/src/tools/git.ts +0 -132
- package/src/tools/index.ts +0 -108
- package/src/tools/search.ts +0 -263
- package/src/tools/shell.ts +0 -136
- package/src/tools/types.ts +0 -122
- package/src/tui/index.ts +0 -8
- package/src/tui/input.ts +0 -56
- package/src/tui/output.ts +0 -83
- package/src/tui/repl.ts +0 -131
- package/src/tui/welcome.ts +0 -101
- package/src/types.ts +0 -42
- package/src/utils/diff.ts +0 -71
- package/src/utils/project.ts +0 -99
- package/tsconfig.json +0 -19
package/src/app/index.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App - Core application singleton
|
|
3
|
-
* Assembles all services: config, LLM, session, tools, hooks, prompts
|
|
4
|
-
* Replaces the scattered initialization in old src/index.ts
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { ConfigManager } from '../config/index.js';
|
|
8
|
-
import { LLMService } from '../llm/index.js';
|
|
9
|
-
import { SessionManager } from '../session/index.js';
|
|
10
|
-
import { ToolRegistry } from '../tools/index.js';
|
|
11
|
-
import { HookManager } from '../hooks/index.js';
|
|
12
|
-
import { SystemPromptBuilder } from '../prompts/index.js';
|
|
13
|
-
import { Agent } from './agent.js';
|
|
14
|
-
import type { ChatMessage } from '../types.js';
|
|
15
|
-
|
|
16
|
-
export class App {
|
|
17
|
-
config: ConfigManager;
|
|
18
|
-
llm: LLMService;
|
|
19
|
-
session: SessionManager;
|
|
20
|
-
tools: ToolRegistry;
|
|
21
|
-
hooks: HookManager;
|
|
22
|
-
prompts: SystemPromptBuilder;
|
|
23
|
-
private agent: Agent;
|
|
24
|
-
|
|
25
|
-
private constructor(
|
|
26
|
-
config: ConfigManager,
|
|
27
|
-
llm: LLMService,
|
|
28
|
-
session: SessionManager,
|
|
29
|
-
tools: ToolRegistry,
|
|
30
|
-
hooks: HookManager,
|
|
31
|
-
prompts: SystemPromptBuilder,
|
|
32
|
-
agent: Agent,
|
|
33
|
-
) {
|
|
34
|
-
this.config = config;
|
|
35
|
-
this.llm = llm;
|
|
36
|
-
this.session = session;
|
|
37
|
-
this.tools = tools;
|
|
38
|
-
this.hooks = hooks;
|
|
39
|
-
this.prompts = prompts;
|
|
40
|
-
this.agent = agent;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Create and initialize the App
|
|
45
|
-
*/
|
|
46
|
-
static async create(): Promise<App> {
|
|
47
|
-
// Load config
|
|
48
|
-
const config = await ConfigManager.load();
|
|
49
|
-
const aiConfig = config.getAIConfig();
|
|
50
|
-
|
|
51
|
-
// Create services
|
|
52
|
-
const llm = LLMService.fromConfig(aiConfig);
|
|
53
|
-
const session = new SessionManager();
|
|
54
|
-
const tools = new ToolRegistry();
|
|
55
|
-
const hooks = new HookManager();
|
|
56
|
-
const prompts = new SystemPromptBuilder({
|
|
57
|
-
cwd: process.cwd(),
|
|
58
|
-
tools: tools.list(),
|
|
59
|
-
permissionMode: 'ask',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Create agent
|
|
63
|
-
const agent = new Agent(llm, tools, { hooks, maxIterations: 10 });
|
|
64
|
-
|
|
65
|
-
// Set up system prompt
|
|
66
|
-
session.addMessage('system', prompts.build());
|
|
67
|
-
|
|
68
|
-
return new App(config, llm, session, tools, hooks, prompts, agent);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Run a single prompt (non-interactive mode)
|
|
73
|
-
*/
|
|
74
|
-
async runPrompt(prompt: string): Promise<string> {
|
|
75
|
-
this.session.addMessage('user', prompt);
|
|
76
|
-
|
|
77
|
-
let fullResponse = '';
|
|
78
|
-
for await (const chunk of this.agent.run(this.session.getMessages())) {
|
|
79
|
-
process.stdout.write(chunk);
|
|
80
|
-
fullResponse += chunk;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
console.log(); // newline
|
|
84
|
-
this.session.addMessage('assistant', fullResponse);
|
|
85
|
-
return fullResponse;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Get the agent for streaming control
|
|
90
|
-
*/
|
|
91
|
-
getAgent(): Agent {
|
|
92
|
-
return this.agent;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get current config
|
|
97
|
-
*/
|
|
98
|
-
getConfig(): ConfigManager {
|
|
99
|
-
return this.config;
|
|
100
|
-
}
|
|
101
|
-
}
|
package/src/cmd/index.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Thatgfsj Code - CLI Entry Point
|
|
5
|
-
* Simplified from old src/index.ts (655 lines → ~60 lines)
|
|
6
|
-
*
|
|
7
|
-
* Two modes:
|
|
8
|
-
* gfcode → Interactive REPL
|
|
9
|
-
* gfcode "prompt" → Single prompt mode
|
|
10
|
-
* gfcode init → Setup wizard
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Force UTF-8 on Windows
|
|
14
|
-
if (process.platform === 'win32') {
|
|
15
|
-
try {
|
|
16
|
-
require('child_process').execSync('chcp 65001', { stdio: 'ignore', windowsHide: true });
|
|
17
|
-
} catch {}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
import { program } from 'commander';
|
|
21
|
-
import chalk from 'chalk';
|
|
22
|
-
import { App } from '../app/index.js';
|
|
23
|
-
import { REPL } from '../tui/repl.js';
|
|
24
|
-
import { WelcomeScreen } from '../tui/welcome.js';
|
|
25
|
-
import { ProjectContext } from '../utils/project.js';
|
|
26
|
-
|
|
27
|
-
// ==================== Error Handling ====================
|
|
28
|
-
|
|
29
|
-
process.on('uncaughtException', (error) => {
|
|
30
|
-
console.error(chalk.red('\n❌ Error:'), error.message);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
process.on('unhandledRejection', (reason) => {
|
|
35
|
-
console.error(chalk.red('\n❌ Error:'), reason);
|
|
36
|
-
process.exit(1);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// ==================== CLI Commands ====================
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
.name('gfcode')
|
|
43
|
-
.description('🤖 Thatgfsj Code - AI Coding Assistant')
|
|
44
|
-
.version('0.3.0')
|
|
45
|
-
.argument('[prompt]', 'Task to execute (omit to start interactive mode)')
|
|
46
|
-
.option('-m, --model <model>', 'Specify model')
|
|
47
|
-
.option('-i, --interactive', 'Force interactive mode')
|
|
48
|
-
.option('--hooks', 'Enable audit logging hooks')
|
|
49
|
-
.action(async (prompt: string | undefined, options: { model?: string; interactive?: boolean; hooks?: boolean }) => {
|
|
50
|
-
try {
|
|
51
|
-
// Initialize app
|
|
52
|
-
const app = await App.create();
|
|
53
|
-
|
|
54
|
-
// Show welcome if no API key
|
|
55
|
-
WelcomeScreen.show(app.config.hasApiKey());
|
|
56
|
-
|
|
57
|
-
// Override model if specified
|
|
58
|
-
if (options.model) {
|
|
59
|
-
await app.config.save({ model: options.model });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Enable hooks if requested
|
|
63
|
-
if (options.hooks) {
|
|
64
|
-
const { auditLogHook } = await import('../hooks/index.js');
|
|
65
|
-
app.hooks.register('afterToolCall', auditLogHook);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!prompt || options.interactive) {
|
|
69
|
-
// Interactive REPL mode
|
|
70
|
-
const repl = new REPL(app);
|
|
71
|
-
await repl.start();
|
|
72
|
-
} 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');
|
|
78
|
-
|
|
79
|
-
await app.runPrompt(prompt);
|
|
80
|
-
}
|
|
81
|
-
} catch (error: any) {
|
|
82
|
-
console.error(chalk.red(`\n❌ ${error.message}`));
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Init command - setup wizard
|
|
88
|
-
program
|
|
89
|
-
.command('init')
|
|
90
|
-
.description('配置 API Key 和模型')
|
|
91
|
-
.action(async () => {
|
|
92
|
-
await WelcomeScreen.interactiveSetup();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Parse and run
|
|
96
|
-
program.parse(process.argv);
|
package/src/config/index.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config Manager - Handles configuration loading and saving
|
|
3
|
-
* Migrated from old src/core/config.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
7
|
-
import { join, dirname } from 'path';
|
|
8
|
-
import { homedir } from 'os';
|
|
9
|
-
import type { Config, AIConfig, ProviderName } from './types.js';
|
|
10
|
-
import { PROVIDERS, getApiKeyFromEnv } from './providers.js';
|
|
11
|
-
|
|
12
|
-
const DEFAULT_CONFIG: Config = {
|
|
13
|
-
model: 'Qwen/Qwen2.5-7B-Instruct',
|
|
14
|
-
apiKey: '',
|
|
15
|
-
temperature: 0.7,
|
|
16
|
-
maxTokens: 4096,
|
|
17
|
-
provider: 'siliconflow',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export class ConfigManager {
|
|
21
|
-
private configPath: string;
|
|
22
|
-
private config: Config;
|
|
23
|
-
|
|
24
|
-
private constructor(configPath: string, config: Config) {
|
|
25
|
-
this.configPath = configPath;
|
|
26
|
-
this.config = config;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Load configuration from file + environment variables
|
|
31
|
-
*/
|
|
32
|
-
static async load(): Promise<ConfigManager> {
|
|
33
|
-
const configDir = join(homedir(), '.thatgfsj');
|
|
34
|
-
const configPath = join(configDir, 'config.json');
|
|
35
|
-
|
|
36
|
-
let config = { ...DEFAULT_CONFIG };
|
|
37
|
-
|
|
38
|
-
// Load from file
|
|
39
|
-
try {
|
|
40
|
-
if (existsSync(configPath)) {
|
|
41
|
-
const data = readFileSync(configPath, 'utf-8');
|
|
42
|
-
config = { ...config, ...JSON.parse(data) };
|
|
43
|
-
}
|
|
44
|
-
} catch {
|
|
45
|
-
// Use defaults if file is corrupted
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Resolve provider
|
|
49
|
-
config = ConfigManager.resolveProvider(config);
|
|
50
|
-
|
|
51
|
-
return new ConfigManager(configPath, config);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Resolve provider settings: API key from env, base URL, model
|
|
56
|
-
*/
|
|
57
|
-
private static resolveProvider(config: Config): Config {
|
|
58
|
-
const provider = config.provider || 'siliconflow';
|
|
59
|
-
const providerConfig = PROVIDERS[provider];
|
|
60
|
-
|
|
61
|
-
if (!providerConfig) {
|
|
62
|
-
return { ...config, provider: 'siliconflow', baseUrl: PROVIDERS.siliconflow.baseUrl };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Model: env MODEL > config > provider default
|
|
66
|
-
const model = process.env.MODEL || config.model || providerConfig.defaultModel;
|
|
67
|
-
|
|
68
|
-
// API key: env > config
|
|
69
|
-
let apiKey = config.apiKey;
|
|
70
|
-
if (provider === 'ollama') {
|
|
71
|
-
apiKey = '';
|
|
72
|
-
} else if (!apiKey) {
|
|
73
|
-
apiKey = getApiKeyFromEnv(provider);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Base URL: config > provider default
|
|
77
|
-
const baseUrl = config.baseUrl || providerConfig.baseUrl;
|
|
78
|
-
|
|
79
|
-
return { ...config, provider, baseUrl, model, apiKey: apiKey || '' };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Get the current config
|
|
84
|
-
*/
|
|
85
|
-
get(): Config {
|
|
86
|
-
return { ...this.config };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get AIConfig for LLM providers
|
|
91
|
-
*/
|
|
92
|
-
getAIConfig(): AIConfig {
|
|
93
|
-
return {
|
|
94
|
-
model: this.config.model,
|
|
95
|
-
apiKey: this.config.apiKey,
|
|
96
|
-
temperature: this.config.temperature,
|
|
97
|
-
maxTokens: this.config.maxTokens,
|
|
98
|
-
baseUrl: this.config.baseUrl,
|
|
99
|
-
provider: this.config.provider,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get provider format (openai | anthropic | gemini)
|
|
105
|
-
*/
|
|
106
|
-
getProviderFormat(): 'openai' | 'anthropic' | 'gemini' {
|
|
107
|
-
return PROVIDERS[this.config.provider]?.format || 'openai';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Update config and save to file
|
|
112
|
-
*/
|
|
113
|
-
async save(updates: Partial<Config>): Promise<void> {
|
|
114
|
-
this.config = { ...this.config, ...updates };
|
|
115
|
-
|
|
116
|
-
const dir = dirname(this.configPath);
|
|
117
|
-
if (!existsSync(dir)) {
|
|
118
|
-
mkdirSync(dir, { recursive: true });
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Check if an API key is configured
|
|
126
|
-
*/
|
|
127
|
-
hasApiKey(): boolean {
|
|
128
|
-
return !!this.config.apiKey;
|
|
129
|
-
}
|
|
130
|
-
}
|
package/src/config/providers.ts
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider definitions and model catalogs
|
|
3
|
-
* Consolidated from old types.ts PROVIDERS + welcome.ts model lists
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ProviderConfig, ProviderName, ModelInfo } from './types.js';
|
|
7
|
-
|
|
8
|
-
// ==================== Provider Definitions ====================
|
|
9
|
-
|
|
10
|
-
export const PROVIDERS: Record<ProviderName, ProviderConfig> = {
|
|
11
|
-
siliconflow: {
|
|
12
|
-
name: 'SiliconFlow (硅基流动)',
|
|
13
|
-
baseUrl: 'https://api.siliconflow.cn/v1',
|
|
14
|
-
defaultModel: 'Qwen/Qwen2.5-7B-Instruct',
|
|
15
|
-
envKeys: ['SILICONFLOW_API_KEY', 'OPENAI_API_KEY'],
|
|
16
|
-
format: 'openai',
|
|
17
|
-
},
|
|
18
|
-
minimax: {
|
|
19
|
-
name: 'MiniMax',
|
|
20
|
-
baseUrl: 'https://api.minimax.io/anthropic/v1',
|
|
21
|
-
defaultModel: 'MiniMax-M2.5',
|
|
22
|
-
envKeys: ['MINIMAX_API_KEY', 'OPENAI_API_KEY'],
|
|
23
|
-
format: 'anthropic',
|
|
24
|
-
},
|
|
25
|
-
openai: {
|
|
26
|
-
name: 'OpenAI',
|
|
27
|
-
baseUrl: 'https://api.openai.com/v1',
|
|
28
|
-
defaultModel: 'gpt-4o-mini',
|
|
29
|
-
envKeys: ['OPENAI_API_KEY'],
|
|
30
|
-
format: 'openai',
|
|
31
|
-
},
|
|
32
|
-
anthropic: {
|
|
33
|
-
name: 'Anthropic',
|
|
34
|
-
baseUrl: 'https://api.anthropic.com/v1',
|
|
35
|
-
defaultModel: 'claude-3-haiku-20240307',
|
|
36
|
-
envKeys: ['ANTHROPIC_API_KEY'],
|
|
37
|
-
format: 'anthropic',
|
|
38
|
-
},
|
|
39
|
-
ollama: {
|
|
40
|
-
name: 'Ollama (Local)',
|
|
41
|
-
baseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',
|
|
42
|
-
defaultModel: 'llama2',
|
|
43
|
-
envKeys: [],
|
|
44
|
-
format: 'openai',
|
|
45
|
-
},
|
|
46
|
-
gemini: {
|
|
47
|
-
name: 'Google Gemini',
|
|
48
|
-
baseUrl: 'https://generativelanguage.googleapis.com/v1beta',
|
|
49
|
-
defaultModel: 'gemini-1.5-flash',
|
|
50
|
-
envKeys: ['GEMINI_API_KEY'],
|
|
51
|
-
format: 'gemini',
|
|
52
|
-
},
|
|
53
|
-
kimi: {
|
|
54
|
-
name: 'Kimi (Moonshot AI)',
|
|
55
|
-
baseUrl: 'https://api.moonshot.cn/v1',
|
|
56
|
-
defaultModel: 'moonshot-v1-8k',
|
|
57
|
-
envKeys: ['KIMI_API_KEY', 'MOONSHOT_API_KEY'],
|
|
58
|
-
format: 'openai',
|
|
59
|
-
},
|
|
60
|
-
deepseek: {
|
|
61
|
-
name: 'DeepSeek',
|
|
62
|
-
baseUrl: 'https://api.deepseek.com/v1',
|
|
63
|
-
defaultModel: 'deepseek-chat',
|
|
64
|
-
envKeys: ['DEEPSEEK_API_KEY'],
|
|
65
|
-
format: 'openai',
|
|
66
|
-
},
|
|
67
|
-
ernie: {
|
|
68
|
-
name: 'Baidu ERNIE (文心一言)',
|
|
69
|
-
baseUrl: 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1',
|
|
70
|
-
defaultModel: 'ernie-4.0-8k',
|
|
71
|
-
envKeys: ['ERNIE_API_KEY', 'BAIDU_API_KEY'],
|
|
72
|
-
format: 'openai',
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// ==================== Model Catalogs ====================
|
|
77
|
-
|
|
78
|
-
export const MODEL_CATALOGS: Record<ProviderName, ModelInfo[]> = {
|
|
79
|
-
siliconflow: [
|
|
80
|
-
{ id: 'Qwen/Qwen2.5-7B-Instruct', name: 'Qwen2.5-7B (推荐)', desc: '性价比高,适合日常编程' },
|
|
81
|
-
{ id: 'Qwen/Qwen2.5-32B-Instruct', name: 'Qwen2.5-32B', desc: '更强性能,适合复杂任务' },
|
|
82
|
-
{ id: 'Qwen/Qwen2.5-72B-Instruct', name: 'Qwen2.5-72B', desc: '旗舰模型' },
|
|
83
|
-
{ id: 'Pro/moonshotai/Kimi-K2.5', name: 'Kimi-K2.5 (私有)', desc: 'Moonshot 强力模型' },
|
|
84
|
-
{ id: 'Pro/deepseek-ai/DeepSeek-V3', name: 'DeepSeek-V3', desc: '深度求索最新模型' },
|
|
85
|
-
{ id: 'Pro/deepseek-ai/DeepSeek-R1', name: 'DeepSeek-R1', desc: '推理能力强' },
|
|
86
|
-
{ id: 'THUDM/glm-4-9b-chat', name: 'GLM-4-9B', desc: '智谱模型' },
|
|
87
|
-
{ id: 'THUDM/glm-4-32b-chat', name: 'GLM-4-32B', desc: '智谱大模型' },
|
|
88
|
-
{ id: '01-ai/Yi-1.5-34B-Chat', name: 'Yi-1.5-34B', desc: '零一万物' },
|
|
89
|
-
{ id: 'microsoft/WizardLM-2-8x22B', name: 'WizardLM-2', desc: '微软开源' },
|
|
90
|
-
],
|
|
91
|
-
minimax: [
|
|
92
|
-
{ id: 'MiniMax-M2.5', name: 'MiniMax-M2.5 (推荐)', desc: 'Agent 能力最强' },
|
|
93
|
-
{ id: 'MiniMax-M2.1', name: 'MiniMax-M2.1', desc: '稳定版本' },
|
|
94
|
-
],
|
|
95
|
-
openai: [
|
|
96
|
-
{ id: 'gpt-4o-mini', name: 'GPT-4o-mini (推荐)', desc: '性价比高' },
|
|
97
|
-
{ id: 'gpt-4o', name: 'GPT-4o', desc: '最新旗舰' },
|
|
98
|
-
{ id: 'gpt-4-turbo', name: 'GPT-4-Turbo', desc: '强性能' },
|
|
99
|
-
],
|
|
100
|
-
anthropic: [
|
|
101
|
-
{ id: 'claude-3-haiku-20240307', name: 'Claude-3-Haiku (推荐)', desc: '快速响应' },
|
|
102
|
-
{ id: 'claude-3.5-sonnet-20241022', name: 'Claude-3.5-Sonnet', desc: '最新旗舰' },
|
|
103
|
-
{ id: 'claude-3-opus-20240229', name: 'Claude-3-Opus', desc: '最强性能' },
|
|
104
|
-
],
|
|
105
|
-
ollama: [
|
|
106
|
-
{ id: 'llama2', name: 'Llama 2', desc: 'Meta 开源模型' },
|
|
107
|
-
{ id: 'codellama', name: 'Code Llama', desc: '编程专用' },
|
|
108
|
-
{ id: 'mistral', name: 'Mistral', desc: '高性能开源' },
|
|
109
|
-
],
|
|
110
|
-
gemini: [
|
|
111
|
-
{ id: 'gemini-1.5-flash-8b', name: 'Gemini-1.5-Flash-8B (推荐)', desc: '免费快速' },
|
|
112
|
-
{ id: 'gemini-1.5-flash', name: 'Gemini-1.5-Flash', desc: '性价比高' },
|
|
113
|
-
{ id: 'gemini-1.5-pro', name: 'Gemini-1.5-Pro', desc: '最新旗舰' },
|
|
114
|
-
],
|
|
115
|
-
kimi: [
|
|
116
|
-
{ id: 'moonshot-v1-8k', name: 'Moonshot-V1-8K (推荐)', desc: '日常编程' },
|
|
117
|
-
{ id: 'moonshot-v1-32k', name: 'Moonshot-V1-32K', desc: '更长上下文' },
|
|
118
|
-
{ id: 'moonshot-v1-128k', name: 'Moonshot-V1-128K', desc: '超长上下文' },
|
|
119
|
-
],
|
|
120
|
-
deepseek: [
|
|
121
|
-
{ id: 'deepseek-chat', name: 'DeepSeek-Chat (推荐)', desc: '性价比高' },
|
|
122
|
-
{ id: 'deepseek-coder', name: 'DeepSeek-Coder', desc: '编程专用' },
|
|
123
|
-
],
|
|
124
|
-
ernie: [
|
|
125
|
-
{ id: 'ernie-4.0-8k', name: 'ERNIE-4.0-8K (推荐)', desc: '百度旗舰' },
|
|
126
|
-
{ id: 'ernie-3.5-8k', name: 'ERNIE-3.5-8K', desc: '性价比高' },
|
|
127
|
-
],
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// ==================== Helpers ====================
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get models for a specific provider
|
|
134
|
-
*/
|
|
135
|
-
export function getModelsForProvider(provider: ProviderName): ModelInfo[] {
|
|
136
|
-
return MODEL_CATALOGS[provider] || MODEL_CATALOGS.siliconflow;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get API key for a provider from environment variables
|
|
141
|
-
*/
|
|
142
|
-
export function getApiKeyFromEnv(provider: ProviderName): string {
|
|
143
|
-
const providerConfig = PROVIDERS[provider];
|
|
144
|
-
if (!providerConfig) return '';
|
|
145
|
-
|
|
146
|
-
for (const envKey of providerConfig.envKeys) {
|
|
147
|
-
if (process.env[envKey]) return process.env[envKey];
|
|
148
|
-
}
|
|
149
|
-
return '';
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* List all provider names
|
|
154
|
-
*/
|
|
155
|
-
export function listProviders(): Array<{ key: ProviderName; name: string }> {
|
|
156
|
-
return Object.entries(PROVIDERS).map(([key, val]) => ({
|
|
157
|
-
key: key as ProviderName,
|
|
158
|
-
name: val.name,
|
|
159
|
-
}));
|
|
160
|
-
}
|
package/src/config/types.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration types for Thatgfsj Code
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type ProviderName =
|
|
6
|
-
| 'siliconflow'
|
|
7
|
-
| 'minimax'
|
|
8
|
-
| 'openai'
|
|
9
|
-
| 'anthropic'
|
|
10
|
-
| 'ollama'
|
|
11
|
-
| 'gemini'
|
|
12
|
-
| 'kimi'
|
|
13
|
-
| 'deepseek'
|
|
14
|
-
| 'ernie';
|
|
15
|
-
|
|
16
|
-
export interface ProviderConfig {
|
|
17
|
-
name: string;
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
defaultModel: string;
|
|
20
|
-
envKeys: string[];
|
|
21
|
-
format: 'openai' | 'anthropic' | 'gemini';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface Config {
|
|
25
|
-
model: string;
|
|
26
|
-
apiKey: string;
|
|
27
|
-
temperature: number;
|
|
28
|
-
maxTokens: number;
|
|
29
|
-
provider: ProviderName;
|
|
30
|
-
baseUrl?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface AIConfig {
|
|
34
|
-
model: string;
|
|
35
|
-
apiKey?: string;
|
|
36
|
-
temperature?: number;
|
|
37
|
-
maxTokens?: number;
|
|
38
|
-
baseUrl?: string;
|
|
39
|
-
provider?: ProviderName;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ModelInfo {
|
|
43
|
-
id: string;
|
|
44
|
-
name: string;
|
|
45
|
-
desc: string;
|
|
46
|
-
}
|
package/src/hooks/index.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hooks System - Event-driven lifecycle hooks
|
|
3
|
-
* Migrated from old src/core/hooks.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ChatMessage, ToolCall } from '../types.js';
|
|
7
|
-
|
|
8
|
-
// ==================== Hook Types ====================
|
|
9
|
-
|
|
10
|
-
export type HookName =
|
|
11
|
-
| 'beforeToolCall'
|
|
12
|
-
| 'afterToolCall'
|
|
13
|
-
| 'beforeAgentLoop'
|
|
14
|
-
| 'afterAgentLoop'
|
|
15
|
-
| 'onError';
|
|
16
|
-
|
|
17
|
-
export interface HookContext {
|
|
18
|
-
toolName?: string;
|
|
19
|
-
toolParams?: Record<string, any>;
|
|
20
|
-
toolResult?: any;
|
|
21
|
-
messages?: ChatMessage[];
|
|
22
|
-
error?: Error;
|
|
23
|
-
iteration?: number;
|
|
24
|
-
[key: string]: any;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type HookFn = (ctx: HookContext) => void | Promise<void>;
|
|
28
|
-
|
|
29
|
-
interface HookRegistration {
|
|
30
|
-
name: HookName;
|
|
31
|
-
fn: HookFn;
|
|
32
|
-
priority?: number;
|
|
33
|
-
once?: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ==================== Hook Manager ====================
|
|
37
|
-
|
|
38
|
-
export class HookManager {
|
|
39
|
-
private hooks: Map<HookName, HookRegistration[]> = new Map();
|
|
40
|
-
|
|
41
|
-
constructor() {
|
|
42
|
-
const allHooks: HookName[] = ['beforeToolCall', 'afterToolCall', 'beforeAgentLoop', 'afterAgentLoop', 'onError'];
|
|
43
|
-
for (const h of allHooks) {
|
|
44
|
-
this.hooks.set(h, []);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
register(name: HookName, fn: HookFn, priority = 0, once = false): void {
|
|
49
|
-
const regs = this.hooks.get(name) || [];
|
|
50
|
-
regs.push({ name, fn, priority, once });
|
|
51
|
-
regs.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
52
|
-
this.hooks.set(name, regs);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
unregister(name: HookName, fn: HookFn): void {
|
|
56
|
-
const regs = this.hooks.get(name) || [];
|
|
57
|
-
this.hooks.set(name, regs.filter(r => r.fn !== fn));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
clear(name?: HookName): void {
|
|
61
|
-
if (name) {
|
|
62
|
-
this.hooks.set(name, []);
|
|
63
|
-
} else {
|
|
64
|
-
for (const regs of this.hooks.values()) {
|
|
65
|
-
regs.length = 0;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async emit(name: HookName, ctx: HookContext): Promise<void> {
|
|
71
|
-
const regs = this.hooks.get(name) || [];
|
|
72
|
-
for (const reg of regs) {
|
|
73
|
-
try {
|
|
74
|
-
await Promise.resolve(reg.fn(ctx));
|
|
75
|
-
} catch (error: any) {
|
|
76
|
-
console.error(`[Hook ${name}] error:`, error.message);
|
|
77
|
-
}
|
|
78
|
-
if (reg.once) {
|
|
79
|
-
this.unregister(name, reg.fn);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
hasHooks(name: HookName): boolean {
|
|
85
|
-
return (this.hooks.get(name)?.length || 0) > 0;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ==================== Built-in Hooks ====================
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Audit logging hook - logs all tool calls
|
|
93
|
-
*/
|
|
94
|
-
export function auditLogHook(ctx: HookContext): void {
|
|
95
|
-
if (ctx.toolName) {
|
|
96
|
-
const ts = new Date().toISOString().split('T')[1].split('.')[0];
|
|
97
|
-
const status = ctx.toolResult?.success ? 'OK' : 'FAIL';
|
|
98
|
-
console.log(`[AUDIT ${ts}] ${status} | tool=${ctx.toolName} | params=${JSON.stringify(ctx.toolParams || {})}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ==================== Singleton ====================
|
|
103
|
-
|
|
104
|
-
let globalHookManager: HookManager | null = null;
|
|
105
|
-
|
|
106
|
-
export function getHookManager(): HookManager {
|
|
107
|
-
if (!globalHookManager) {
|
|
108
|
-
globalHookManager = new HookManager();
|
|
109
|
-
}
|
|
110
|
-
return globalHookManager;
|
|
111
|
-
}
|