@hanzo/dev 1.2.0 → 2.1.0
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/.eslintrc.json +24 -0
- package/README.md +359 -0
- package/dist/cli/dev.js +21724 -602
- package/package.json +19 -4
- package/src/cli/dev.ts +623 -106
- package/src/lib/agent-loop.ts +552 -0
- package/src/lib/benchmark-runner.ts +431 -0
- package/src/lib/code-act-agent.ts +378 -0
- package/src/lib/config.ts +163 -0
- package/src/lib/editor.ts +395 -0
- package/src/lib/function-calling.ts +318 -0
- package/src/lib/mcp-client.ts +259 -0
- package/src/lib/peer-agent-network.ts +584 -0
- package/src/lib/swarm-runner.ts +379 -0
- package/src/lib/unified-workspace.ts +435 -0
- package/test-swarm/file1.js +6 -0
- package/test-swarm/file2.ts +12 -0
- package/test-swarm/file3.py +15 -0
- package/test-swarm/file4.md +13 -0
- package/test-swarm/file5.json +12 -0
- package/test-swarm-demo.sh +22 -0
- package/tests/browser-integration.test.ts +242 -0
- package/tests/code-act-agent.test.ts +305 -0
- package/tests/editor.test.ts +223 -0
- package/tests/fixtures/sample-code.js +13 -0
- package/tests/fixtures/sample-code.py +28 -0
- package/tests/fixtures/sample-code.ts +22 -0
- package/tests/mcp-client.test.ts +238 -0
- package/tests/peer-agent-network.test.ts +340 -0
- package/tests/swarm-runner.test.ts +301 -0
- package/tests/swe-bench.test.ts +357 -0
- package/tsconfig.json +13 -15
- package/vitest.config.ts +37 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { spawn, ChildProcess } from 'child_process';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { FileEditor } from './editor';
|
|
7
|
+
import { CodeActAgent } from './code-act-agent';
|
|
8
|
+
import { FunctionCallingSystem } from './function-calling';
|
|
9
|
+
import { MCPClient, MCPSession } from './mcp-client';
|
|
10
|
+
|
|
11
|
+
export interface WorkspacePane {
|
|
12
|
+
id: string;
|
|
13
|
+
type: 'shell' | 'editor' | 'browser' | 'planner' | 'output';
|
|
14
|
+
title: string;
|
|
15
|
+
content?: string;
|
|
16
|
+
active: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ShellSession {
|
|
20
|
+
id: string;
|
|
21
|
+
process: ChildProcess;
|
|
22
|
+
cwd: string;
|
|
23
|
+
history: string[];
|
|
24
|
+
output: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class UnifiedWorkspace extends EventEmitter {
|
|
28
|
+
private panes: Map<string, WorkspacePane> = new Map();
|
|
29
|
+
private shellSessions: Map<string, ShellSession> = new Map();
|
|
30
|
+
private editor: FileEditor;
|
|
31
|
+
private agent: CodeActAgent;
|
|
32
|
+
private functionCalling: FunctionCallingSystem;
|
|
33
|
+
private mcpClient: MCPClient;
|
|
34
|
+
private activePane: string = '';
|
|
35
|
+
private browserUrl: string = '';
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
super();
|
|
39
|
+
this.editor = new FileEditor();
|
|
40
|
+
this.agent = new CodeActAgent();
|
|
41
|
+
this.functionCalling = new FunctionCallingSystem();
|
|
42
|
+
this.mcpClient = new MCPClient();
|
|
43
|
+
|
|
44
|
+
// Initialize default panes
|
|
45
|
+
this.initializeDefaultPanes();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private initializeDefaultPanes(): void {
|
|
49
|
+
// Shell pane
|
|
50
|
+
this.createPane('shell', 'Shell', '');
|
|
51
|
+
|
|
52
|
+
// Editor pane
|
|
53
|
+
this.createPane('editor', 'Editor', 'No file open');
|
|
54
|
+
|
|
55
|
+
// Browser pane
|
|
56
|
+
this.createPane('browser', 'Browser', 'Browser: Ready');
|
|
57
|
+
|
|
58
|
+
// Planner pane
|
|
59
|
+
this.createPane('planner', 'Planner', 'Task planner ready');
|
|
60
|
+
|
|
61
|
+
// Output pane
|
|
62
|
+
this.createPane('output', 'Output', '');
|
|
63
|
+
|
|
64
|
+
// Set shell as active by default
|
|
65
|
+
this.setActivePane('shell');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private createPane(type: WorkspacePane['type'], title: string, content: string): void {
|
|
69
|
+
const id = `${type}-${Date.now()}`;
|
|
70
|
+
const pane: WorkspacePane = {
|
|
71
|
+
id,
|
|
72
|
+
type,
|
|
73
|
+
title,
|
|
74
|
+
content,
|
|
75
|
+
active: false
|
|
76
|
+
};
|
|
77
|
+
this.panes.set(id, pane);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setActivePane(type: WorkspacePane['type']): void {
|
|
81
|
+
// Find pane by type
|
|
82
|
+
for (const [id, pane] of this.panes) {
|
|
83
|
+
if (pane.type === type) {
|
|
84
|
+
this.activePane = id;
|
|
85
|
+
pane.active = true;
|
|
86
|
+
} else {
|
|
87
|
+
pane.active = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.emit('pane-changed', type);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Shell operations
|
|
94
|
+
async executeShellCommand(command: string): Promise<void> {
|
|
95
|
+
const shellPane = this.getPane('shell');
|
|
96
|
+
if (!shellPane) return;
|
|
97
|
+
|
|
98
|
+
// Get or create shell session
|
|
99
|
+
let session = this.getOrCreateShellSession();
|
|
100
|
+
|
|
101
|
+
// Add to history
|
|
102
|
+
session.history.push(command);
|
|
103
|
+
|
|
104
|
+
// Execute command
|
|
105
|
+
this.appendToPane('shell', `\n$ ${command}\n`);
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const result = await this.functionCalling.callFunction({
|
|
109
|
+
id: Date.now().toString(),
|
|
110
|
+
name: 'run_command',
|
|
111
|
+
arguments: { command, cwd: session.cwd }
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (result.result?.stdout) {
|
|
115
|
+
this.appendToPane('shell', result.result.stdout);
|
|
116
|
+
}
|
|
117
|
+
if (result.result?.stderr) {
|
|
118
|
+
this.appendToPane('shell', chalk.red(result.result.stderr));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Update cwd if cd command
|
|
122
|
+
if (command.startsWith('cd ')) {
|
|
123
|
+
const newDir = command.substring(3).trim();
|
|
124
|
+
session.cwd = path.resolve(session.cwd, newDir);
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.appendToPane('shell', chalk.red(`Error: ${error}`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private getOrCreateShellSession(): ShellSession {
|
|
132
|
+
const sessionId = 'main';
|
|
133
|
+
if (!this.shellSessions.has(sessionId)) {
|
|
134
|
+
const session: ShellSession = {
|
|
135
|
+
id: sessionId,
|
|
136
|
+
process: spawn('bash', [], { cwd: process.cwd() }),
|
|
137
|
+
cwd: process.cwd(),
|
|
138
|
+
history: [],
|
|
139
|
+
output: ''
|
|
140
|
+
};
|
|
141
|
+
this.shellSessions.set(sessionId, session);
|
|
142
|
+
}
|
|
143
|
+
return this.shellSessions.get(sessionId)!;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Editor operations
|
|
147
|
+
async openFile(filePath: string): Promise<void> {
|
|
148
|
+
const result = await this.editor.execute({
|
|
149
|
+
command: 'view',
|
|
150
|
+
path: filePath
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (result.success) {
|
|
154
|
+
this.updatePane('editor', result.content || '');
|
|
155
|
+
this.updatePaneTitle('editor', `Editor - ${path.basename(filePath)}`);
|
|
156
|
+
this.setActivePane('editor');
|
|
157
|
+
} else {
|
|
158
|
+
this.appendToPane('output', chalk.red(`Failed to open file: ${result.message}`));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async saveFile(filePath: string, content: string): Promise<void> {
|
|
163
|
+
fs.writeFileSync(filePath, content);
|
|
164
|
+
this.appendToPane('output', chalk.green(`✓ Saved ${filePath}`));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Browser operations
|
|
168
|
+
async navigateBrowser(url: string): Promise<void> {
|
|
169
|
+
this.browserUrl = url;
|
|
170
|
+
this.updatePane('browser', `Browser: ${url}`);
|
|
171
|
+
this.appendToPane('output', `Navigated to ${url}`);
|
|
172
|
+
|
|
173
|
+
// In a real implementation, this would use a headless browser
|
|
174
|
+
// For now, we'll just simulate
|
|
175
|
+
try {
|
|
176
|
+
const response = await fetch(url);
|
|
177
|
+
const text = await response.text();
|
|
178
|
+
const preview = text.substring(0, 500) + '...';
|
|
179
|
+
this.updatePane('browser', `URL: ${url}\n\n${preview}`);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
this.updatePane('browser', `Failed to load ${url}: ${error}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Planner operations
|
|
186
|
+
async planTask(description: string): Promise<void> {
|
|
187
|
+
this.updatePane('planner', `Planning: ${description}\n\nGenerating execution plan...`);
|
|
188
|
+
this.setActivePane('planner');
|
|
189
|
+
|
|
190
|
+
// Use the agent to plan
|
|
191
|
+
const plan = await this.generatePlan(description);
|
|
192
|
+
|
|
193
|
+
let planContent = `Task: ${description}\n\nExecution Plan:\n`;
|
|
194
|
+
plan.steps.forEach((step, i) => {
|
|
195
|
+
const parallel = plan.parallelizable[i] ? ' [can run in parallel]' : '';
|
|
196
|
+
planContent += `${i + 1}. ${step}${parallel}\n`;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
this.updatePane('planner', planContent);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private async generatePlan(description: string): Promise<{
|
|
203
|
+
steps: string[];
|
|
204
|
+
parallelizable: boolean[];
|
|
205
|
+
}> {
|
|
206
|
+
// Simplified planning logic
|
|
207
|
+
const steps: string[] = [];
|
|
208
|
+
const parallelizable: boolean[] = [];
|
|
209
|
+
|
|
210
|
+
if (description.includes('debug')) {
|
|
211
|
+
steps.push('Reproduce the issue');
|
|
212
|
+
parallelizable.push(false);
|
|
213
|
+
steps.push('Analyze error logs');
|
|
214
|
+
parallelizable.push(false);
|
|
215
|
+
steps.push('Identify root cause');
|
|
216
|
+
parallelizable.push(false);
|
|
217
|
+
steps.push('Implement fix');
|
|
218
|
+
parallelizable.push(false);
|
|
219
|
+
steps.push('Test the fix');
|
|
220
|
+
parallelizable.push(false);
|
|
221
|
+
} else if (description.includes('feature')) {
|
|
222
|
+
steps.push('Analyze requirements');
|
|
223
|
+
parallelizable.push(false);
|
|
224
|
+
steps.push('Design implementation');
|
|
225
|
+
parallelizable.push(false);
|
|
226
|
+
steps.push('Write tests');
|
|
227
|
+
parallelizable.push(true);
|
|
228
|
+
steps.push('Implement feature');
|
|
229
|
+
parallelizable.push(true);
|
|
230
|
+
steps.push('Run tests');
|
|
231
|
+
parallelizable.push(false);
|
|
232
|
+
steps.push('Update documentation');
|
|
233
|
+
parallelizable.push(true);
|
|
234
|
+
} else {
|
|
235
|
+
steps.push('Analyze task');
|
|
236
|
+
parallelizable.push(false);
|
|
237
|
+
steps.push('Execute task');
|
|
238
|
+
parallelizable.push(false);
|
|
239
|
+
steps.push('Verify results');
|
|
240
|
+
parallelizable.push(false);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { steps, parallelizable };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Execute planned task
|
|
247
|
+
async executePlan(): Promise<void> {
|
|
248
|
+
const plannerPane = this.getPane('planner');
|
|
249
|
+
if (!plannerPane || !plannerPane.content) return;
|
|
250
|
+
|
|
251
|
+
// Extract task from planner
|
|
252
|
+
const lines = plannerPane.content.split('\n');
|
|
253
|
+
const taskLine = lines.find(l => l.startsWith('Task:'));
|
|
254
|
+
if (!taskLine) return;
|
|
255
|
+
|
|
256
|
+
const task = taskLine.substring(5).trim();
|
|
257
|
+
this.appendToPane('output', chalk.cyan(`\nExecuting task: ${task}\n`));
|
|
258
|
+
|
|
259
|
+
// Execute using agent
|
|
260
|
+
await this.agent.executeTask(task);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Pane management
|
|
264
|
+
private getPane(type: WorkspacePane['type']): WorkspacePane | undefined {
|
|
265
|
+
for (const pane of this.panes.values()) {
|
|
266
|
+
if (pane.type === type) return pane;
|
|
267
|
+
}
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private updatePane(type: WorkspacePane['type'], content: string): void {
|
|
272
|
+
const pane = this.getPane(type);
|
|
273
|
+
if (pane) {
|
|
274
|
+
pane.content = content;
|
|
275
|
+
this.emit('pane-updated', type, content);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private appendToPane(type: WorkspacePane['type'], content: string): void {
|
|
280
|
+
const pane = this.getPane(type);
|
|
281
|
+
if (pane) {
|
|
282
|
+
pane.content = (pane.content || '') + content;
|
|
283
|
+
this.emit('pane-updated', type, pane.content);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private updatePaneTitle(type: WorkspacePane['type'], title: string): void {
|
|
288
|
+
const pane = this.getPane(type);
|
|
289
|
+
if (pane) {
|
|
290
|
+
pane.title = title;
|
|
291
|
+
this.emit('pane-title-updated', type, title);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Display workspace (simplified for CLI)
|
|
296
|
+
displayWorkspace(): void {
|
|
297
|
+
console.clear();
|
|
298
|
+
console.log(chalk.bold.cyan('╔══════════════════════════════════════════════════════════════╗'));
|
|
299
|
+
console.log(chalk.bold.cyan('║ 🚀 Hanzo Dev Workspace ║'));
|
|
300
|
+
console.log(chalk.bold.cyan('╚══════════════════════════════════════════════════════════════╝'));
|
|
301
|
+
console.log();
|
|
302
|
+
|
|
303
|
+
// Display pane tabs
|
|
304
|
+
const tabs: string[] = [];
|
|
305
|
+
for (const pane of this.panes.values()) {
|
|
306
|
+
const isActive = pane.id === this.activePane;
|
|
307
|
+
const tab = isActive
|
|
308
|
+
? chalk.bold.yellow(`[${pane.title}]`)
|
|
309
|
+
: chalk.gray(`[${pane.title}]`);
|
|
310
|
+
tabs.push(tab);
|
|
311
|
+
}
|
|
312
|
+
console.log(tabs.join(' '));
|
|
313
|
+
console.log(chalk.gray('─'.repeat(64)));
|
|
314
|
+
|
|
315
|
+
// Display active pane content
|
|
316
|
+
const activePane = this.panes.get(this.activePane);
|
|
317
|
+
if (activePane && activePane.content) {
|
|
318
|
+
const lines = activePane.content.split('\n');
|
|
319
|
+
const maxLines = 20;
|
|
320
|
+
const displayLines = lines.slice(-maxLines);
|
|
321
|
+
console.log(displayLines.join('\n'));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
console.log(chalk.gray('─'.repeat(64)));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Cleanup
|
|
328
|
+
async cleanup(): Promise<void> {
|
|
329
|
+
// Close shell sessions
|
|
330
|
+
for (const session of this.shellSessions.values()) {
|
|
331
|
+
session.process.kill();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Disconnect MCP sessions
|
|
335
|
+
const sessions = this.mcpClient.getAllSessions();
|
|
336
|
+
for (const session of sessions) {
|
|
337
|
+
await this.mcpClient.disconnect(session.id);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Interactive workspace session
|
|
343
|
+
export class WorkspaceSession {
|
|
344
|
+
private workspace: UnifiedWorkspace;
|
|
345
|
+
private running: boolean = true;
|
|
346
|
+
|
|
347
|
+
constructor() {
|
|
348
|
+
this.workspace = new UnifiedWorkspace();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async start(): Promise<void> {
|
|
352
|
+
console.log(chalk.bold.cyan('\n🎯 Starting Unified Workspace...\n'));
|
|
353
|
+
|
|
354
|
+
// Set up event listeners
|
|
355
|
+
this.workspace.on('pane-updated', () => {
|
|
356
|
+
if (this.running) {
|
|
357
|
+
this.workspace.displayWorkspace();
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Initial display
|
|
362
|
+
this.workspace.displayWorkspace();
|
|
363
|
+
|
|
364
|
+
// Start interactive loop
|
|
365
|
+
const readline = require('readline');
|
|
366
|
+
const rl = readline.createInterface({
|
|
367
|
+
input: process.stdin,
|
|
368
|
+
output: process.stdout
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
console.log(chalk.gray('\nCommands: shell <cmd>, edit <file>, browse <url>, plan <task>, execute, switch <pane>, exit\n'));
|
|
372
|
+
|
|
373
|
+
const prompt = () => {
|
|
374
|
+
rl.question(chalk.green('workspace> '), async (input) => {
|
|
375
|
+
if (!this.running) return;
|
|
376
|
+
|
|
377
|
+
const [cmd, ...args] = input.trim().split(' ');
|
|
378
|
+
const arg = args.join(' ');
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
switch (cmd) {
|
|
382
|
+
case 'shell':
|
|
383
|
+
case 'sh':
|
|
384
|
+
await this.workspace.executeShellCommand(arg);
|
|
385
|
+
break;
|
|
386
|
+
|
|
387
|
+
case 'edit':
|
|
388
|
+
case 'e':
|
|
389
|
+
await this.workspace.openFile(arg);
|
|
390
|
+
break;
|
|
391
|
+
|
|
392
|
+
case 'browse':
|
|
393
|
+
case 'b':
|
|
394
|
+
await this.workspace.navigateBrowser(arg);
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
case 'plan':
|
|
398
|
+
case 'p':
|
|
399
|
+
await this.workspace.planTask(arg);
|
|
400
|
+
break;
|
|
401
|
+
|
|
402
|
+
case 'execute':
|
|
403
|
+
case 'x':
|
|
404
|
+
await this.workspace.executePlan();
|
|
405
|
+
break;
|
|
406
|
+
|
|
407
|
+
case 'switch':
|
|
408
|
+
case 's':
|
|
409
|
+
this.workspace.setActivePane(arg as any);
|
|
410
|
+
this.workspace.displayWorkspace();
|
|
411
|
+
break;
|
|
412
|
+
|
|
413
|
+
case 'exit':
|
|
414
|
+
case 'quit':
|
|
415
|
+
this.running = false;
|
|
416
|
+
await this.workspace.cleanup();
|
|
417
|
+
rl.close();
|
|
418
|
+
return;
|
|
419
|
+
|
|
420
|
+
default:
|
|
421
|
+
console.log(chalk.red(`Unknown command: ${cmd}`));
|
|
422
|
+
}
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (this.running) {
|
|
428
|
+
prompt();
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
prompt();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// TypeScript utility functions
|
|
2
|
+
export function formatDate(date: Date): string {
|
|
3
|
+
return date.toISOString().split('T')[0];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function parseJSON<T>(json: string): T | null {
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(json);
|
|
9
|
+
} catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Python data processing
|
|
2
|
+
import json
|
|
3
|
+
from typing import List, Dict
|
|
4
|
+
|
|
5
|
+
def process_data(items: List[Dict]) -> Dict:
|
|
6
|
+
"""Process a list of items and return summary statistics."""
|
|
7
|
+
total = sum(item.get('value', 0) for item in items)
|
|
8
|
+
count = len(items)
|
|
9
|
+
average = total / count if count > 0 else 0
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
'total': total,
|
|
13
|
+
'count': count,
|
|
14
|
+
'average': average
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "test-project",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Test project for swarm processing",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["test", "swarm"],
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC"
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "🐝 Hanzo Dev Swarm Demo"
|
|
4
|
+
echo "======================"
|
|
5
|
+
echo ""
|
|
6
|
+
echo "This demo will add copyright headers to 5 test files in parallel"
|
|
7
|
+
echo ""
|
|
8
|
+
echo "Files before:"
|
|
9
|
+
echo "-------------"
|
|
10
|
+
head -n 1 test-swarm/*.{js,ts,py,md,json} 2>/dev/null
|
|
11
|
+
|
|
12
|
+
echo ""
|
|
13
|
+
echo "Running swarm with 5 agents..."
|
|
14
|
+
echo ""
|
|
15
|
+
|
|
16
|
+
# Run the swarm command
|
|
17
|
+
node dist/cli/dev.js --claude --swarm 5 -p "Add this copyright header at the very top of each file: '// Copyright 2025 Hanzo Industries Inc.' (use # for Python, // for JS/TS/JSON)"
|
|
18
|
+
|
|
19
|
+
echo ""
|
|
20
|
+
echo "Files after:"
|
|
21
|
+
echo "------------"
|
|
22
|
+
head -n 2 test-swarm/*.{js,ts,py,md,json} 2>/dev/null
|