codeep 1.2.16 → 1.2.18
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/README.md +20 -7
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.js +21 -17
- package/dist/renderer/App.d.ts +1 -5
- package/dist/renderer/App.js +106 -486
- package/dist/renderer/Input.js +8 -1
- package/dist/renderer/agentExecution.d.ts +36 -0
- package/dist/renderer/agentExecution.js +394 -0
- package/dist/renderer/commands.d.ts +16 -0
- package/dist/renderer/commands.js +838 -0
- package/dist/renderer/handlers.d.ts +87 -0
- package/dist/renderer/handlers.js +260 -0
- package/dist/renderer/highlight.d.ts +18 -0
- package/dist/renderer/highlight.js +130 -0
- package/dist/renderer/main.d.ts +4 -2
- package/dist/renderer/main.js +103 -1550
- package/dist/utils/agent.d.ts +5 -15
- package/dist/utils/agent.js +9 -693
- package/dist/utils/agentChat.d.ts +46 -0
- package/dist/utils/agentChat.js +343 -0
- package/dist/utils/agentStream.d.ts +23 -0
- package/dist/utils/agentStream.js +216 -0
- package/dist/utils/keychain.js +3 -2
- package/dist/utils/learning.js +9 -3
- package/dist/utils/mcpIntegration.d.ts +61 -0
- package/dist/utils/mcpIntegration.js +154 -0
- package/dist/utils/project.js +8 -3
- package/dist/utils/skills.js +21 -11
- package/dist/utils/smartContext.d.ts +4 -0
- package/dist/utils/smartContext.js +51 -14
- package/dist/utils/toolExecution.d.ts +27 -0
- package/dist/utils/toolExecution.js +525 -0
- package/dist/utils/toolParsing.d.ts +18 -0
- package/dist/utils/toolParsing.js +302 -0
- package/dist/utils/tools.d.ts +27 -24
- package/dist/utils/tools.js +30 -1169
- package/package.json +3 -1
- package/dist/config/config.test.d.ts +0 -1
- package/dist/config/config.test.js +0 -157
- package/dist/config/providers.test.d.ts +0 -1
- package/dist/config/providers.test.js +0 -187
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -4
- package/dist/hooks/useAgent.d.ts +0 -29
- package/dist/hooks/useAgent.js +0 -148
- package/dist/utils/agent.test.d.ts +0 -1
- package/dist/utils/agent.test.js +0 -315
- package/dist/utils/git.test.d.ts +0 -1
- package/dist/utils/git.test.js +0 -193
- package/dist/utils/gitignore.test.d.ts +0 -1
- package/dist/utils/gitignore.test.js +0 -167
- package/dist/utils/project.test.d.ts +0 -1
- package/dist/utils/project.test.js +0 -212
- package/dist/utils/ratelimit.test.d.ts +0 -1
- package/dist/utils/ratelimit.test.js +0 -131
- package/dist/utils/retry.test.d.ts +0 -1
- package/dist/utils/retry.test.js +0 -163
- package/dist/utils/smartContext.test.d.ts +0 -1
- package/dist/utils/smartContext.test.js +0 -382
- package/dist/utils/tools.test.d.ts +0 -1
- package/dist/utils/tools.test.js +0 -676
- package/dist/utils/validation.test.d.ts +0 -1
- package/dist/utils/validation.test.js +0 -164
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.18",
|
|
4
4
|
"description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -58,6 +58,8 @@
|
|
|
58
58
|
"files": [
|
|
59
59
|
"bin/**/*",
|
|
60
60
|
"dist/**/*",
|
|
61
|
+
"!dist/**/*.test.js",
|
|
62
|
+
"!dist/**/*.test.d.ts",
|
|
61
63
|
"README.md",
|
|
62
64
|
"LICENSE"
|
|
63
65
|
],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdirSync, rmSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
// We need to test the config functions
|
|
6
|
-
// Since config uses Conf which has side effects, we'll test the utility functions
|
|
7
|
-
describe('config utilities', () => {
|
|
8
|
-
const TEST_DIR = join(tmpdir(), 'codeep-config-test-' + Date.now());
|
|
9
|
-
const SESSIONS_DIR = join(TEST_DIR, '.codeep', 'sessions');
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
try {
|
|
15
|
-
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
16
|
-
}
|
|
17
|
-
catch { }
|
|
18
|
-
});
|
|
19
|
-
describe('session file operations', () => {
|
|
20
|
-
it('should create sessions directory structure', () => {
|
|
21
|
-
expect(existsSync(SESSIONS_DIR)).toBe(true);
|
|
22
|
-
});
|
|
23
|
-
it('should handle session JSON files', () => {
|
|
24
|
-
const sessionId = 'test-session';
|
|
25
|
-
const sessionFile = join(SESSIONS_DIR, `${sessionId}.json`);
|
|
26
|
-
const sessionData = {
|
|
27
|
-
name: sessionId,
|
|
28
|
-
history: [
|
|
29
|
-
{ role: 'user', content: 'Hello' },
|
|
30
|
-
{ role: 'assistant', content: 'Hi there!' },
|
|
31
|
-
],
|
|
32
|
-
createdAt: new Date().toISOString(),
|
|
33
|
-
};
|
|
34
|
-
writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2));
|
|
35
|
-
expect(existsSync(sessionFile)).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
describe('language codes', () => {
|
|
39
|
-
const LANGUAGES = {
|
|
40
|
-
'auto': 'Auto-detect',
|
|
41
|
-
'en': 'English',
|
|
42
|
-
'zh': 'Chinese (中文)',
|
|
43
|
-
'es': 'Spanish (Español)',
|
|
44
|
-
'hi': 'Hindi (हिन्दी)',
|
|
45
|
-
'ar': 'Arabic (العربية)',
|
|
46
|
-
'pt': 'Portuguese (Português)',
|
|
47
|
-
'fr': 'French (Français)',
|
|
48
|
-
'de': 'German (Deutsch)',
|
|
49
|
-
'ja': 'Japanese (日本語)',
|
|
50
|
-
'ru': 'Russian (Русский)',
|
|
51
|
-
'hr': 'Croatian (Hrvatski)',
|
|
52
|
-
};
|
|
53
|
-
it('should have all supported languages', () => {
|
|
54
|
-
expect(Object.keys(LANGUAGES)).toContain('auto');
|
|
55
|
-
expect(Object.keys(LANGUAGES)).toContain('en');
|
|
56
|
-
expect(Object.keys(LANGUAGES)).toContain('hr');
|
|
57
|
-
});
|
|
58
|
-
it('should have display names for all languages', () => {
|
|
59
|
-
for (const [code, name] of Object.entries(LANGUAGES)) {
|
|
60
|
-
expect(typeof name).toBe('string');
|
|
61
|
-
expect(name.length).toBeGreaterThan(0);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe('protocols', () => {
|
|
66
|
-
const PROTOCOLS = {
|
|
67
|
-
'openai': 'OpenAI Compatible',
|
|
68
|
-
'anthropic': 'Anthropic Protocol',
|
|
69
|
-
};
|
|
70
|
-
it('should support openai protocol', () => {
|
|
71
|
-
expect(PROTOCOLS['openai']).toBe('OpenAI Compatible');
|
|
72
|
-
});
|
|
73
|
-
it('should support anthropic protocol', () => {
|
|
74
|
-
expect(PROTOCOLS['anthropic']).toBe('Anthropic Protocol');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
describe('config schema validation', () => {
|
|
78
|
-
it('should have valid default values', () => {
|
|
79
|
-
const defaults = {
|
|
80
|
-
apiKey: '',
|
|
81
|
-
provider: 'z.ai',
|
|
82
|
-
model: 'glm-4.7',
|
|
83
|
-
protocol: 'openai',
|
|
84
|
-
plan: 'lite',
|
|
85
|
-
language: 'en',
|
|
86
|
-
autoSave: true,
|
|
87
|
-
currentSessionId: '',
|
|
88
|
-
temperature: 0.7,
|
|
89
|
-
maxTokens: 4096,
|
|
90
|
-
apiTimeout: 30000,
|
|
91
|
-
rateLimitApi: 30,
|
|
92
|
-
rateLimitCommands: 100,
|
|
93
|
-
projectPermissions: [],
|
|
94
|
-
providerApiKeys: [],
|
|
95
|
-
};
|
|
96
|
-
// Validate types
|
|
97
|
-
expect(typeof defaults.apiKey).toBe('string');
|
|
98
|
-
expect(typeof defaults.provider).toBe('string');
|
|
99
|
-
expect(typeof defaults.model).toBe('string');
|
|
100
|
-
expect(['openai', 'anthropic']).toContain(defaults.protocol);
|
|
101
|
-
expect(['lite', 'pro', 'max']).toContain(defaults.plan);
|
|
102
|
-
expect(typeof defaults.autoSave).toBe('boolean');
|
|
103
|
-
expect(typeof defaults.temperature).toBe('number');
|
|
104
|
-
expect(defaults.temperature).toBeGreaterThanOrEqual(0);
|
|
105
|
-
expect(defaults.temperature).toBeLessThanOrEqual(2);
|
|
106
|
-
expect(typeof defaults.maxTokens).toBe('number');
|
|
107
|
-
expect(defaults.maxTokens).toBeGreaterThan(0);
|
|
108
|
-
expect(typeof defaults.apiTimeout).toBe('number');
|
|
109
|
-
expect(defaults.apiTimeout).toBeGreaterThan(0);
|
|
110
|
-
expect(typeof defaults.rateLimitApi).toBe('number');
|
|
111
|
-
expect(typeof defaults.rateLimitCommands).toBe('number');
|
|
112
|
-
expect(Array.isArray(defaults.projectPermissions)).toBe(true);
|
|
113
|
-
expect(Array.isArray(defaults.providerApiKeys)).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
describe('project permissions structure', () => {
|
|
117
|
-
it('should validate permission structure', () => {
|
|
118
|
-
const permission = {
|
|
119
|
-
path: '/Users/test/project',
|
|
120
|
-
readPermission: true,
|
|
121
|
-
writePermission: false,
|
|
122
|
-
grantedAt: new Date().toISOString(),
|
|
123
|
-
};
|
|
124
|
-
expect(typeof permission.path).toBe('string');
|
|
125
|
-
expect(typeof permission.readPermission).toBe('boolean');
|
|
126
|
-
expect(typeof permission.writePermission).toBe('boolean');
|
|
127
|
-
expect(typeof permission.grantedAt).toBe('string');
|
|
128
|
-
// Validate ISO date string
|
|
129
|
-
expect(() => new Date(permission.grantedAt)).not.toThrow();
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
describe('provider API keys structure', () => {
|
|
133
|
-
it('should validate API key structure', () => {
|
|
134
|
-
const apiKey = {
|
|
135
|
-
providerId: 'z.ai',
|
|
136
|
-
apiKey: 'test-api-key-123',
|
|
137
|
-
};
|
|
138
|
-
expect(typeof apiKey.providerId).toBe('string');
|
|
139
|
-
expect(typeof apiKey.apiKey).toBe('string');
|
|
140
|
-
expect(apiKey.providerId.length).toBeGreaterThan(0);
|
|
141
|
-
expect(apiKey.apiKey.length).toBeGreaterThan(0);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
describe('message structure', () => {
|
|
145
|
-
it('should validate message structure', () => {
|
|
146
|
-
const userMessage = { role: 'user', content: 'Hello' };
|
|
147
|
-
const assistantMessage = { role: 'assistant', content: 'Hi!' };
|
|
148
|
-
const systemMessage = { role: 'system', content: 'You are a helpful assistant' };
|
|
149
|
-
expect(['user', 'assistant', 'system']).toContain(userMessage.role);
|
|
150
|
-
expect(['user', 'assistant', 'system']).toContain(assistantMessage.role);
|
|
151
|
-
expect(['user', 'assistant', 'system']).toContain(systemMessage.role);
|
|
152
|
-
expect(typeof userMessage.content).toBe('string');
|
|
153
|
-
expect(typeof assistantMessage.content).toBe('string');
|
|
154
|
-
expect(typeof systemMessage.content).toBe('string');
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { PROVIDERS, getProvider, getProviderList, getProviderModels, getProviderBaseUrl, getProviderAuthHeader, getProviderMcpEndpoints, } from './providers.js';
|
|
3
|
-
describe('providers', () => {
|
|
4
|
-
describe('PROVIDERS constant', () => {
|
|
5
|
-
it('should have z.ai provider', () => {
|
|
6
|
-
expect(PROVIDERS['z.ai']).toBeDefined();
|
|
7
|
-
expect(PROVIDERS['z.ai'].name).toBe('Z.AI (ZhipuAI)');
|
|
8
|
-
});
|
|
9
|
-
it('should have z.ai-cn provider', () => {
|
|
10
|
-
expect(PROVIDERS['z.ai-cn']).toBeDefined();
|
|
11
|
-
expect(PROVIDERS['z.ai-cn'].name).toBe('Z.AI China (ZhipuAI)');
|
|
12
|
-
});
|
|
13
|
-
it('should have minimax provider', () => {
|
|
14
|
-
expect(PROVIDERS['minimax']).toBeDefined();
|
|
15
|
-
expect(PROVIDERS['minimax'].name).toBe('MiniMax');
|
|
16
|
-
});
|
|
17
|
-
it('should have valid structure for all providers', () => {
|
|
18
|
-
for (const [id, provider] of Object.entries(PROVIDERS)) {
|
|
19
|
-
expect(provider.name).toBeDefined();
|
|
20
|
-
expect(typeof provider.name).toBe('string');
|
|
21
|
-
expect(provider.description).toBeDefined();
|
|
22
|
-
expect(provider.protocols).toBeDefined();
|
|
23
|
-
expect(provider.models).toBeDefined();
|
|
24
|
-
expect(Array.isArray(provider.models)).toBe(true);
|
|
25
|
-
expect(provider.models.length).toBeGreaterThan(0);
|
|
26
|
-
expect(provider.defaultModel).toBeDefined();
|
|
27
|
-
expect(provider.defaultProtocol).toBeDefined();
|
|
28
|
-
expect(['openai', 'anthropic']).toContain(provider.defaultProtocol);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
it('should have valid model structure', () => {
|
|
32
|
-
for (const provider of Object.values(PROVIDERS)) {
|
|
33
|
-
for (const model of provider.models) {
|
|
34
|
-
expect(model.id).toBeDefined();
|
|
35
|
-
expect(typeof model.id).toBe('string');
|
|
36
|
-
expect(model.name).toBeDefined();
|
|
37
|
-
expect(typeof model.name).toBe('string');
|
|
38
|
-
expect(model.description).toBeDefined();
|
|
39
|
-
expect(typeof model.description).toBe('string');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
it('should have default model in models list', () => {
|
|
44
|
-
for (const provider of Object.values(PROVIDERS)) {
|
|
45
|
-
const modelIds = provider.models.map(m => m.id);
|
|
46
|
-
expect(modelIds).toContain(provider.defaultModel);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe('getProvider', () => {
|
|
51
|
-
it('should return provider config for valid id', () => {
|
|
52
|
-
const provider = getProvider('z.ai');
|
|
53
|
-
expect(provider).not.toBeNull();
|
|
54
|
-
expect(provider.name).toBe('Z.AI (ZhipuAI)');
|
|
55
|
-
});
|
|
56
|
-
it('should return null for invalid id', () => {
|
|
57
|
-
expect(getProvider('nonexistent')).toBeNull();
|
|
58
|
-
expect(getProvider('')).toBeNull();
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
describe('getProviderList', () => {
|
|
62
|
-
it('should return list of providers', () => {
|
|
63
|
-
const list = getProviderList();
|
|
64
|
-
expect(Array.isArray(list)).toBe(true);
|
|
65
|
-
expect(list.length).toBeGreaterThan(0);
|
|
66
|
-
});
|
|
67
|
-
it('should include id, name, and description', () => {
|
|
68
|
-
const list = getProviderList();
|
|
69
|
-
for (const item of list) {
|
|
70
|
-
expect(item.id).toBeDefined();
|
|
71
|
-
expect(item.name).toBeDefined();
|
|
72
|
-
expect(item.description).toBeDefined();
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
it('should include z.ai, z.ai-cn, minimax, minimax-cn, and anthropic', () => {
|
|
76
|
-
const list = getProviderList();
|
|
77
|
-
const ids = list.map(p => p.id);
|
|
78
|
-
expect(ids).toContain('z.ai');
|
|
79
|
-
expect(ids).toContain('z.ai-cn');
|
|
80
|
-
expect(ids).toContain('minimax');
|
|
81
|
-
expect(ids).toContain('minimax-cn');
|
|
82
|
-
expect(ids).toContain('anthropic');
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
describe('getProviderModels', () => {
|
|
86
|
-
it('should return models for valid provider', () => {
|
|
87
|
-
const models = getProviderModels('z.ai');
|
|
88
|
-
expect(Array.isArray(models)).toBe(true);
|
|
89
|
-
expect(models.length).toBeGreaterThan(0);
|
|
90
|
-
});
|
|
91
|
-
it('should return empty array for invalid provider', () => {
|
|
92
|
-
const models = getProviderModels('nonexistent');
|
|
93
|
-
expect(Array.isArray(models)).toBe(true);
|
|
94
|
-
expect(models.length).toBe(0);
|
|
95
|
-
});
|
|
96
|
-
it('should include glm-4.7 for z.ai', () => {
|
|
97
|
-
const models = getProviderModels('z.ai');
|
|
98
|
-
const ids = models.map(m => m.id);
|
|
99
|
-
expect(ids).toContain('glm-4.7');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
describe('getProviderBaseUrl', () => {
|
|
103
|
-
it('should return base URL for valid provider and protocol', () => {
|
|
104
|
-
const url = getProviderBaseUrl('z.ai', 'openai');
|
|
105
|
-
expect(url).not.toBeNull();
|
|
106
|
-
expect(url).toContain('api.z.ai');
|
|
107
|
-
});
|
|
108
|
-
it('should return different URLs for different protocols', () => {
|
|
109
|
-
const openaiUrl = getProviderBaseUrl('z.ai', 'openai');
|
|
110
|
-
const anthropicUrl = getProviderBaseUrl('z.ai', 'anthropic');
|
|
111
|
-
expect(openaiUrl).not.toBe(anthropicUrl);
|
|
112
|
-
});
|
|
113
|
-
it('should return null for invalid provider', () => {
|
|
114
|
-
expect(getProviderBaseUrl('nonexistent', 'openai')).toBeNull();
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
describe('getProviderAuthHeader', () => {
|
|
118
|
-
it('should return auth header for valid provider', () => {
|
|
119
|
-
const header = getProviderAuthHeader('z.ai', 'openai');
|
|
120
|
-
expect(['Bearer', 'x-api-key']).toContain(header);
|
|
121
|
-
});
|
|
122
|
-
it('should return Bearer as default for invalid provider', () => {
|
|
123
|
-
expect(getProviderAuthHeader('nonexistent', 'openai')).toBe('Bearer');
|
|
124
|
-
});
|
|
125
|
-
it('should return correct header for each protocol', () => {
|
|
126
|
-
// z.ai uses Bearer for openai and x-api-key for anthropic
|
|
127
|
-
expect(getProviderAuthHeader('z.ai', 'openai')).toBe('Bearer');
|
|
128
|
-
expect(getProviderAuthHeader('z.ai', 'anthropic')).toBe('x-api-key');
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
describe('environment variable keys', () => {
|
|
132
|
-
it('should have env key for z.ai', () => {
|
|
133
|
-
expect(PROVIDERS['z.ai'].envKey).toBe('ZAI_API_KEY');
|
|
134
|
-
});
|
|
135
|
-
it('should have env key for z.ai-cn', () => {
|
|
136
|
-
expect(PROVIDERS['z.ai-cn'].envKey).toBe('ZAI_CN_API_KEY');
|
|
137
|
-
});
|
|
138
|
-
it('should have env key for minimax', () => {
|
|
139
|
-
expect(PROVIDERS['minimax'].envKey).toBe('MINIMAX_API_KEY');
|
|
140
|
-
});
|
|
141
|
-
it('should have env key for minimax-cn', () => {
|
|
142
|
-
expect(PROVIDERS['minimax-cn'].envKey).toBe('MINIMAX_CN_API_KEY');
|
|
143
|
-
});
|
|
144
|
-
it('should have env key for anthropic', () => {
|
|
145
|
-
expect(PROVIDERS['anthropic'].envKey).toBe('ANTHROPIC_API_KEY');
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
describe('minimax-cn provider', () => {
|
|
149
|
-
it('should have correct name and endpoints', () => {
|
|
150
|
-
expect(PROVIDERS['minimax-cn']).toBeDefined();
|
|
151
|
-
expect(PROVIDERS['minimax-cn'].name).toBe('MiniMax China');
|
|
152
|
-
expect(getProviderBaseUrl('minimax-cn', 'openai')).toContain('api.minimaxi.com');
|
|
153
|
-
expect(getProviderBaseUrl('minimax-cn', 'anthropic')).toContain('api.minimaxi.com');
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
describe('anthropic provider', () => {
|
|
157
|
-
it('should include Claude Sonnet 4.6 as default model', () => {
|
|
158
|
-
expect(PROVIDERS['anthropic'].defaultModel).toBe('claude-sonnet-4-6');
|
|
159
|
-
const modelIds = PROVIDERS['anthropic'].models.map(m => m.id);
|
|
160
|
-
expect(modelIds).toContain('claude-sonnet-4-6');
|
|
161
|
-
expect(modelIds).toContain('claude-opus-4-6');
|
|
162
|
-
expect(modelIds).toContain('claude-sonnet-4-5-20250929');
|
|
163
|
-
expect(modelIds).toContain('claude-haiku-4-5-20251001');
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
describe('MCP endpoints', () => {
|
|
167
|
-
it('should have MCP endpoints for z.ai', () => {
|
|
168
|
-
const endpoints = getProviderMcpEndpoints('z.ai');
|
|
169
|
-
expect(endpoints).not.toBeNull();
|
|
170
|
-
expect(endpoints.webSearch).toContain('api.z.ai');
|
|
171
|
-
expect(endpoints.webReader).toContain('api.z.ai');
|
|
172
|
-
expect(endpoints.zread).toContain('api.z.ai');
|
|
173
|
-
});
|
|
174
|
-
it('should have MCP endpoints for z.ai-cn', () => {
|
|
175
|
-
const endpoints = getProviderMcpEndpoints('z.ai-cn');
|
|
176
|
-
expect(endpoints).not.toBeNull();
|
|
177
|
-
expect(endpoints.webSearch).toContain('open.bigmodel.cn');
|
|
178
|
-
expect(endpoints.webReader).toContain('open.bigmodel.cn');
|
|
179
|
-
expect(endpoints.zread).toContain('open.bigmodel.cn');
|
|
180
|
-
});
|
|
181
|
-
it('should return null for providers without MCP endpoints', () => {
|
|
182
|
-
expect(getProviderMcpEndpoints('minimax')).toBeNull();
|
|
183
|
-
expect(getProviderMcpEndpoints('deepseek')).toBeNull();
|
|
184
|
-
expect(getProviderMcpEndpoints('nonexistent')).toBeNull();
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
});
|
package/dist/hooks/index.d.ts
DELETED
package/dist/hooks/index.js
DELETED
package/dist/hooks/useAgent.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useAgent hook - isolates agent state management from main App
|
|
3
|
-
* Reduces re-renders in App component when agent state changes
|
|
4
|
-
*/
|
|
5
|
-
import { AgentResult } from '../utils/agent';
|
|
6
|
-
import { ActionLog } from '../utils/tools';
|
|
7
|
-
import { ProjectContext } from '../utils/project';
|
|
8
|
-
import { Message } from '../config/index';
|
|
9
|
-
interface UseAgentOptions {
|
|
10
|
-
projectContext: ProjectContext | null;
|
|
11
|
-
hasWriteAccess: boolean;
|
|
12
|
-
messages: Message[];
|
|
13
|
-
projectPath: string;
|
|
14
|
-
onMessageAdd: (message: Message) => void;
|
|
15
|
-
notify: (msg: string, duration?: number) => void;
|
|
16
|
-
}
|
|
17
|
-
interface UseAgentReturn {
|
|
18
|
-
isAgentRunning: boolean;
|
|
19
|
-
agentIteration: number;
|
|
20
|
-
agentActions: ActionLog[];
|
|
21
|
-
agentThinking: string;
|
|
22
|
-
agentResult: AgentResult | null;
|
|
23
|
-
agentDryRun: boolean;
|
|
24
|
-
startAgent: (prompt: string, dryRun?: boolean) => Promise<void>;
|
|
25
|
-
stopAgent: () => void;
|
|
26
|
-
clearAgentState: () => void;
|
|
27
|
-
}
|
|
28
|
-
export declare function useAgent({ projectContext, hasWriteAccess, messages, projectPath, onMessageAdd, notify, }: UseAgentOptions): UseAgentReturn;
|
|
29
|
-
export default useAgent;
|
package/dist/hooks/useAgent.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useAgent hook - isolates agent state management from main App
|
|
3
|
-
* Reduces re-renders in App component when agent state changes
|
|
4
|
-
*/
|
|
5
|
-
import { useState, useCallback, useRef } from 'react';
|
|
6
|
-
import { runAgent, formatAgentResult } from '../utils/agent.js';
|
|
7
|
-
import { createActionLog } from '../utils/tools.js';
|
|
8
|
-
import { autoSaveSession } from '../config/index.js';
|
|
9
|
-
export function useAgent({ projectContext, hasWriteAccess, messages, projectPath, onMessageAdd, notify, }) {
|
|
10
|
-
const [isAgentRunning, setIsAgentRunning] = useState(false);
|
|
11
|
-
const [agentIteration, setAgentIteration] = useState(0);
|
|
12
|
-
const [agentActions, setAgentActions] = useState([]);
|
|
13
|
-
const [agentThinking, setAgentThinking] = useState('');
|
|
14
|
-
const [agentResult, setAgentResult] = useState(null);
|
|
15
|
-
const [agentDryRun, setAgentDryRun] = useState(false);
|
|
16
|
-
const abortControllerRef = useRef(null);
|
|
17
|
-
const clearAgentState = useCallback(() => {
|
|
18
|
-
setAgentResult(null);
|
|
19
|
-
setAgentActions([]);
|
|
20
|
-
setAgentThinking('');
|
|
21
|
-
setAgentIteration(0);
|
|
22
|
-
}, []);
|
|
23
|
-
const stopAgent = useCallback(() => {
|
|
24
|
-
abortControllerRef.current?.abort();
|
|
25
|
-
}, []);
|
|
26
|
-
const startAgent = useCallback(async (prompt, dryRun = false) => {
|
|
27
|
-
if (!projectContext) {
|
|
28
|
-
notify('Agent mode requires project context. Run in a project directory.');
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (!hasWriteAccess && !dryRun) {
|
|
32
|
-
notify('Agent mode requires write access. Grant permission first or use /agent-dry');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
// Reset agent state
|
|
36
|
-
setIsAgentRunning(true);
|
|
37
|
-
setAgentIteration(0);
|
|
38
|
-
setAgentActions([]);
|
|
39
|
-
setAgentThinking('');
|
|
40
|
-
setAgentResult(null);
|
|
41
|
-
setAgentDryRun(dryRun);
|
|
42
|
-
// Add user message
|
|
43
|
-
const userMessage = {
|
|
44
|
-
role: 'user',
|
|
45
|
-
content: dryRun ? `[DRY RUN] ${prompt}` : `[AGENT] ${prompt}`
|
|
46
|
-
};
|
|
47
|
-
onMessageAdd(userMessage);
|
|
48
|
-
const controller = new AbortController();
|
|
49
|
-
abortControllerRef.current = controller;
|
|
50
|
-
try {
|
|
51
|
-
const result = await runAgent(prompt, projectContext, {
|
|
52
|
-
dryRun,
|
|
53
|
-
onIteration: (iteration) => {
|
|
54
|
-
setAgentIteration(iteration);
|
|
55
|
-
},
|
|
56
|
-
onToolCall: (tool) => {
|
|
57
|
-
const toolName = tool.tool.toLowerCase().replace(/-/g, '_');
|
|
58
|
-
let details;
|
|
59
|
-
if (toolName === 'write_file' && tool.parameters.content) {
|
|
60
|
-
details = tool.parameters.content;
|
|
61
|
-
}
|
|
62
|
-
else if (toolName === 'edit_file' && tool.parameters.new_text) {
|
|
63
|
-
details = tool.parameters.new_text;
|
|
64
|
-
}
|
|
65
|
-
const actionLog = {
|
|
66
|
-
type: toolName === 'write_file' ? 'write' :
|
|
67
|
-
toolName === 'edit_file' ? 'edit' :
|
|
68
|
-
toolName === 'read_file' ? 'read' :
|
|
69
|
-
toolName === 'delete_file' ? 'delete' :
|
|
70
|
-
toolName === 'execute_command' ? 'command' :
|
|
71
|
-
toolName === 'search_code' ? 'search' :
|
|
72
|
-
toolName === 'list_files' ? 'list' :
|
|
73
|
-
toolName === 'create_directory' ? 'mkdir' :
|
|
74
|
-
toolName === 'fetch_url' ? 'fetch' : 'command',
|
|
75
|
-
target: tool.parameters.path ||
|
|
76
|
-
tool.parameters.command ||
|
|
77
|
-
tool.parameters.pattern ||
|
|
78
|
-
tool.parameters.url || 'unknown',
|
|
79
|
-
result: 'success',
|
|
80
|
-
details,
|
|
81
|
-
timestamp: Date.now(),
|
|
82
|
-
};
|
|
83
|
-
setAgentActions(prev => [...prev, actionLog]);
|
|
84
|
-
},
|
|
85
|
-
onToolResult: (result, toolCall) => {
|
|
86
|
-
const actionLog = createActionLog(toolCall, result);
|
|
87
|
-
setAgentActions(prev => {
|
|
88
|
-
const updated = [...prev];
|
|
89
|
-
if (updated.length > 0) {
|
|
90
|
-
updated[updated.length - 1] = actionLog;
|
|
91
|
-
}
|
|
92
|
-
return updated;
|
|
93
|
-
});
|
|
94
|
-
},
|
|
95
|
-
onThinking: (text) => {
|
|
96
|
-
const cleanText = text
|
|
97
|
-
.replace(/<think>[\s\S]*?<\/think>/gi, '')
|
|
98
|
-
.replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
|
|
99
|
-
.replace(/<toolcall>[\s\S]*?<\/toolcall>/gi, '')
|
|
100
|
-
.trim();
|
|
101
|
-
if (cleanText) {
|
|
102
|
-
setAgentThinking(prev => prev + cleanText);
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
abortSignal: controller.signal,
|
|
106
|
-
});
|
|
107
|
-
setAgentResult(result);
|
|
108
|
-
// Add agent summary as assistant message
|
|
109
|
-
const summaryMessage = {
|
|
110
|
-
role: 'assistant',
|
|
111
|
-
content: result.finalResponse || formatAgentResult(result),
|
|
112
|
-
};
|
|
113
|
-
onMessageAdd(summaryMessage);
|
|
114
|
-
// Auto-save session
|
|
115
|
-
autoSaveSession([...messages, userMessage, summaryMessage], projectPath);
|
|
116
|
-
if (result.success) {
|
|
117
|
-
notify(`Agent completed: ${result.actions.length} action(s)`);
|
|
118
|
-
}
|
|
119
|
-
else if (result.aborted) {
|
|
120
|
-
notify('Agent stopped by user');
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
notify(`Agent failed: ${result.error}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
const err = error;
|
|
128
|
-
notify(`Agent error: ${err.message}`);
|
|
129
|
-
}
|
|
130
|
-
finally {
|
|
131
|
-
setIsAgentRunning(false);
|
|
132
|
-
abortControllerRef.current = null;
|
|
133
|
-
setAgentThinking('');
|
|
134
|
-
}
|
|
135
|
-
}, [projectContext, hasWriteAccess, messages, projectPath, onMessageAdd, notify]);
|
|
136
|
-
return {
|
|
137
|
-
isAgentRunning,
|
|
138
|
-
agentIteration,
|
|
139
|
-
agentActions,
|
|
140
|
-
agentThinking,
|
|
141
|
-
agentResult,
|
|
142
|
-
agentDryRun,
|
|
143
|
-
startAgent,
|
|
144
|
-
stopAgent,
|
|
145
|
-
clearAgentState,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
export default useAgent;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|