@hanzo/dev 2.1.1 → 3.0.2
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 +278 -279
- package/bin/dev.js +413 -0
- package/package.json +32 -61
- package/postinstall.js +513 -0
- package/scripts/preinstall.js +69 -0
- package/scripts/windows-cleanup.ps1 +31 -0
- package/.eslintrc.json +0 -24
- package/dist/cli/dev.js +0 -24746
- package/src/cli/dev.ts +0 -946
- package/src/lib/agent-loop.ts +0 -552
- package/src/lib/benchmark-runner.ts +0 -431
- package/src/lib/code-act-agent.ts +0 -378
- package/src/lib/config.ts +0 -163
- package/src/lib/editor.ts +0 -395
- package/src/lib/function-calling.ts +0 -318
- package/src/lib/mcp-client.ts +0 -259
- package/src/lib/peer-agent-network.ts +0 -584
- package/src/lib/swarm-runner.ts +0 -389
- package/src/lib/unified-workspace.ts +0 -435
- package/test-swarm/file1.js +0 -6
- package/test-swarm/file2.ts +0 -12
- package/test-swarm/file3.py +0 -15
- package/test-swarm/file4.md +0 -13
- package/test-swarm/file5.json +0 -12
- package/test-swarm-demo.sh +0 -22
- package/tests/browser-integration.test.ts +0 -242
- package/tests/code-act-agent.test.ts +0 -305
- package/tests/editor.test.ts +0 -223
- package/tests/fixtures/sample-code.js +0 -13
- package/tests/fixtures/sample-code.py +0 -28
- package/tests/fixtures/sample-code.ts +0 -22
- package/tests/mcp-client.test.ts +0 -238
- package/tests/peer-agent-network.test.ts +0 -340
- package/tests/swarm-runner.test.ts +0 -301
- package/tests/swe-bench.test.ts +0 -357
- package/tsconfig.cli.json +0 -25
- package/tsconfig.json +0 -35
- package/vitest.config.ts +0 -37
package/src/lib/mcp-client.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { spawn, ChildProcess } from 'child_process';
|
|
2
|
-
import WebSocket from 'ws';
|
|
3
|
-
import { EventEmitter } from 'events';
|
|
4
|
-
|
|
5
|
-
export interface MCPTool {
|
|
6
|
-
name: string;
|
|
7
|
-
description: string;
|
|
8
|
-
inputSchema: any;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface MCPSession {
|
|
12
|
-
id: string;
|
|
13
|
-
transport: 'stdio' | 'websocket';
|
|
14
|
-
tools: MCPTool[];
|
|
15
|
-
client: MCPClient;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface MCPServerConfig {
|
|
19
|
-
name: string;
|
|
20
|
-
command?: string;
|
|
21
|
-
args?: string[];
|
|
22
|
-
env?: Record<string, string>;
|
|
23
|
-
url?: string; // For websocket connections
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class MCPClient extends EventEmitter {
|
|
27
|
-
private sessions: Map<string, MCPSession> = new Map();
|
|
28
|
-
private processes: Map<string, ChildProcess> = new Map();
|
|
29
|
-
private websockets: Map<string, WebSocket> = new Map();
|
|
30
|
-
|
|
31
|
-
async connect(config: MCPServerConfig): Promise<MCPSession> {
|
|
32
|
-
const sessionId = this.generateSessionId();
|
|
33
|
-
|
|
34
|
-
if (config.url) {
|
|
35
|
-
// WebSocket connection
|
|
36
|
-
return this.connectWebSocket(sessionId, config);
|
|
37
|
-
} else if (config.command) {
|
|
38
|
-
// Stdio connection
|
|
39
|
-
return this.connectStdio(sessionId, config);
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error('Either url or command must be specified');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private async connectStdio(sessionId: string, config: MCPServerConfig): Promise<MCPSession> {
|
|
46
|
-
return new Promise((resolve, reject) => {
|
|
47
|
-
const proc = spawn(config.command!, config.args || [], {
|
|
48
|
-
env: { ...process.env, ...config.env },
|
|
49
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
this.processes.set(sessionId, proc);
|
|
53
|
-
|
|
54
|
-
let buffer = '';
|
|
55
|
-
let tools: MCPTool[] = [];
|
|
56
|
-
|
|
57
|
-
proc.stdout?.on('data', (data) => {
|
|
58
|
-
buffer += data.toString();
|
|
59
|
-
const lines = buffer.split('\n');
|
|
60
|
-
buffer = lines.pop() || '';
|
|
61
|
-
|
|
62
|
-
for (const line of lines) {
|
|
63
|
-
if (line.trim()) {
|
|
64
|
-
try {
|
|
65
|
-
const msg = JSON.parse(line);
|
|
66
|
-
if (msg.type === 'tools') {
|
|
67
|
-
tools = msg.tools;
|
|
68
|
-
const session: MCPSession = {
|
|
69
|
-
id: sessionId,
|
|
70
|
-
transport: 'stdio',
|
|
71
|
-
tools,
|
|
72
|
-
client: this
|
|
73
|
-
};
|
|
74
|
-
this.sessions.set(sessionId, session);
|
|
75
|
-
resolve(session);
|
|
76
|
-
} else if (msg.type === 'result') {
|
|
77
|
-
this.emit(`result:${sessionId}`, msg);
|
|
78
|
-
} else if (msg.type === 'error') {
|
|
79
|
-
this.emit(`error:${sessionId}`, msg);
|
|
80
|
-
}
|
|
81
|
-
} catch (e) {
|
|
82
|
-
// Ignore parse errors
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
proc.stderr?.on('data', (data) => {
|
|
89
|
-
console.error(`MCP stderr: ${data}`);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
proc.on('error', (error) => {
|
|
93
|
-
reject(error);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
proc.on('exit', (code) => {
|
|
97
|
-
this.processes.delete(sessionId);
|
|
98
|
-
this.sessions.delete(sessionId);
|
|
99
|
-
this.emit(`close:${sessionId}`, code);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Request tools list
|
|
103
|
-
proc.stdin?.write(JSON.stringify({ type: 'list_tools' }) + '\n');
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private async connectWebSocket(sessionId: string, config: MCPServerConfig): Promise<MCPSession> {
|
|
108
|
-
return new Promise((resolve, reject) => {
|
|
109
|
-
const ws = new WebSocket(config.url!);
|
|
110
|
-
this.websockets.set(sessionId, ws);
|
|
111
|
-
|
|
112
|
-
let tools: MCPTool[] = [];
|
|
113
|
-
|
|
114
|
-
ws.on('open', () => {
|
|
115
|
-
// Request tools list
|
|
116
|
-
ws.send(JSON.stringify({ type: 'list_tools' }));
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
ws.on('message', (data) => {
|
|
120
|
-
try {
|
|
121
|
-
const msg = JSON.parse(data.toString());
|
|
122
|
-
if (msg.type === 'tools') {
|
|
123
|
-
tools = msg.tools;
|
|
124
|
-
const session: MCPSession = {
|
|
125
|
-
id: sessionId,
|
|
126
|
-
transport: 'websocket',
|
|
127
|
-
tools,
|
|
128
|
-
client: this
|
|
129
|
-
};
|
|
130
|
-
this.sessions.set(sessionId, session);
|
|
131
|
-
resolve(session);
|
|
132
|
-
} else if (msg.type === 'result') {
|
|
133
|
-
this.emit(`result:${sessionId}`, msg);
|
|
134
|
-
} else if (msg.type === 'error') {
|
|
135
|
-
this.emit(`error:${sessionId}`, msg);
|
|
136
|
-
}
|
|
137
|
-
} catch (e) {
|
|
138
|
-
console.error('Failed to parse MCP message:', e);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
ws.on('error', (error) => {
|
|
143
|
-
reject(error);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
ws.on('close', () => {
|
|
147
|
-
this.websockets.delete(sessionId);
|
|
148
|
-
this.sessions.delete(sessionId);
|
|
149
|
-
this.emit(`close:${sessionId}`);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async callTool(sessionId: string, toolName: string, args: any): Promise<any> {
|
|
155
|
-
const session = this.sessions.get(sessionId);
|
|
156
|
-
if (!session) {
|
|
157
|
-
throw new Error(`Session ${sessionId} not found`);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const requestId = this.generateRequestId();
|
|
161
|
-
const request = {
|
|
162
|
-
type: 'tool_call',
|
|
163
|
-
id: requestId,
|
|
164
|
-
tool: toolName,
|
|
165
|
-
arguments: args
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
return new Promise((resolve, reject) => {
|
|
169
|
-
const timeout = setTimeout(() => {
|
|
170
|
-
reject(new Error('Tool call timeout'));
|
|
171
|
-
}, 30000);
|
|
172
|
-
|
|
173
|
-
const resultHandler = (msg: any) => {
|
|
174
|
-
if (msg.id === requestId) {
|
|
175
|
-
clearTimeout(timeout);
|
|
176
|
-
this.removeListener(`result:${sessionId}`, resultHandler);
|
|
177
|
-
this.removeListener(`error:${sessionId}`, errorHandler);
|
|
178
|
-
resolve(msg.result);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const errorHandler = (msg: any) => {
|
|
183
|
-
if (msg.id === requestId) {
|
|
184
|
-
clearTimeout(timeout);
|
|
185
|
-
this.removeListener(`result:${sessionId}`, resultHandler);
|
|
186
|
-
this.removeListener(`error:${sessionId}`, errorHandler);
|
|
187
|
-
reject(new Error(msg.error));
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
this.on(`result:${sessionId}`, resultHandler);
|
|
192
|
-
this.on(`error:${sessionId}`, errorHandler);
|
|
193
|
-
|
|
194
|
-
if (session.transport === 'stdio') {
|
|
195
|
-
const proc = this.processes.get(sessionId);
|
|
196
|
-
proc?.stdin?.write(JSON.stringify(request) + '\n');
|
|
197
|
-
} else {
|
|
198
|
-
const ws = this.websockets.get(sessionId);
|
|
199
|
-
ws?.send(JSON.stringify(request));
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async disconnect(sessionId: string): Promise<void> {
|
|
205
|
-
const session = this.sessions.get(sessionId);
|
|
206
|
-
if (!session) return;
|
|
207
|
-
|
|
208
|
-
if (session.transport === 'stdio') {
|
|
209
|
-
const proc = this.processes.get(sessionId);
|
|
210
|
-
proc?.kill();
|
|
211
|
-
} else {
|
|
212
|
-
const ws = this.websockets.get(sessionId);
|
|
213
|
-
ws?.close();
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
this.sessions.delete(sessionId);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
getSession(sessionId: string): MCPSession | undefined {
|
|
220
|
-
return this.sessions.get(sessionId);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
getAllSessions(): MCPSession[] {
|
|
224
|
-
return Array.from(this.sessions.values());
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
private generateSessionId(): string {
|
|
228
|
-
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
private generateRequestId(): string {
|
|
232
|
-
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Default MCP server configurations
|
|
237
|
-
export const DEFAULT_MCP_SERVERS: MCPServerConfig[] = [
|
|
238
|
-
{
|
|
239
|
-
name: 'filesystem',
|
|
240
|
-
command: 'npx',
|
|
241
|
-
args: ['@modelcontextprotocol/server-filesystem'],
|
|
242
|
-
env: {
|
|
243
|
-
MCP_ALLOWED_PATHS: process.cwd()
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
name: 'git',
|
|
248
|
-
command: 'npx',
|
|
249
|
-
args: ['@modelcontextprotocol/server-git'],
|
|
250
|
-
env: {
|
|
251
|
-
MCP_GIT_REPO: process.cwd()
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
name: 'search',
|
|
256
|
-
command: 'npx',
|
|
257
|
-
args: ['@modelcontextprotocol/server-search']
|
|
258
|
-
}
|
|
259
|
-
];
|