agentgui 1.0.471 → 1.0.473
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/CLAUDE.md +11 -0
- package/lib/tool-manager.js +18 -4
- package/package.json +1 -1
- package/server.js +15 -2
package/CLAUDE.md
CHANGED
|
@@ -83,6 +83,17 @@ All routes are prefixed with `BASE_URL` (default `/gm`).
|
|
|
83
83
|
- `POST /api/tts` - Text-to-speech (body: text)
|
|
84
84
|
- `GET /api/speech-status` - Speech model loading status
|
|
85
85
|
- `POST /api/folders` - Create folder
|
|
86
|
+
- `GET /api/tools` - List detected tools with installation status (via WebSocket tools.list handler)
|
|
87
|
+
|
|
88
|
+
## Tool Detection System
|
|
89
|
+
|
|
90
|
+
The system auto-detects installed AI coding tools via `bunx` package resolution:
|
|
91
|
+
- **OpenCode**: `opencode-ai` package (id: gm-oc)
|
|
92
|
+
- **Gemini CLI**: `@google/gemini-cli` package (id: gm-gc)
|
|
93
|
+
- **Kilo**: `@kilocode/cli` package (id: gm-kilo)
|
|
94
|
+
- **Claude Code**: `@anthropic-ai/claude-code` package (id: gm-cc)
|
|
95
|
+
|
|
96
|
+
Tool package names are configured in `lib/tool-manager.js` TOOLS array (lines 6-11). Detection happens by spawning `bunx <package> --version` to check if tools are installed. Response from `/api/tools` includes: id, name, pkg, installed, status (one of: installed|needs_update|not_installed), isUpToDate, upgradeNeeded, hasUpdate. Frontend displays tools in UI and updates based on installation status.
|
|
86
97
|
|
|
87
98
|
## WebSocket Protocol
|
|
88
99
|
|
package/lib/tool-manager.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
4
6
|
|
|
5
7
|
const isWindows = os.platform() === 'win32';
|
|
6
8
|
const TOOLS = [
|
|
@@ -15,6 +17,16 @@ const installLocks = new Map();
|
|
|
15
17
|
|
|
16
18
|
const getTool = (id) => TOOLS.find(t => t.id === id);
|
|
17
19
|
|
|
20
|
+
const checkToolInstalled = (pkg) => {
|
|
21
|
+
try {
|
|
22
|
+
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
23
|
+
const nodeModulesPath = path.join(__dirname, '..', 'node_modules', pkg);
|
|
24
|
+
return fs.existsSync(nodeModulesPath);
|
|
25
|
+
} catch (_) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
18
30
|
const checkToolViaBunx = async (pkg) => {
|
|
19
31
|
try {
|
|
20
32
|
const cmd = isWindows ? 'bunx.cmd' : 'bunx';
|
|
@@ -29,23 +41,25 @@ const checkToolViaBunx = async (pkg) => {
|
|
|
29
41
|
proc.stderr.on('data', (d) => { stderr += d.toString(); });
|
|
30
42
|
const timer = setTimeout(() => {
|
|
31
43
|
try { proc.kill('SIGKILL'); } catch (_) {}
|
|
32
|
-
|
|
44
|
+
const installed = checkToolInstalled(pkg);
|
|
45
|
+
resolve({ installed, isUpToDate: installed, upgradeNeeded: false, output: 'timeout' });
|
|
33
46
|
}, 10000);
|
|
34
47
|
proc.on('close', (code) => {
|
|
35
48
|
clearTimeout(timer);
|
|
36
49
|
const output = stdout + stderr;
|
|
37
|
-
const installed =
|
|
50
|
+
const installed = code === 0 || checkToolInstalled(pkg);
|
|
38
51
|
const upgradeNeeded = output.includes('Upgrading') || output.includes('upgrade');
|
|
39
52
|
const isUpToDate = installed && !upgradeNeeded;
|
|
40
53
|
resolve({ installed, isUpToDate, upgradeNeeded, output });
|
|
41
54
|
});
|
|
42
55
|
proc.on('error', () => {
|
|
43
56
|
clearTimeout(timer);
|
|
44
|
-
|
|
57
|
+
const installed = checkToolInstalled(pkg);
|
|
58
|
+
resolve({ installed, isUpToDate: false, upgradeNeeded: false, output: '' });
|
|
45
59
|
});
|
|
46
60
|
});
|
|
47
61
|
} catch (_) {
|
|
48
|
-
return { installed:
|
|
62
|
+
return { installed: checkToolInstalled(pkg), isUpToDate: false, upgradeNeeded: false, output: '' };
|
|
49
63
|
}
|
|
50
64
|
};
|
|
51
65
|
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -4258,8 +4258,21 @@ async function resumeInterruptedStreams() {
|
|
|
4258
4258
|
const messageId = lastMsg?.id || null;
|
|
4259
4259
|
console.log(`[RESUME] Resuming conv ${conv.id} (claude session: ${conv.claudeSessionId})`);
|
|
4260
4260
|
|
|
4261
|
-
|
|
4262
|
-
.
|
|
4261
|
+
try {
|
|
4262
|
+
await processMessageWithStreaming(conv.id, messageId, session.id, promptText, conv.agentType, conv.model, conv.subAgent);
|
|
4263
|
+
} catch (err) {
|
|
4264
|
+
console.error(`[RESUME] Error resuming conv ${conv.id}: ${err.message}`);
|
|
4265
|
+
queries.setIsStreaming(conv.id, false);
|
|
4266
|
+
const activeSessions = queries.getSessionsByStatus(conv.id, 'active');
|
|
4267
|
+
const pendingSessions = queries.getSessionsByStatus(conv.id, 'pending');
|
|
4268
|
+
for (const s of [...activeSessions, ...pendingSessions]) {
|
|
4269
|
+
queries.updateSession(s.id, {
|
|
4270
|
+
status: 'error',
|
|
4271
|
+
error: 'Resume failed: ' + err.message,
|
|
4272
|
+
completed_at: Date.now()
|
|
4273
|
+
});
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4263
4276
|
|
|
4264
4277
|
if (i < toResume.length - 1) {
|
|
4265
4278
|
await new Promise(r => setTimeout(r, 200));
|