agentgui 1.0.616 → 1.0.617
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/TOOLS-FIX-SUMMARY.md +122 -0
- package/TOOLS_COMPLETION_REPORT.md +199 -0
- package/TOOLS_DEBUG_SUMMARY.md +105 -0
- package/database.js +5 -2
- package/lib/speech.js +0 -1
- package/lib/tool-manager.js +178 -119
- package/lib/ws-handlers-conv.js +16 -2
- package/lib/ws-handlers-session.js +32 -39
- package/lib/ws-handlers-util.js +32 -1
- package/package.json +1 -1
- package/scripts/patch-fsbrowse.js +131 -4
- package/server.js +187 -110
- package/static/index.html +13 -22
- package/static/js/client.js +61 -2
- package/static/js/streaming-renderer.js +3 -1
- package/static/js/tools-manager.js +11 -0
- package/test-cli-detection.mjs +37 -0
- package/test-system-validation.js +188 -0
package/static/index.html
CHANGED
|
@@ -1456,7 +1456,6 @@
|
|
|
1456
1456
|
align-items: center;
|
|
1457
1457
|
justify-content: space-between;
|
|
1458
1458
|
gap: 0.5rem;
|
|
1459
|
-
background: #1f2937;
|
|
1460
1459
|
padding: 0.5rem 1rem;
|
|
1461
1460
|
}
|
|
1462
1461
|
|
|
@@ -1532,7 +1531,6 @@
|
|
|
1532
1531
|
.block-tool-use {
|
|
1533
1532
|
margin-bottom: 0;
|
|
1534
1533
|
border-radius: 0.5rem;
|
|
1535
|
-
background: #ecfeff;
|
|
1536
1534
|
overflow: hidden;
|
|
1537
1535
|
}
|
|
1538
1536
|
|
|
@@ -1543,7 +1541,6 @@
|
|
|
1543
1541
|
display: flex;
|
|
1544
1542
|
align-items: center;
|
|
1545
1543
|
gap: 0.375rem;
|
|
1546
|
-
background: #cffafe;
|
|
1547
1544
|
}
|
|
1548
1545
|
|
|
1549
1546
|
html.dark .block-tool-use .tool-header { }
|
|
@@ -2410,10 +2407,10 @@
|
|
|
2410
2407
|
overflow: hidden;
|
|
2411
2408
|
}
|
|
2412
2409
|
|
|
2413
|
-
.block-tool-result.result-success {
|
|
2414
|
-
.block-tool-result.result-error {
|
|
2415
|
-
html.dark .block-tool-result.result-success {
|
|
2416
|
-
html.dark .block-tool-result.result-error {
|
|
2410
|
+
.block-tool-result.result-success { }
|
|
2411
|
+
.block-tool-result.result-error { }
|
|
2412
|
+
html.dark .block-tool-result.result-success { }
|
|
2413
|
+
html.dark .block-tool-result.result-error { }
|
|
2417
2414
|
|
|
2418
2415
|
.block-tool-result .result-header {
|
|
2419
2416
|
padding: 0.3rem 0.75rem;
|
|
@@ -2422,10 +2419,10 @@
|
|
|
2422
2419
|
justify-content: space-between;
|
|
2423
2420
|
}
|
|
2424
2421
|
|
|
2425
|
-
.block-tool-result.result-success .result-header {
|
|
2426
|
-
.block-tool-result.result-error .result-header {
|
|
2427
|
-
html.dark .block-tool-result.result-success .result-header {
|
|
2428
|
-
html.dark .block-tool-result.result-error .result-header {
|
|
2422
|
+
.block-tool-result.result-success .result-header { }
|
|
2423
|
+
.block-tool-result.result-error .result-header { }
|
|
2424
|
+
html.dark .block-tool-result.result-success .result-header { }
|
|
2425
|
+
html.dark .block-tool-result.result-error .result-header { }
|
|
2429
2426
|
|
|
2430
2427
|
.block-tool-result .result-header .status-label {
|
|
2431
2428
|
display: flex;
|
|
@@ -2497,15 +2494,13 @@
|
|
|
2497
2494
|
}
|
|
2498
2495
|
|
|
2499
2496
|
.block-result.result-ok {
|
|
2500
|
-
background: linear-gradient(135deg, #ecfdf5, #f0fdf4);
|
|
2501
2497
|
}
|
|
2502
2498
|
|
|
2503
2499
|
.block-result.result-err {
|
|
2504
|
-
background: linear-gradient(135deg, #fef2f2, #fff1f2);
|
|
2505
2500
|
}
|
|
2506
2501
|
|
|
2507
|
-
html.dark .block-result.result-ok {
|
|
2508
|
-
html.dark .block-result.result-err {
|
|
2502
|
+
html.dark .block-result.result-ok { }
|
|
2503
|
+
html.dark .block-result.result-err { }
|
|
2509
2504
|
|
|
2510
2505
|
.block-result .result-summary-header {
|
|
2511
2506
|
padding: 0.375rem 0.75rem;
|
|
@@ -2553,21 +2548,19 @@
|
|
|
2553
2548
|
.block-system {
|
|
2554
2549
|
margin-bottom: 0;
|
|
2555
2550
|
border-radius: 0.5rem;
|
|
2556
|
-
background: #eef2ff;
|
|
2557
2551
|
overflow: hidden;
|
|
2558
2552
|
}
|
|
2559
2553
|
|
|
2560
|
-
html.dark .block-system {
|
|
2554
|
+
html.dark .block-system { }
|
|
2561
2555
|
|
|
2562
2556
|
.block-system .system-header {
|
|
2563
2557
|
padding: 0.375rem 0.75rem;
|
|
2564
|
-
background: #e0e7ff;
|
|
2565
2558
|
font-weight: 600;
|
|
2566
2559
|
font-size: 0.85rem;
|
|
2567
2560
|
color: #3730a3;
|
|
2568
2561
|
}
|
|
2569
2562
|
|
|
2570
|
-
html.dark .block-system .system-header {
|
|
2563
|
+
html.dark .block-system .system-header { color: #a5b4fc; }
|
|
2571
2564
|
|
|
2572
2565
|
.block-system .system-body {
|
|
2573
2566
|
padding: 0.375rem 0.75rem;
|
|
@@ -2611,7 +2604,6 @@
|
|
|
2611
2604
|
margin-bottom: 0;
|
|
2612
2605
|
border-radius: 0.5rem;
|
|
2613
2606
|
overflow: hidden;
|
|
2614
|
-
background: #111827;
|
|
2615
2607
|
}
|
|
2616
2608
|
|
|
2617
2609
|
.block-bash .bash-command {
|
|
@@ -2688,10 +2680,9 @@
|
|
|
2688
2680
|
margin-bottom: 0;
|
|
2689
2681
|
padding: 0.5rem 0.75rem;
|
|
2690
2682
|
border-radius: 0.5rem;
|
|
2691
|
-
background: #fef2f2;
|
|
2692
2683
|
}
|
|
2693
2684
|
|
|
2694
|
-
html.dark .block-error {
|
|
2685
|
+
html.dark .block-error { }
|
|
2695
2686
|
|
|
2696
2687
|
/* --- Image Block --- */
|
|
2697
2688
|
.block-image {
|
package/static/js/client.js
CHANGED
|
@@ -532,7 +532,8 @@ class AgentGUIClient {
|
|
|
532
532
|
return;
|
|
533
533
|
}
|
|
534
534
|
try {
|
|
535
|
-
|
|
535
|
+
// Queue uses msg.send which will enqueue if streaming is active
|
|
536
|
+
const data = await window.wsClient.rpc('msg.send', { id: this.state.currentConversation.id, content: message });
|
|
536
537
|
console.log('Queue response:', data);
|
|
537
538
|
if (this.ui.messageInput) {
|
|
538
539
|
this.ui.messageInput.value = '';
|
|
@@ -918,6 +919,24 @@ class AgentGUIClient {
|
|
|
918
919
|
this.scrollToBottom(true);
|
|
919
920
|
}
|
|
920
921
|
|
|
922
|
+
// Immediately fetch any existing chunks for this session and start polling
|
|
923
|
+
// This ensures real-time feedback appears immediately
|
|
924
|
+
try {
|
|
925
|
+
const initialChunks = await this.fetchChunks(data.conversationId, 0);
|
|
926
|
+
// Filter to only chunks from the current session
|
|
927
|
+
const sessionChunks = initialChunks.filter(c => c.sessionId === data.sessionId && c.block && c.block.type);
|
|
928
|
+
if (sessionChunks.length > 0) {
|
|
929
|
+
this.renderChunkBatch(sessionChunks);
|
|
930
|
+
// Update lastFetchTimestamp so polling doesn't duplicate these chunks
|
|
931
|
+
const lastChunk = sessionChunks[sessionChunks.length - 1];
|
|
932
|
+
if (lastChunk && lastChunk.created_at) {
|
|
933
|
+
this.chunkPollState.lastFetchTimestamp = lastChunk.created_at;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
} catch (e) {
|
|
937
|
+
console.warn('Initial chunk fetch failed:', e.message);
|
|
938
|
+
}
|
|
939
|
+
|
|
921
940
|
// Start polling for chunks from database
|
|
922
941
|
this.startChunkPolling(data.conversationId);
|
|
923
942
|
|
|
@@ -952,6 +971,18 @@ class AgentGUIClient {
|
|
|
952
971
|
if (!this.state.streamingBlocks) this.state.streamingBlocks = [];
|
|
953
972
|
this.state.streamingBlocks.push(block);
|
|
954
973
|
|
|
974
|
+
// Thinking blocks are transient and not stored in DB, so render immediately
|
|
975
|
+
if (block.type === 'thinking' && this.state.currentSession?.id === data.sessionId) {
|
|
976
|
+
const streamingEl = document.getElementById(`streaming-${data.sessionId}`);
|
|
977
|
+
if (streamingEl) {
|
|
978
|
+
const blocksEl = streamingEl.querySelector('.streaming-blocks');
|
|
979
|
+
if (blocksEl) {
|
|
980
|
+
const el = this.renderer.renderBlock(block, data, blocksEl);
|
|
981
|
+
if (el) blocksEl.appendChild(el);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
955
986
|
// WebSocket is now just a notification trigger, not data source
|
|
956
987
|
// Actual blocks come from database polling in startChunkPolling()
|
|
957
988
|
}
|
|
@@ -1131,6 +1162,14 @@ class AgentGUIClient {
|
|
|
1131
1162
|
this.saveScrollPosition(conversationId);
|
|
1132
1163
|
}
|
|
1133
1164
|
|
|
1165
|
+
// Fetch any final chunks that may have been missed during polling
|
|
1166
|
+
// This ensures all output is visible without requiring a page refresh
|
|
1167
|
+
if (conversationId && sessionId) {
|
|
1168
|
+
this.fetchRemainingChunks(conversationId, sessionId).catch(err => {
|
|
1169
|
+
console.warn('Final chunk fetch failed:', err.message);
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1134
1173
|
this.enableControls();
|
|
1135
1174
|
this.emit('streaming:complete', data);
|
|
1136
1175
|
|
|
@@ -1935,7 +1974,10 @@ class AgentGUIClient {
|
|
|
1935
1974
|
if (pollState.isPolling) return;
|
|
1936
1975
|
|
|
1937
1976
|
pollState.isPolling = true;
|
|
1938
|
-
|
|
1977
|
+
// Only reset lastFetchTimestamp if it wasn't already set by initial fetch
|
|
1978
|
+
if (pollState.lastFetchTimestamp === 0) {
|
|
1979
|
+
pollState.lastFetchTimestamp = Date.now();
|
|
1980
|
+
}
|
|
1939
1981
|
pollState.backoffDelay = this._getAdaptivePollInterval();
|
|
1940
1982
|
pollState.sessionCheckCounter = 0;
|
|
1941
1983
|
pollState.emptyPollCount = 0;
|
|
@@ -2045,6 +2087,23 @@ class AgentGUIClient {
|
|
|
2045
2087
|
if (this._placeholderTimer) { clearTimeout(this._placeholderTimer); this._placeholderTimer = null; }
|
|
2046
2088
|
}
|
|
2047
2089
|
|
|
2090
|
+
/**
|
|
2091
|
+
* Fetch any remaining chunks after streaming completes
|
|
2092
|
+
* Ensures all output is visible without requiring a page refresh
|
|
2093
|
+
*/
|
|
2094
|
+
async fetchRemainingChunks(conversationId, sessionId) {
|
|
2095
|
+
try {
|
|
2096
|
+
const lastTimestamp = this.chunkPollState.lastFetchTimestamp || 0;
|
|
2097
|
+
const chunks = await this.fetchChunks(conversationId, lastTimestamp);
|
|
2098
|
+
const sessionChunks = chunks.filter(c => c.sessionId === sessionId && c.block && c.block.type);
|
|
2099
|
+
if (sessionChunks.length > 0) {
|
|
2100
|
+
this.renderChunkBatch(sessionChunks);
|
|
2101
|
+
}
|
|
2102
|
+
} catch (err) {
|
|
2103
|
+
console.error('Failed to fetch remaining chunks:', err);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2048
2107
|
/**
|
|
2049
2108
|
* Render a single chunk to the output
|
|
2050
2109
|
*/
|
|
@@ -334,7 +334,9 @@ class StreamingRenderer {
|
|
|
334
334
|
case 'code_block':
|
|
335
335
|
return this.renderCode(event);
|
|
336
336
|
case 'thinking_block':
|
|
337
|
-
|
|
337
|
+
// Thinking blocks are now rendered immediately via handleStreamingProgress
|
|
338
|
+
// Don't render them here to avoid duplicates
|
|
339
|
+
return null;
|
|
338
340
|
case 'tool_use':
|
|
339
341
|
return this.renderToolUse(event);
|
|
340
342
|
default:
|
|
@@ -287,6 +287,17 @@
|
|
|
287
287
|
operationInProgress.delete(data.toolId);
|
|
288
288
|
render();
|
|
289
289
|
}
|
|
290
|
+
} else if (data.type === 'tool_status_update') {
|
|
291
|
+
var tool = tools.find(t => t.id === data.toolId);
|
|
292
|
+
if (tool && data.data) {
|
|
293
|
+
if (data.data.installed) {
|
|
294
|
+
tool.status = data.data.isUpToDate ? 'installed' : 'needs_update';
|
|
295
|
+
tool.installed = true;
|
|
296
|
+
tool.isUpToDate = data.data.isUpToDate ?? true;
|
|
297
|
+
tool.installedVersion = data.data.installedVersion || tool.installedVersion;
|
|
298
|
+
}
|
|
299
|
+
render();
|
|
300
|
+
}
|
|
290
301
|
} else if (data.type === 'tools_update_complete') {
|
|
291
302
|
fetchTools();
|
|
292
303
|
} else if (data.type === 'tools_refresh_complete') {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { checkCliInstalled, getCliVersion } from './lib/tool-manager.js';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
|
|
5
|
+
console.log('=== CLI Tool Detection Test ===\n');
|
|
6
|
+
|
|
7
|
+
const tools = [
|
|
8
|
+
{ pkg: '@anthropic-ai/claude-code', bin: 'claude' },
|
|
9
|
+
{ pkg: 'opencode-ai', bin: 'opencode' },
|
|
10
|
+
{ pkg: '@google/gemini-cli', bin: 'gemini' },
|
|
11
|
+
{ pkg: '@kilocode/cli', bin: 'kilo' },
|
|
12
|
+
{ pkg: '@openai/codex', bin: 'codex' }
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
tools.forEach(tool => {
|
|
16
|
+
try {
|
|
17
|
+
// Direct which check
|
|
18
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
19
|
+
execSync(`${which} ${tool.bin}`, { stdio: 'pipe', timeout: 3000 });
|
|
20
|
+
const version = execSync(`${tool.bin} --version`, { stdio: 'pipe', timeout: 2000, encoding: 'utf8' }).trim();
|
|
21
|
+
const match = version.match(/(\d+\.\d+\.\d+)/);
|
|
22
|
+
console.log(`✓ ${tool.pkg}`);
|
|
23
|
+
console.log(` Binary: ${tool.bin} (found)`);
|
|
24
|
+
console.log(` Version output: ${version.substring(0, 50)}`);
|
|
25
|
+
console.log(` Parsed version: ${match ? match[1] : 'NOT FOUND'}`);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.log(`✗ ${tool.pkg}`);
|
|
28
|
+
console.log(` Binary: ${tool.bin} (not found in PATH)`);
|
|
29
|
+
}
|
|
30
|
+
console.log();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log('=== Testing Tool Manager Functions ===\n');
|
|
34
|
+
|
|
35
|
+
// Test with promises
|
|
36
|
+
console.log('Note: Tool manager functions require async context');
|
|
37
|
+
console.log('Use tool-manager directly in server to test full functionality');
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* System Validation Script
|
|
5
|
+
* Verifies that CLI tools are properly detected and agents are available
|
|
6
|
+
* Usage: node test-system-validation.js
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
const homeDir = os.homedir();
|
|
15
|
+
const colors = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
green: '\x1b[32m',
|
|
18
|
+
red: '\x1b[31m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function log(color, label, message) {
|
|
24
|
+
console.log(`${colors[color]}[${label}]${colors.reset} ${message}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function success(label, message) {
|
|
28
|
+
log('green', label, message);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function error(label, message) {
|
|
32
|
+
log('red', label, message);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function warn(label, message) {
|
|
36
|
+
log('yellow', label, message);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function info(label, message) {
|
|
40
|
+
log('blue', label, message);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Test CLI tool detection
|
|
44
|
+
function testCLIDetection() {
|
|
45
|
+
info('TEST', 'CLI Tool Detection');
|
|
46
|
+
|
|
47
|
+
const tools = [
|
|
48
|
+
{ pkg: '@anthropic-ai/claude-code', bin: 'claude', name: 'Claude Code' },
|
|
49
|
+
{ pkg: 'opencode-ai', bin: 'opencode', name: 'OpenCode' },
|
|
50
|
+
{ pkg: '@google/gemini-cli', bin: 'gemini', name: 'Gemini CLI' },
|
|
51
|
+
{ pkg: '@kilocode/cli', bin: 'kilo', name: 'Kilo Code' },
|
|
52
|
+
{ pkg: '@openai/codex', bin: 'codex', name: 'Codex CLI' }
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
let foundCount = 0;
|
|
56
|
+
|
|
57
|
+
for (const tool of tools) {
|
|
58
|
+
try {
|
|
59
|
+
const cmd = os.platform() === 'win32' ? 'where' : 'which';
|
|
60
|
+
const result = execSync(`${cmd} ${tool.bin}`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
61
|
+
|
|
62
|
+
if (result) {
|
|
63
|
+
success(tool.name, `Found at ${result}`);
|
|
64
|
+
|
|
65
|
+
// Try to get version
|
|
66
|
+
try {
|
|
67
|
+
const version = execSync(`${tool.bin} --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
68
|
+
const match = version.match(/(\d+\.\d+\.\d+)/);
|
|
69
|
+
if (match) {
|
|
70
|
+
success(tool.name, `Version ${match[1]}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (_) {
|
|
73
|
+
warn(tool.name, 'Could not detect version');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
foundCount++;
|
|
77
|
+
}
|
|
78
|
+
} catch (_) {
|
|
79
|
+
error(tool.name, 'NOT FOUND in PATH');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(`\n✓ CLI Detection Summary: ${foundCount}/${tools.length} tools found\n`);
|
|
84
|
+
return foundCount > 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Test agent discovery paths
|
|
88
|
+
function testAgentPaths() {
|
|
89
|
+
info('TEST', 'Agent Plugin Paths');
|
|
90
|
+
|
|
91
|
+
const paths = [
|
|
92
|
+
{ label: 'Claude Code Plugin', path: path.join(homeDir, '.claude', 'plugins', 'gm-cc') },
|
|
93
|
+
{ label: 'OpenCode Agent', path: path.join(homeDir, '.config', 'opencode', 'agents', 'gm.md') },
|
|
94
|
+
{ label: 'Gemini Extension', path: path.join(homeDir, '.gemini', 'extensions', 'gm') },
|
|
95
|
+
{ label: 'Kilo Agent', path: path.join(homeDir, '.config', 'kilo', 'agents', 'gm.md') }
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
let foundCount = 0;
|
|
99
|
+
|
|
100
|
+
for (const { label, path: p } of paths) {
|
|
101
|
+
if (fs.existsSync(p)) {
|
|
102
|
+
success(label, `Found at ${p}`);
|
|
103
|
+
foundCount++;
|
|
104
|
+
} else {
|
|
105
|
+
warn(label, `Not found at ${p}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log(`\n✓ Agent Paths Summary: ${foundCount}/${paths.length} agent paths exist\n`);
|
|
110
|
+
return foundCount > 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Test Node.js binary discovery
|
|
114
|
+
function testNodeBinaries() {
|
|
115
|
+
info('TEST', 'Node Modules Binaries');
|
|
116
|
+
|
|
117
|
+
const agentguiPath = '/config/workspace/agentgui';
|
|
118
|
+
const binaries = ['claude', 'opencode', 'gemini', 'kilo', 'codex'];
|
|
119
|
+
|
|
120
|
+
let foundCount = 0;
|
|
121
|
+
|
|
122
|
+
for (const bin of binaries) {
|
|
123
|
+
const path = `${agentguiPath}/node_modules/.bin/${bin}`;
|
|
124
|
+
if (fs.existsSync(path)) {
|
|
125
|
+
success(`Binary: ${bin}`, `Found at ${path}`);
|
|
126
|
+
foundCount++;
|
|
127
|
+
} else {
|
|
128
|
+
warn(`Binary: ${bin}`, `NOT found at ${path}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`\n✓ Node Binaries Summary: ${foundCount}/${binaries.length} binaries found\n`);
|
|
133
|
+
return foundCount > 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Test ES module imports
|
|
137
|
+
function testESModuleImports() {
|
|
138
|
+
info('TEST', 'ES Module Imports (tool-manager.js)');
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const toolManagerPath = '/config/workspace/agentgui/lib/tool-manager.js';
|
|
142
|
+
const content = fs.readFileSync(toolManagerPath, 'utf8');
|
|
143
|
+
|
|
144
|
+
// Check for proper execSync import
|
|
145
|
+
if (content.includes('import { spawn, execSync } from \'child_process\'')) {
|
|
146
|
+
success('execSync Import', 'Properly imported from child_process');
|
|
147
|
+
} else {
|
|
148
|
+
error('execSync Import', 'NOT found or incorrectly imported');
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Check that require() is not used
|
|
153
|
+
if (!content.includes('require(\'child_process\')')) {
|
|
154
|
+
success('No require()', 'No CommonJS require() calls found');
|
|
155
|
+
} else {
|
|
156
|
+
error('require() Calls', 'Found require() calls which won\'t work in ES modules');
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log();
|
|
161
|
+
return true;
|
|
162
|
+
} catch (err) {
|
|
163
|
+
error('File Read', err.message);
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Run all tests
|
|
169
|
+
console.log('\n' + colors.blue + '═══════════════════════════════════════════════════════════' + colors.reset);
|
|
170
|
+
console.log(colors.blue + ' AgentGUI System Validation' + colors.reset);
|
|
171
|
+
console.log(colors.blue + '═══════════════════════════════════════════════════════════' + colors.reset + '\n');
|
|
172
|
+
|
|
173
|
+
let allPassed = true;
|
|
174
|
+
|
|
175
|
+
allPassed &= testCLIDetection();
|
|
176
|
+
allPassed &= testAgentPaths();
|
|
177
|
+
allPassed &= testNodeBinaries();
|
|
178
|
+
allPassed &= testESModuleImports();
|
|
179
|
+
|
|
180
|
+
console.log(colors.blue + '═══════════════════════════════════════════════════════════' + colors.reset);
|
|
181
|
+
if (allPassed) {
|
|
182
|
+
success('RESULT', 'All critical checks passed! System should work correctly.');
|
|
183
|
+
} else {
|
|
184
|
+
warn('RESULT', 'Some checks failed. Review errors above.');
|
|
185
|
+
}
|
|
186
|
+
console.log(colors.blue + '═══════════════════════════════════════════════════════════' + colors.reset + '\n');
|
|
187
|
+
|
|
188
|
+
process.exit(allPassed ? 0 : 1);
|