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/tools/shell.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shell Tool - Execute shell commands with security checks
|
|
3
|
-
* Migrated from old src/tools/shell.ts (permission logic inlined)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Tool, ToolResult, ToolContext } from './types.js';
|
|
7
|
-
import { exec } from 'child_process';
|
|
8
|
-
import { promisify } from 'util';
|
|
9
|
-
|
|
10
|
-
const execAsync = promisify(exec);
|
|
11
|
-
|
|
12
|
-
// Dangerous command patterns - blocked immediately
|
|
13
|
-
const DANGEROUS_PATTERNS = [
|
|
14
|
-
/^rm\s+-rf\s+\//i,
|
|
15
|
-
/^del\s+\/f\s+\/s\s+\/q/i,
|
|
16
|
-
/^format\s+[a-z]:/i,
|
|
17
|
-
/^mkfs/i,
|
|
18
|
-
/^dd\s+if=/i,
|
|
19
|
-
/^shred/i,
|
|
20
|
-
/^cat\s+\/dev\/null\s*>/i,
|
|
21
|
-
/>\s*\/dev\/sda/i,
|
|
22
|
-
/^rm\s+-rf\s+\$HOME/i,
|
|
23
|
-
/^rm\s+-rf\s+%USERPROFILE%/i,
|
|
24
|
-
/^curl\s+.*\|.*sh/i,
|
|
25
|
-
/^wget\s+.*\|.*sh/i,
|
|
26
|
-
/^eval\s+/i,
|
|
27
|
-
/base64\s+-d\s+.*\|/i,
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
// Commands that need user confirmation
|
|
31
|
-
const CONFIRM_REQUIRED = [
|
|
32
|
-
'rm -rf',
|
|
33
|
-
'rmdir',
|
|
34
|
-
'del /s /q',
|
|
35
|
-
'format',
|
|
36
|
-
'mkfs',
|
|
37
|
-
'dd',
|
|
38
|
-
'shutdown',
|
|
39
|
-
'reboot',
|
|
40
|
-
'pkill',
|
|
41
|
-
'killall',
|
|
42
|
-
'git push --force',
|
|
43
|
-
'git push -f',
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
export class ShellTool implements Tool {
|
|
47
|
-
name = 'shell';
|
|
48
|
-
description = 'Execute shell commands and scripts. Some commands require user confirmation.';
|
|
49
|
-
|
|
50
|
-
inputSchema = {
|
|
51
|
-
type: 'object' as const,
|
|
52
|
-
properties: {
|
|
53
|
-
command: { type: 'string', description: 'Shell command to execute' },
|
|
54
|
-
cwd: { type: 'string', description: 'Working directory' },
|
|
55
|
-
timeout: { type: 'number', description: 'Timeout in seconds', default: 30 },
|
|
56
|
-
},
|
|
57
|
-
required: ['command'],
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
metadata = {
|
|
61
|
-
permissions: ['execute', 'write', 'network'] as ('read' | 'write' | 'execute' | 'network')[],
|
|
62
|
-
tags: ['shell', 'system', 'dangerous'],
|
|
63
|
-
maxDuration: 120000,
|
|
64
|
-
version: '1.0.0',
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
parameters = [
|
|
68
|
-
{ name: 'command', type: 'string', description: 'Shell command to execute', required: true },
|
|
69
|
-
{ name: 'cwd', type: 'string', description: 'Working directory', required: false },
|
|
70
|
-
{ name: 'timeout', type: 'number', description: 'Timeout in seconds', required: false },
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Check if command matches dangerous patterns
|
|
75
|
-
*/
|
|
76
|
-
private isDangerous(command: string): boolean {
|
|
77
|
-
return DANGEROUS_PATTERNS.some(pattern => pattern.test(command.trim()));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if command needs user confirmation
|
|
82
|
-
*/
|
|
83
|
-
private needsConfirmation(command: string): boolean {
|
|
84
|
-
const lower = command.toLowerCase();
|
|
85
|
-
return CONFIRM_REQUIRED.some(cmd => lower.includes(cmd.toLowerCase()));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async execute(params: Record<string, any>, ctx?: ToolContext): Promise<ToolResult> {
|
|
89
|
-
const { command, cwd, timeout = 30 } = params;
|
|
90
|
-
|
|
91
|
-
if (!command || typeof command !== 'string') {
|
|
92
|
-
return { success: false, error: 'Command is required and must be a string' };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const trimmed = command.trim();
|
|
96
|
-
|
|
97
|
-
// Block dangerous commands
|
|
98
|
-
if (this.isDangerous(trimmed)) {
|
|
99
|
-
return { success: false, error: `Blocked: dangerous command "${trimmed.substring(0, 50)}..."` };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (trimmed.length > 10000) {
|
|
103
|
-
return { success: false, error: 'Command too long (max 10000 characters)' };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Ask for confirmation on risky commands
|
|
107
|
-
if (ctx?.confirmAction && this.needsConfirmation(trimmed)) {
|
|
108
|
-
const confirmed = await ctx.confirmAction(
|
|
109
|
-
`⚠️ Confirm command:\n ${command}\n\n[y] Yes [n] No`
|
|
110
|
-
);
|
|
111
|
-
if (!confirmed) {
|
|
112
|
-
return { success: false, error: 'Command cancelled by user' };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
const options: any = {
|
|
118
|
-
timeout: timeout * 1000,
|
|
119
|
-
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
120
|
-
};
|
|
121
|
-
if (cwd) options.cwd = cwd;
|
|
122
|
-
|
|
123
|
-
const { stdout, stderr } = await execAsync(command, options);
|
|
124
|
-
const stdoutStr = stdout?.toString() || '';
|
|
125
|
-
const stderrStr = stderr?.toString() || '';
|
|
126
|
-
const output = stdoutStr + (stderrStr ? `\n[stderr]: ${stderrStr}` : '');
|
|
127
|
-
|
|
128
|
-
return { success: true, output: output.trim() || '(command executed successfully with no output)' };
|
|
129
|
-
} catch (error: any) {
|
|
130
|
-
if (error.killed) {
|
|
131
|
-
return { success: false, error: 'Command timed out' };
|
|
132
|
-
}
|
|
133
|
-
return { success: false, error: error.message || 'Command execution failed' };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
package/src/tools/types.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool interface definitions
|
|
3
|
-
* Extracted from old src/core/types.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ==================== Tool Parameter & Schema ====================
|
|
7
|
-
|
|
8
|
-
export interface ToolParameter {
|
|
9
|
-
name: string;
|
|
10
|
-
type: string;
|
|
11
|
-
description: string;
|
|
12
|
-
required: boolean;
|
|
13
|
-
default?: any;
|
|
14
|
-
enum?: string[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ToolInputSchema {
|
|
18
|
-
type: 'object';
|
|
19
|
-
properties: Record<string, {
|
|
20
|
-
type: string;
|
|
21
|
-
description: string;
|
|
22
|
-
default?: any;
|
|
23
|
-
enum?: string[];
|
|
24
|
-
}>;
|
|
25
|
-
required?: string[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ToolMetadata {
|
|
29
|
-
permissions?: ('read' | 'write' | 'execute' | 'network')[];
|
|
30
|
-
maxDuration?: number;
|
|
31
|
-
tags?: string[];
|
|
32
|
-
version?: string;
|
|
33
|
-
deprecated?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ==================== Tool Interface ====================
|
|
37
|
-
|
|
38
|
-
export interface ToolContext {
|
|
39
|
-
sessionId?: string;
|
|
40
|
-
workingDirectory?: string;
|
|
41
|
-
confirmAction?: (msg: string) => Promise<boolean>;
|
|
42
|
-
signal?: AbortSignal;
|
|
43
|
-
toolCallId?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface ToolResult {
|
|
47
|
-
success: boolean;
|
|
48
|
-
output?: string;
|
|
49
|
-
error?: string;
|
|
50
|
-
data?: any;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface Tool {
|
|
54
|
-
name: string;
|
|
55
|
-
description: string;
|
|
56
|
-
parameters: ToolParameter[];
|
|
57
|
-
inputSchema?: ToolInputSchema;
|
|
58
|
-
metadata?: ToolMetadata;
|
|
59
|
-
execute(params: Record<string, any>, ctx?: ToolContext): Promise<ToolResult>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ==================== Tool Builder ====================
|
|
63
|
-
|
|
64
|
-
export class ToolBuilder {
|
|
65
|
-
private _name = '';
|
|
66
|
-
private _description = '';
|
|
67
|
-
private _parameters: ToolParameter[] = [];
|
|
68
|
-
private _inputSchema: ToolInputSchema = { type: 'object', properties: {} };
|
|
69
|
-
private _metadata: ToolMetadata = {};
|
|
70
|
-
private _fn?: (params: Record<string, any>, ctx: ToolContext) => Promise<ToolResult>;
|
|
71
|
-
|
|
72
|
-
name(n: string): this { this._name = n; return this; }
|
|
73
|
-
description(d: string): this { this._description = d; return this; }
|
|
74
|
-
|
|
75
|
-
param(p: ToolParameter): this {
|
|
76
|
-
this._parameters.push(p);
|
|
77
|
-
this._inputSchema.properties[p.name] = {
|
|
78
|
-
type: p.type,
|
|
79
|
-
description: p.description,
|
|
80
|
-
default: p.default,
|
|
81
|
-
enum: p.enum,
|
|
82
|
-
};
|
|
83
|
-
return this;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
stringParam(name: string, description: string, required = true, defaultVal?: string): this {
|
|
87
|
-
return this.param({ name, type: 'string', description, required, default: defaultVal });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
booleanParam(name: string, description: string, required = false, defaultVal?: boolean): this {
|
|
91
|
-
return this.param({ name, type: 'boolean', description, required, default: defaultVal });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
permissions(...perms: ('read' | 'write' | 'execute' | 'network')[]): this {
|
|
95
|
-
this._metadata.permissions = perms;
|
|
96
|
-
return this;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
tags(...t: string[]): this {
|
|
100
|
-
this._metadata.tags = t;
|
|
101
|
-
return this;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
handle(fn: (params: Record<string, any>, ctx: ToolContext) => Promise<ToolResult>): this {
|
|
105
|
-
this._fn = fn;
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
build(): Tool {
|
|
110
|
-
if (!this._name || !this._fn) {
|
|
111
|
-
throw new Error('Tool name and handler are required');
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
name: this._name,
|
|
115
|
-
description: this._description,
|
|
116
|
-
parameters: this._parameters,
|
|
117
|
-
inputSchema: this._inputSchema,
|
|
118
|
-
metadata: this._metadata,
|
|
119
|
-
execute: this._fn,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
package/src/tui/index.ts
DELETED
package/src/tui/input.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* REPL Input Handler
|
|
3
|
-
* Migrated from old src/repl/input.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import readline from 'readline';
|
|
7
|
-
import chalk from 'chalk';
|
|
8
|
-
|
|
9
|
-
export class REPLInput {
|
|
10
|
-
private rl: readline.Interface;
|
|
11
|
-
private history: string[] = [];
|
|
12
|
-
private historyIndex: number = -1;
|
|
13
|
-
|
|
14
|
-
constructor() {
|
|
15
|
-
this.rl = readline.createInterface({
|
|
16
|
-
input: process.stdin,
|
|
17
|
-
output: process.stdout,
|
|
18
|
-
completer: this.completer.bind(this),
|
|
19
|
-
historySize: 100,
|
|
20
|
-
tabSize: 4,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Handle Ctrl+C
|
|
24
|
-
this.rl.on('SIGINT', () => {
|
|
25
|
-
process.stdout.write(chalk.gray('\n\n👋 Exiting...\n'));
|
|
26
|
-
process.exit(0);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Track history
|
|
30
|
-
this.rl.on('line', (line) => {
|
|
31
|
-
if (line.trim()) {
|
|
32
|
-
this.history.push(line);
|
|
33
|
-
if (this.history.length > 100) this.history.shift();
|
|
34
|
-
}
|
|
35
|
-
this.historyIndex = this.history.length;
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async prompt(prefix: string = chalk.green('\n> ')): Promise<string> {
|
|
40
|
-
return new Promise((resolve) => {
|
|
41
|
-
this.rl.question(prefix, (answer) => {
|
|
42
|
-
resolve(answer);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
close(): void {
|
|
48
|
-
this.rl.close();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private completer(line: string): [string[], string] {
|
|
52
|
-
const commands = ['exit', 'quit', 'clear', 'help', 'tools', 'model'];
|
|
53
|
-
const hits = commands.filter(c => c.startsWith(line.toLowerCase()));
|
|
54
|
-
return [hits.length ? hits : [], line];
|
|
55
|
-
}
|
|
56
|
-
}
|
package/src/tui/output.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* REPL Output Handler
|
|
3
|
-
* Migrated from old src/repl/output.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import ora, { Ora } from 'ora';
|
|
8
|
-
|
|
9
|
-
export class REPLOutput {
|
|
10
|
-
private spinner: Ora | null = null;
|
|
11
|
-
|
|
12
|
-
printError(error: string): void {
|
|
13
|
-
console.error(chalk.red(`\n❌ Error: ${error}`));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
printWarning(warning: string): void {
|
|
17
|
-
console.warn(chalk.yellow(`\n⚠️ ${warning}`));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
printSuccess(message: string): void {
|
|
21
|
-
console.log(chalk.green(`\n✅ ${message}`));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
printInfo(message: string): void {
|
|
25
|
-
console.log(chalk.gray(message));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
printDivider(char = '─', length = 40): void {
|
|
29
|
-
console.log(chalk.gray(char.repeat(length)));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
printHeader(text: string): void {
|
|
33
|
-
this.printDivider();
|
|
34
|
-
console.log(chalk.cyan(text));
|
|
35
|
-
this.printDivider();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
startSpinner(text: string): void {
|
|
39
|
-
this.spinner = ora({ text, color: 'cyan', spinner: 'dots' }).start();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
stopSpinner(): void {
|
|
43
|
-
if (this.spinner) {
|
|
44
|
-
this.spinner.stop();
|
|
45
|
-
this.spinner = null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
stopSpinnerFail(text?: string): void {
|
|
50
|
-
if (this.spinner) {
|
|
51
|
-
this.spinner.fail(text || this.spinner.text);
|
|
52
|
-
this.spinner = null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
clear(): void {
|
|
57
|
-
console.clear();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
printBanner(): void {
|
|
61
|
-
console.log(chalk.cyan(`
|
|
62
|
-
╔═══════════════════════════════════════╗
|
|
63
|
-
║ 🤖 Thatgfsj Code v0.3.0 ║
|
|
64
|
-
║ AI Coding Assistant ║
|
|
65
|
-
╚═══════════════════════════════════════╝
|
|
66
|
-
`));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
printHelp(): void {
|
|
70
|
-
console.log(`
|
|
71
|
-
${chalk.cyan('Commands:')}
|
|
72
|
-
${chalk.gray('exit, Ctrl+C')} - Exit
|
|
73
|
-
${chalk.gray('clear')} - Clear screen
|
|
74
|
-
${chalk.gray('help')} - Show this help
|
|
75
|
-
${chalk.gray('tools')} - List available tools
|
|
76
|
-
${chalk.gray('model')} - Show current model
|
|
77
|
-
|
|
78
|
-
${chalk.cyan('Tips:')}
|
|
79
|
-
• Use ${chalk.gray('↑/↓')} for command history
|
|
80
|
-
• Use ${chalk.gray('Tab')} for auto-complete
|
|
81
|
-
`);
|
|
82
|
-
}
|
|
83
|
-
}
|
package/src/tui/repl.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* REPL - Main interactive loop
|
|
3
|
-
* Migrated from old src/repl/loop.ts + src/index.ts interactive mode
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { REPLInput } from './input.js';
|
|
8
|
-
import { REPLOutput } from './output.js';
|
|
9
|
-
import { App } from '../app/index.js';
|
|
10
|
-
import { ProjectContext } from '../utils/project.js';
|
|
11
|
-
|
|
12
|
-
export class REPL {
|
|
13
|
-
private input: REPLInput;
|
|
14
|
-
private output: REPLOutput;
|
|
15
|
-
private app: App;
|
|
16
|
-
private running = false;
|
|
17
|
-
|
|
18
|
-
constructor(app: App) {
|
|
19
|
-
this.input = new REPLInput();
|
|
20
|
-
this.output = new REPLOutput();
|
|
21
|
-
this.app = app;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Start the REPL
|
|
26
|
-
*/
|
|
27
|
-
async start(): Promise<void> {
|
|
28
|
-
this.running = true;
|
|
29
|
-
|
|
30
|
-
// Show banner
|
|
31
|
-
this.output.clear();
|
|
32
|
-
this.output.printBanner();
|
|
33
|
-
this.output.printInfo('Type "help" for available commands\n');
|
|
34
|
-
this.output.printDivider();
|
|
35
|
-
|
|
36
|
-
// Show project context
|
|
37
|
-
console.log(chalk.gray(ProjectContext.getSummary()));
|
|
38
|
-
this.output.printDivider();
|
|
39
|
-
console.log();
|
|
40
|
-
|
|
41
|
-
// Main loop
|
|
42
|
-
while (this.running) {
|
|
43
|
-
try {
|
|
44
|
-
const userInput = await this.input.prompt();
|
|
45
|
-
|
|
46
|
-
if (!userInput.trim()) continue;
|
|
47
|
-
|
|
48
|
-
// Handle commands
|
|
49
|
-
const handled = await this.handleCommand(userInput.trim());
|
|
50
|
-
if (handled) continue;
|
|
51
|
-
|
|
52
|
-
// Process with AI
|
|
53
|
-
await this.processInput(userInput.trim());
|
|
54
|
-
} catch (error: any) {
|
|
55
|
-
if (error.message === 'SIGINT') continue;
|
|
56
|
-
this.output.printError(error.message);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Handle built-in commands
|
|
63
|
-
*/
|
|
64
|
-
private async handleCommand(input: string): Promise<boolean> {
|
|
65
|
-
const cmd = input.toLowerCase();
|
|
66
|
-
|
|
67
|
-
switch (cmd) {
|
|
68
|
-
case 'exit':
|
|
69
|
-
case 'quit':
|
|
70
|
-
this.output.printInfo('\n👋 Goodbye!');
|
|
71
|
-
this.running = false;
|
|
72
|
-
this.input.close();
|
|
73
|
-
return true;
|
|
74
|
-
|
|
75
|
-
case 'clear':
|
|
76
|
-
this.output.clear();
|
|
77
|
-
this.output.printBanner();
|
|
78
|
-
return true;
|
|
79
|
-
|
|
80
|
-
case 'help':
|
|
81
|
-
this.output.printHelp();
|
|
82
|
-
return true;
|
|
83
|
-
|
|
84
|
-
case 'tools':
|
|
85
|
-
this.output.printHeader('🔧 Available Tools');
|
|
86
|
-
for (const tool of this.app.tools.list()) {
|
|
87
|
-
this.output.printInfo(` ${tool.name} - ${tool.description}`);
|
|
88
|
-
}
|
|
89
|
-
console.log();
|
|
90
|
-
return true;
|
|
91
|
-
|
|
92
|
-
case 'model':
|
|
93
|
-
this.output.printHeader('🤖 Current Model');
|
|
94
|
-
const cfg = this.app.config.get();
|
|
95
|
-
this.output.printInfo(` Provider: ${cfg.provider}`);
|
|
96
|
-
this.output.printInfo(` Model: ${cfg.model}`);
|
|
97
|
-
this.output.printInfo(` Base URL: ${cfg.baseUrl || 'default'}`);
|
|
98
|
-
console.log();
|
|
99
|
-
return true;
|
|
100
|
-
|
|
101
|
-
default:
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Process user input with AI
|
|
108
|
-
*/
|
|
109
|
-
private async processInput(input: string): Promise<void> {
|
|
110
|
-
this.app.session.addMessage('user', input);
|
|
111
|
-
|
|
112
|
-
this.output.startSpinner('Thinking...');
|
|
113
|
-
let fullResponse = '';
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const stream = this.app.getAgent().run(this.app.session.getMessages());
|
|
117
|
-
for await (const chunk of stream) {
|
|
118
|
-
this.output.stopSpinner();
|
|
119
|
-
process.stdout.write(chunk);
|
|
120
|
-
fullResponse += chunk;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
console.log(); // newline
|
|
124
|
-
|
|
125
|
-
this.app.session.addMessage('assistant', fullResponse);
|
|
126
|
-
this.app.session.truncate();
|
|
127
|
-
} catch (error: any) {
|
|
128
|
-
this.output.stopSpinnerFail(chalk.red(`Error: ${error.message}`));
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
package/src/tui/welcome.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Welcome / Setup Wizard
|
|
3
|
-
* Migrated and simplified from old src/repl/welcome.ts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import readline from 'readline';
|
|
8
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
import { homedir } from 'os';
|
|
11
|
-
import { PROVIDERS, getModelsForProvider, listProviders } from '../config/providers.js';
|
|
12
|
-
import type { ProviderName } from '../config/types.js';
|
|
13
|
-
|
|
14
|
-
export class WelcomeScreen {
|
|
15
|
-
/**
|
|
16
|
-
* Show welcome if no API key is configured
|
|
17
|
-
*/
|
|
18
|
-
static show(hasApiKey: boolean): void {
|
|
19
|
-
if (hasApiKey) return;
|
|
20
|
-
|
|
21
|
-
const w = 62;
|
|
22
|
-
console.log(chalk.cyan('+') + chalk.white.bold(' Thatgfsj Code ') + chalk.cyan('-'.repeat(w - 16)) + '+');
|
|
23
|
-
console.log(chalk.cyan('|') + chalk.yellow(' 快速开始指南').padEnd(w) + chalk.cyan('|'));
|
|
24
|
-
console.log(chalk.cyan('|') + ' '.repeat(w) + chalk.cyan('|'));
|
|
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('|'));
|
|
27
|
-
console.log(chalk.cyan('+') + '-'.repeat(w) + '+');
|
|
28
|
-
console.log();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Interactive setup wizard
|
|
33
|
-
*/
|
|
34
|
-
static async interactiveSetup(): Promise<void> {
|
|
35
|
-
console.clear();
|
|
36
|
-
console.log(chalk.cyan('\n 🤖 Thatgfsj Code 配置向导\n'));
|
|
37
|
-
|
|
38
|
-
const rl = readline.createInterface({
|
|
39
|
-
input: process.stdin,
|
|
40
|
-
output: process.stdout,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const question = (prompt: string): Promise<string> =>
|
|
44
|
-
new Promise(resolve => rl.question(prompt, answer => resolve(answer.trim())));
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
// Step 1: Choose provider
|
|
48
|
-
console.log(chalk.white(' 步骤 1/3: 选择 AI 提供商\n'));
|
|
49
|
-
const providers = listProviders();
|
|
50
|
-
providers.forEach((p, i) => {
|
|
51
|
-
console.log(chalk.green(` ${i + 1}. ${p.name}`));
|
|
52
|
-
});
|
|
53
|
-
console.log();
|
|
54
|
-
|
|
55
|
-
const choice = await question(chalk.green(' 请选择 (1-' + providers.length + '): '));
|
|
56
|
-
const selected = providers[parseInt(choice) - 1] || providers[0];
|
|
57
|
-
const providerName = selected.key;
|
|
58
|
-
|
|
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', '')}`));
|
|
62
|
-
const apiKey = await question(chalk.green(' 请输入 API Key: '));
|
|
63
|
-
|
|
64
|
-
// Step 3: Choose model
|
|
65
|
-
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
|
-
|
|
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 });
|
|
81
|
-
}
|
|
82
|
-
|
|
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
|
-
console.log(chalk.green('\n ✅ 配置已保存!'));
|
|
92
|
-
console.log(chalk.gray(` 提供商: ${providerName}`));
|
|
93
|
-
console.log(chalk.gray(` 模型: ${selectedModel.name}`));
|
|
94
|
-
console.log(chalk.gray(` 配置文件: ${configPath}`));
|
|
95
|
-
console.log(chalk.cyan('\n 运行 gfcode 开始使用\n'));
|
|
96
|
-
|
|
97
|
-
} finally {
|
|
98
|
-
rl.close();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Global shared types for Thatgfsj Code
|
|
3
|
-
* Only the most fundamental types used across modules
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
7
|
-
|
|
8
|
-
export interface ChatMessage {
|
|
9
|
-
role: Role;
|
|
10
|
-
content: string;
|
|
11
|
-
name?: string;
|
|
12
|
-
tool_calls?: ToolCall[];
|
|
13
|
-
tool_call_id?: string;
|
|
14
|
-
reasoning_content?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ToolCall {
|
|
18
|
-
id: string;
|
|
19
|
-
type: 'function';
|
|
20
|
-
function: {
|
|
21
|
-
name: string;
|
|
22
|
-
arguments: string;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ChatResponse {
|
|
27
|
-
content: string;
|
|
28
|
-
role: 'assistant';
|
|
29
|
-
usage?: {
|
|
30
|
-
prompt_tokens: number;
|
|
31
|
-
completion_tokens: number;
|
|
32
|
-
total_tokens: number;
|
|
33
|
-
};
|
|
34
|
-
tool_calls?: ToolCall[];
|
|
35
|
-
reasoning_content?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ChatOptions {
|
|
39
|
-
temperature?: number;
|
|
40
|
-
maxTokens?: number;
|
|
41
|
-
stream?: boolean;
|
|
42
|
-
}
|