agentgui 1.0.78 → 1.0.80

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/test-browser.js DELETED
@@ -1,457 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Browser Testing Harness
5
- * Manages repository cloning, Claude Code execution, and browser testing
6
- * for streaming event visualization
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
- const { execSync, spawn } = require('child_process');
12
- const os = require('os');
13
-
14
- class BrowserTestHarness {
15
- constructor(config = {}) {
16
- this.config = {
17
- baseDir: config.baseDir || path.join(os.tmpdir(), 'agentgui-test'),
18
- serverPort: config.serverPort || 3000,
19
- serverUrl: config.serverUrl || 'http://localhost:3000',
20
- baseURL: config.baseURL || '/gm',
21
- timeout: config.timeout || 30 * 60 * 1000, // 30 minutes
22
- concurrency: config.concurrency || 2,
23
- ...config
24
- };
25
-
26
- this.repos = [];
27
- this.executionLog = [];
28
- this.eventCounts = {};
29
- }
30
-
31
- /**
32
- * Initialize test environment
33
- */
34
- async init() {
35
- console.log('Initializing browser test harness');
36
-
37
- // Ensure base directory
38
- if (!fs.existsSync(this.config.baseDir)) {
39
- fs.mkdirSync(this.config.baseDir, { recursive: true });
40
- }
41
-
42
- console.log(`Test directory: ${this.config.baseDir}`);
43
- return this;
44
- }
45
-
46
- /**
47
- * Clone a repository
48
- */
49
- async cloneRepository(url, name) {
50
- console.log(`Cloning repository: ${url}`);
51
-
52
- const repoPath = path.join(this.config.baseDir, name);
53
-
54
- // Check if already cloned
55
- if (fs.existsSync(repoPath)) {
56
- console.log(`Repository already exists: ${repoPath}`);
57
- this.repos.push({
58
- url,
59
- name,
60
- path: repoPath,
61
- status: 'ready'
62
- });
63
- return repoPath;
64
- }
65
-
66
- try {
67
- execSync(`git clone --depth 1 ${url} ${repoPath}`, {
68
- stdio: 'pipe',
69
- timeout: 60000
70
- });
71
-
72
- const repo = {
73
- url,
74
- name,
75
- path: repoPath,
76
- status: 'cloned',
77
- fileCount: this.countFiles(repoPath),
78
- languages: this.detectLanguages(repoPath)
79
- };
80
-
81
- this.repos.push(repo);
82
- console.log(`Repository cloned successfully: ${repo.fileCount} files`);
83
- return repoPath;
84
- } catch (error) {
85
- console.error(`Failed to clone repository: ${error.message}`);
86
- throw error;
87
- }
88
- }
89
-
90
- /**
91
- * Count files in repository
92
- */
93
- countFiles(dirPath) {
94
- let count = 0;
95
- const walk = (dir) => {
96
- try {
97
- const files = fs.readdirSync(dir);
98
- for (const file of files) {
99
- const fullPath = path.join(dir, file);
100
- if (fs.statSync(fullPath).isDirectory()) {
101
- if (!file.startsWith('.') && file !== 'node_modules') {
102
- walk(fullPath);
103
- }
104
- } else {
105
- count++;
106
- }
107
- }
108
- } catch (e) {
109
- // Ignore
110
- }
111
- };
112
- walk(dirPath);
113
- return count;
114
- }
115
-
116
- /**
117
- * Detect languages in repository
118
- */
119
- detectLanguages(dirPath) {
120
- const langMap = {
121
- '.js': 'JavaScript',
122
- '.ts': 'TypeScript',
123
- '.tsx': 'TypeScript',
124
- '.jsx': 'JavaScript',
125
- '.py': 'Python',
126
- '.java': 'Java',
127
- '.cpp': 'C++',
128
- '.c': 'C',
129
- '.cs': 'C#',
130
- '.go': 'Go',
131
- '.rs': 'Rust',
132
- '.rb': 'Ruby',
133
- '.php': 'PHP',
134
- '.json': 'JSON'
135
- };
136
-
137
- const languages = new Set();
138
- const walk = (dir) => {
139
- try {
140
- const files = fs.readdirSync(dir);
141
- for (const file of files) {
142
- if (file.startsWith('.') || file === 'node_modules') continue;
143
- const fullPath = path.join(dir, file);
144
- if (fs.statSync(fullPath).isDirectory()) {
145
- walk(fullPath);
146
- } else {
147
- const ext = path.extname(file).toLowerCase();
148
- if (langMap[ext]) {
149
- languages.add(langMap[ext]);
150
- }
151
- }
152
- }
153
- } catch (e) {
154
- // Ignore
155
- }
156
- };
157
- walk(dirPath);
158
- return Array.from(languages);
159
- }
160
-
161
- /**
162
- * Execute Claude Code on repository
163
- */
164
- async executeClaudeCode(repoPath, command, agentId = 'claude-code') {
165
- console.log(`Executing Claude Code: ${command.substring(0, 50)}...`);
166
-
167
- const execution = {
168
- repoPath,
169
- command,
170
- agentId,
171
- startTime: Date.now(),
172
- events: [],
173
- status: 'running'
174
- };
175
-
176
- try {
177
- // Execute Claude Code with streaming output
178
- const result = await this.runClaudeCode(repoPath, command, agentId);
179
-
180
- execution.endTime = Date.now();
181
- execution.duration = execution.endTime - execution.startTime;
182
- execution.eventCount = result.events.length;
183
- execution.events = result.events;
184
- execution.status = 'completed';
185
- execution.output = result.output;
186
- execution.error = null;
187
- } catch (error) {
188
- execution.endTime = Date.now();
189
- execution.duration = execution.endTime - execution.startTime;
190
- execution.status = 'failed';
191
- execution.error = error.message;
192
- }
193
-
194
- this.executionLog.push(execution);
195
- return execution;
196
- }
197
-
198
- /**
199
- * Run Claude Code command
200
- */
201
- async runClaudeCode(cwd, command, agentId) {
202
- return new Promise((resolve, reject) => {
203
- try {
204
- const cmd = agentId === 'claude-code' ? 'claude' : 'opencode';
205
- const fullCommand = `${cmd} ${command}`;
206
-
207
- console.log(`Running: ${fullCommand} (cwd: ${cwd})`);
208
-
209
- const proc = spawn('sh', ['-c', fullCommand], {
210
- cwd,
211
- timeout: this.config.timeout,
212
- stdio: ['pipe', 'pipe', 'pipe']
213
- });
214
-
215
- let stdout = '';
216
- let stderr = '';
217
-
218
- proc.stdout.on('data', (data) => {
219
- stdout += data.toString();
220
- });
221
-
222
- proc.stderr.on('data', (data) => {
223
- stderr += data.toString();
224
- });
225
-
226
- proc.on('close', (code) => {
227
- const events = this.parseStreamingOutput(stdout + stderr);
228
-
229
- resolve({
230
- events,
231
- output: stdout,
232
- stderr,
233
- exitCode: code
234
- });
235
- });
236
-
237
- proc.on('error', (error) => {
238
- reject(error);
239
- });
240
- } catch (error) {
241
- reject(error);
242
- }
243
- });
244
- }
245
-
246
- /**
247
- * Parse streaming output to extract events
248
- */
249
- parseStreamingOutput(output) {
250
- const events = [];
251
-
252
- // Try to parse JSON stream (stream-json format)
253
- const lines = output.split('\n');
254
- for (const line of lines) {
255
- if (!line.trim()) continue;
256
- try {
257
- const json = JSON.parse(line);
258
- if (json.type) {
259
- events.push(json);
260
- this.eventCounts[json.type] = (this.eventCounts[json.type] || 0) + 1;
261
- }
262
- } catch (e) {
263
- // Not JSON, skip
264
- }
265
- }
266
-
267
- return events;
268
- }
269
-
270
- /**
271
- * Simulate browser test scenario
272
- */
273
- async testScenario(name, repoPath, command, expectedEventTypes = []) {
274
- console.log(`\n=== Test Scenario: ${name} ===`);
275
-
276
- try {
277
- const execution = await this.executeClaudeCode(repoPath, command);
278
-
279
- // Verify events
280
- const eventTypes = execution.events.map(e => e.type);
281
- const hasExpectedEvents = expectedEventTypes.every(type =>
282
- eventTypes.includes(type)
283
- );
284
-
285
- const result = {
286
- name,
287
- status: execution.status,
288
- duration: execution.duration,
289
- eventCount: execution.eventCount,
290
- eventTypes,
291
- hasExpectedEvents,
292
- passed: execution.status === 'completed' && hasExpectedEvents,
293
- error: execution.error
294
- };
295
-
296
- console.log(`Result: ${result.passed ? 'PASSED' : 'FAILED'}`);
297
- console.log(`Duration: ${(result.duration / 1000).toFixed(2)}s`);
298
- console.log(`Events: ${result.eventCount} (types: ${eventTypes.join(', ')})`);
299
-
300
- return result;
301
- } catch (error) {
302
- console.error(`Test failed with error: ${error.message}`);
303
- return {
304
- name,
305
- status: 'error',
306
- passed: false,
307
- error: error.message
308
- };
309
- }
310
- }
311
-
312
- /**
313
- * Run all test scenarios
314
- */
315
- async runAllScenarios() {
316
- console.log('\n\n=== BROWSER TEST EXECUTION ===\n');
317
-
318
- const results = [];
319
-
320
- // Clone test repositories
321
- console.log('\n--- Repository Setup ---');
322
- const repoURLs = [
323
- { url: 'https://github.com/lodash/lodash', name: 'lodash' },
324
- { url: 'https://github.com/requests/requests', name: 'requests' },
325
- { url: 'https://github.com/kubernetes/kubernetes', name: 'kubernetes' }
326
- ];
327
-
328
- for (const repo of repoURLs) {
329
- try {
330
- await this.cloneRepository(repo.url, repo.name);
331
- } catch (error) {
332
- console.error(`Failed to clone ${repo.name}: ${error.message}`);
333
- }
334
- }
335
-
336
- // Run test scenarios
337
- console.log('\n--- Test Scenarios ---');
338
-
339
- if (this.repos.length > 0) {
340
- const repo1 = this.repos[0];
341
- if (repo1.path) {
342
- // Test 1: Analyze files
343
- results.push(await this.testScenario(
344
- 'Analyze JavaScript files',
345
- repo1.path,
346
- 'ls -la | head -20',
347
- ['file_read', 'command_execute']
348
- ));
349
-
350
- // Test 2: View file structure
351
- results.push(await this.testScenario(
352
- 'Explore directory structure',
353
- repo1.path,
354
- 'find . -name "*.md" | head -10',
355
- ['command_execute']
356
- ));
357
- }
358
- }
359
-
360
- return results;
361
- }
362
-
363
- /**
364
- * Generate test report
365
- */
366
- generateReport() {
367
- const passed = this.executionLog.filter(e => e.status === 'completed').length;
368
- const failed = this.executionLog.filter(e => e.status === 'failed').length;
369
- const totalEvents = Object.values(this.eventCounts).reduce((a, b) => a + b, 0);
370
-
371
- const report = {
372
- timestamp: new Date().toISOString(),
373
- summary: {
374
- totalExecutions: this.executionLog.length,
375
- passed,
376
- failed,
377
- successRate: this.executionLog.length > 0 ? (passed / this.executionLog.length * 100).toFixed(2) + '%' : 'N/A'
378
- },
379
- repositories: this.repos.map(r => ({
380
- name: r.name,
381
- fileCount: r.fileCount,
382
- languages: r.languages,
383
- path: r.path
384
- })),
385
- events: {
386
- totalCount: totalEvents,
387
- byType: this.eventCounts
388
- },
389
- executions: this.executionLog.map(e => ({
390
- command: e.command,
391
- status: e.status,
392
- duration: `${(e.duration / 1000).toFixed(2)}s`,
393
- eventCount: e.eventCount,
394
- error: e.error
395
- }))
396
- };
397
-
398
- return report;
399
- }
400
-
401
- /**
402
- * Save report to file
403
- */
404
- saveReport(filepath) {
405
- const report = this.generateReport();
406
- fs.writeFileSync(filepath, JSON.stringify(report, null, 2));
407
- console.log(`Report saved: ${filepath}`);
408
- return report;
409
- }
410
-
411
- /**
412
- * Cleanup test environment
413
- */
414
- async cleanup() {
415
- console.log('\nCleaning up test environment...');
416
-
417
- try {
418
- if (fs.existsSync(this.config.baseDir)) {
419
- execSync(`rm -rf ${this.config.baseDir}`, { timeout: 30000 });
420
- console.log('Test directory cleaned up');
421
- }
422
- } catch (error) {
423
- console.error(`Cleanup error: ${error.message}`);
424
- }
425
- }
426
- }
427
-
428
- // CLI usage
429
- if (require.main === module) {
430
- (async () => {
431
- const harness = new BrowserTestHarness({
432
- baseDir: path.join(os.tmpdir(), 'agentgui-test-' + Date.now())
433
- });
434
-
435
- try {
436
- await harness.init();
437
- const results = await harness.runAllScenarios();
438
-
439
- // Save report
440
- const reportPath = path.join(process.cwd(), 'test-report.json');
441
- const report = harness.saveReport(reportPath);
442
-
443
- console.log('\n=== FINAL REPORT ===');
444
- console.log(JSON.stringify(report.summary, null, 2));
445
-
446
- // Cleanup
447
- await harness.cleanup();
448
-
449
- process.exit(results.every(r => r.passed) ? 0 : 1);
450
- } catch (error) {
451
- console.error('Fatal error:', error);
452
- process.exit(1);
453
- }
454
- })();
455
- }
456
-
457
- module.exports = BrowserTestHarness;
package/test-runner.js DELETED
@@ -1,182 +0,0 @@
1
- import http from 'http';
2
- import { spawn, execSync } from 'child_process';
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
-
9
- const results = {
10
- phase1: { status: 'PENDING', details: '' },
11
- phase2: { status: 'PENDING', details: '' },
12
- phase3: { status: 'PENDING', details: '' },
13
- phase4: { status: 'PENDING', details: '' },
14
- phase5: { status: 'PENDING', details: '' },
15
- phase6: { status: 'PENDING', details: '' },
16
- phase7: { status: 'PENDING', details: '' },
17
- phase8: { status: 'PENDING', details: '' },
18
- phase9: { status: 'PENDING', details: '' },
19
- };
20
-
21
- function log(phase, message) {
22
- const timestamp = new Date().toISOString();
23
- console.log(`[${timestamp}] [${phase}] ${message}`);
24
- }
25
-
26
- async function checkServerRunning() {
27
- return new Promise((resolve) => {
28
- const req = http.get('http://localhost:3000', (res) => {
29
- resolve(res.statusCode === 200 || res.statusCode === 302);
30
- res.resume();
31
- });
32
- req.on('error', () => resolve(false));
33
- });
34
- }
35
-
36
- async function startServer() {
37
- return new Promise((resolve, reject) => {
38
- log('PHASE1', 'Starting server...');
39
- const proc = spawn('node', ['server.js'], {
40
- cwd: __dirname,
41
- stdio: ['ignore', 'pipe', 'pipe'],
42
- detached: false
43
- });
44
-
45
- let serverReady = false;
46
- let output = '';
47
-
48
- proc.stdout.on('data', (chunk) => {
49
- output += chunk.toString();
50
- if (output.includes('Server running on port 3000') || output.includes('listening')) {
51
- if (!serverReady) {
52
- serverReady = true;
53
- log('PHASE1', 'Server appears to be ready, waiting for confirmation...');
54
- }
55
- }
56
- });
57
-
58
- proc.stderr.on('data', (chunk) => {
59
- console.error(`[SERVER] ${chunk.toString()}`);
60
- });
61
-
62
- setTimeout(async () => {
63
- const isRunning = await checkServerRunning();
64
- if (isRunning) {
65
- log('PHASE1', 'Server is responding to requests');
66
- resolve(proc);
67
- } else {
68
- reject(new Error('Server failed to start after timeout'));
69
- }
70
- }, 5000);
71
- });
72
- }
73
-
74
- async function cloneRepositories() {
75
- return new Promise((resolve, reject) => {
76
- log('PHASE3', 'Creating /tmp/test-repos directory');
77
- try {
78
- if (!fs.existsSync('/tmp/test-repos')) {
79
- fs.mkdirSync('/tmp/test-repos', { recursive: true });
80
- }
81
-
82
- log('PHASE3', 'Cloning lodash repository...');
83
- try {
84
- execSync('git clone https://github.com/lodash/lodash /tmp/test-repos/lodash 2>&1', {
85
- timeout: 60000,
86
- stdio: ['ignore', 'pipe', 'pipe']
87
- });
88
- log('PHASE3', 'Lodash cloned successfully');
89
- } catch (e) {
90
- log('PHASE3', `Lodash clone output: ${e.toString().substring(0, 500)}`);
91
- }
92
-
93
- log('PHASE3', 'Cloning chalk repository...');
94
- try {
95
- execSync('git clone https://github.com/chalk/chalk /tmp/test-repos/chalk 2>&1', {
96
- timeout: 60000,
97
- stdio: ['ignore', 'pipe', 'pipe']
98
- });
99
- log('PHASE3', 'Chalk cloned successfully');
100
- } catch (e) {
101
- log('PHASE3', `Chalk clone output: ${e.toString().substring(0, 500)}`);
102
- }
103
-
104
- const lodashExists = fs.existsSync('/tmp/test-repos/lodash/README.md');
105
- const chalkExists = fs.existsSync('/tmp/test-repos/chalk/README.md');
106
-
107
- if (lodashExists && chalkExists) {
108
- log('PHASE3', 'Both repositories cloned successfully');
109
- resolve({ lodashExists, chalkExists });
110
- } else {
111
- log('PHASE3', `Lodash: ${lodashExists}, Chalk: ${chalkExists}`);
112
- reject(new Error('Repository clone verification failed'));
113
- }
114
- } catch (e) {
115
- reject(e);
116
- }
117
- });
118
- }
119
-
120
- async function verifyServer() {
121
- return new Promise((resolve) => {
122
- const req = http.get('http://localhost:3000', (res) => {
123
- log('PHASE1', `Server responded with status ${res.statusCode}`);
124
- resolve(res.statusCode === 200 || res.statusCode === 302);
125
- res.resume();
126
- });
127
- req.on('error', (err) => {
128
- log('PHASE1', `Server connection error: ${err.message}`);
129
- resolve(false);
130
- });
131
- });
132
- }
133
-
134
- async function executePhases() {
135
- try {
136
- // PHASE 1 & 3: Start server and clone repos (parallel, but we'll do sequentially for now)
137
- try {
138
- const running = await checkServerRunning();
139
- if (running) {
140
- log('PHASE1', 'Server is already running on port 3000');
141
- results.phase1.status = 'PASS';
142
- results.phase1.details = 'Server verified running on port 3000';
143
- } else {
144
- log('PHASE1', 'Server not running, attempting to start...');
145
- await startServer();
146
- const verified = await verifyServer();
147
- results.phase1.status = verified ? 'PASS' : 'FAIL';
148
- results.phase1.details = verified ? 'Server started and verified' : 'Server failed verification';
149
- }
150
- } catch (e) {
151
- results.phase1.status = 'FAIL';
152
- results.phase1.details = e.message;
153
- log('PHASE1', `ERROR: ${e.message}`);
154
- }
155
-
156
- // PHASE 3: Clone repositories
157
- try {
158
- const repos = await cloneRepositories();
159
- results.phase3.status = 'PASS';
160
- results.phase3.details = `Lodash: ${repos.lodashExists}, Chalk: ${repos.chalkExists}`;
161
- } catch (e) {
162
- results.phase3.status = 'FAIL';
163
- results.phase3.details = e.message;
164
- log('PHASE3', `ERROR: ${e.message}`);
165
- }
166
-
167
- // Write preliminary results
168
- fs.writeFileSync('/home/user/agentgui/TEST_RESULTS_PHASE1.json', JSON.stringify(results, null, 2));
169
- log('MAIN', 'Phase 1 and 3 complete. Preliminary results saved.');
170
- log('MAIN', 'Ready for browser-based testing (Phases 2, 4-8)');
171
-
172
- return results;
173
- } catch (e) {
174
- console.error('Test execution failed:', e);
175
- throw e;
176
- }
177
- }
178
-
179
- executePhases().catch(e => {
180
- console.error('Fatal error:', e);
181
- process.exit(1);
182
- });