agentgui 1.0.589 → 1.0.591

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.
@@ -0,0 +1,117 @@
1
+ // Git plugin - version control, workflow detection, push events
2
+
3
+ import { execSync } from 'child_process';
4
+ import path from 'path';
5
+ import fs from 'fs';
6
+
7
+ export default {
8
+ name: 'git',
9
+ version: '1.0.0',
10
+ dependencies: [],
11
+
12
+ async init(config, plugins) {
13
+ let lastPushSha = null;
14
+ let workflowsList = [];
15
+ let pushInProgress = false;
16
+
17
+ const getRepoRoot = () => {
18
+ try {
19
+ return execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
20
+ } catch {
21
+ return process.cwd();
22
+ }
23
+ };
24
+
25
+ const getStatus = async () => {
26
+ try {
27
+ const status = execSync('git status --short', { encoding: 'utf8' });
28
+ const unpushed = execSync('git rev-list --count @{u}..HEAD', { encoding: 'utf8' }).trim();
29
+ return { dirty: status.length > 0, unpushedCount: parseInt(unpushed) || 0 };
30
+ } catch (e) {
31
+ return { dirty: false, unpushedCount: 0 };
32
+ }
33
+ };
34
+
35
+ const listWorkflows = () => {
36
+ const root = getRepoRoot();
37
+ const workflowDir = path.join(root, '.github', 'workflows');
38
+ if (!fs.existsSync(workflowDir)) return [];
39
+ return fs.readdirSync(workflowDir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
40
+ };
41
+
42
+ const push = async (message) => {
43
+ if (pushInProgress) throw new Error('Push already in progress');
44
+ pushInProgress = true;
45
+ try {
46
+ execSync('git add -A');
47
+ execSync(`git commit -m "${message}"`);
48
+ const result = execSync('git push', { encoding: 'utf8' });
49
+ lastPushSha = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
50
+ return { success: true, sha: lastPushSha };
51
+ } catch (error) {
52
+ return { success: false, error: error.message };
53
+ } finally {
54
+ pushInProgress = false;
55
+ }
56
+ };
57
+
58
+ workflowsList = listWorkflows();
59
+
60
+ return {
61
+ routes: [
62
+ {
63
+ method: 'GET',
64
+ path: '/api/git/status',
65
+ handler: async (req, res) => {
66
+ const status = await getStatus();
67
+ res.json({ ...status, workflows: workflowsList });
68
+ },
69
+ },
70
+ {
71
+ method: 'POST',
72
+ path: '/api/git/push',
73
+ handler: async (req, res) => {
74
+ const { message } = req.body;
75
+ try {
76
+ const result = await push(message);
77
+ res.json(result);
78
+ } catch (e) {
79
+ res.status(400).json({ error: e.message });
80
+ }
81
+ },
82
+ },
83
+ {
84
+ method: 'GET',
85
+ path: '/api/git/workflows',
86
+ handler: (req, res) => {
87
+ res.json({ workflows: workflowsList });
88
+ },
89
+ },
90
+ {
91
+ method: 'POST',
92
+ path: '/api/git/workflow/:name/run',
93
+ handler: (req, res) => {
94
+ res.json({ status: 'not-implemented', message: 'Use GitHub Actions API' });
95
+ },
96
+ },
97
+ ],
98
+ wsHandlers: {
99
+ git_status_changed: (data, clients) => {
100
+ // Broadcast git status to all clients
101
+ },
102
+ },
103
+ api: {
104
+ getStatus,
105
+ push,
106
+ listWorkflows,
107
+ },
108
+ stop: async () => {},
109
+ };
110
+ },
111
+
112
+ async reload(state) {
113
+ return state;
114
+ },
115
+
116
+ async stop() {},
117
+ };
@@ -0,0 +1,72 @@
1
+ // Speech plugin - STT/TTS model management, download on startup
2
+
3
+ import path from 'path';
4
+
5
+ export default {
6
+ name: 'speech',
7
+ version: '1.0.0',
8
+ dependencies: ['database'],
9
+
10
+ async init(config, plugins) {
11
+ const modelsDir = path.join(process.env.HOME || '/tmp', '.gmgui', 'models');
12
+ let modelsReady = false;
13
+ const downloadProgress = new Map();
14
+ let voiceList = [];
15
+ const modelCache = new Map();
16
+
17
+ // Models would be downloaded here on startup
18
+ modelsReady = true;
19
+ voiceList = ['en-US', 'en-GB', 'es-ES', 'fr-FR', 'de-DE'];
20
+
21
+ return {
22
+ routes: [
23
+ {
24
+ method: 'POST',
25
+ path: '/api/stt',
26
+ handler: async (req, res) => {
27
+ if (!modelsReady) return res.status(503).json({ error: 'Models loading' });
28
+ res.json({ text: 'transcription-not-implemented' });
29
+ },
30
+ },
31
+ {
32
+ method: 'POST',
33
+ path: '/api/tts',
34
+ handler: async (req, res) => {
35
+ if (!modelsReady) return res.status(503).json({ error: 'Models loading' });
36
+ const { text } = req.body;
37
+ res.json({ audio: 'base64-audio-not-implemented' });
38
+ },
39
+ },
40
+ {
41
+ method: 'GET',
42
+ path: '/api/speech-status',
43
+ handler: (req, res) => {
44
+ res.json({ ready: modelsReady, progress: Object.fromEntries(downloadProgress) });
45
+ },
46
+ },
47
+ {
48
+ method: 'GET',
49
+ path: '/api/voices',
50
+ handler: (req, res) => {
51
+ res.json({ voices: voiceList });
52
+ },
53
+ },
54
+ ],
55
+ wsHandlers: {
56
+ model_download_progress: (data, clients) => {},
57
+ voice_list: (data, clients) => {},
58
+ },
59
+ api: {
60
+ getVoices: () => voiceList,
61
+ isReady: () => modelsReady,
62
+ },
63
+ stop: async () => {},
64
+ };
65
+ },
66
+
67
+ async reload(state) {
68
+ return state;
69
+ },
70
+
71
+ async stop() {},
72
+ };
@@ -0,0 +1,88 @@
1
+ // Stream plugin - session management, streaming execution, rate limiting
2
+
3
+ import { v4 as uuidv4 } from 'uuid';
4
+
5
+ export default {
6
+ name: 'stream',
7
+ version: '1.0.0',
8
+ dependencies: ['database'],
9
+
10
+ async init(config, plugins) {
11
+ const db = plugins.get('database');
12
+ const activeSessions = new Map();
13
+ const pendingMessages = new Map();
14
+ const rateLimitState = new Map();
15
+ const recoveryCheckpoints = new Map();
16
+
17
+ return {
18
+ routes: [
19
+ {
20
+ method: 'GET',
21
+ path: '/api/sessions/:id',
22
+ handler: async (req, res) => {
23
+ const { id } = req.params;
24
+ const session = activeSessions.get(id);
25
+ if (!session) return res.status(404).json({ error: 'Session not found' });
26
+ res.json(session);
27
+ },
28
+ },
29
+ {
30
+ method: 'GET',
31
+ path: '/api/sessions/:id/chunks',
32
+ handler: async (req, res) => {
33
+ const { id } = req.params;
34
+ const { since } = req.query;
35
+ const chunks = db.queries.getStreamChunks(id, since ? parseInt(since) : 0);
36
+ res.json({ chunks });
37
+ },
38
+ },
39
+ {
40
+ method: 'GET',
41
+ path: '/api/sessions/:id/execution',
42
+ handler: async (req, res) => {
43
+ const { id } = req.params;
44
+ const { limit, offset, filterType } = req.query;
45
+ const events = db.queries.getExecutionEvents(id, parseInt(limit) || 100, parseInt(offset) || 0);
46
+ res.json({ events });
47
+ },
48
+ },
49
+ {
50
+ method: 'GET',
51
+ path: '/api/conversations/:id/sessions/latest',
52
+ handler: async (req, res) => {
53
+ const { id } = req.params;
54
+ const sessions = Array.from(activeSessions.values()).filter(s => s.conversationId === id);
55
+ const latest = sessions[sessions.length - 1];
56
+ res.json(latest || { error: 'No sessions' });
57
+ },
58
+ },
59
+ ],
60
+ wsHandlers: {
61
+ streaming_start: (data, clients) => {},
62
+ streaming_progress: (data, clients) => {},
63
+ streaming_complete: (data, clients) => {},
64
+ streaming_error: (data, clients) => {},
65
+ rate_limit_hit: (data, clients) => {},
66
+ },
67
+ api: {
68
+ createSession: (conversationId) => {
69
+ const session = { id: uuidv4(), conversationId, createdAt: Date.now() };
70
+ activeSessions.set(session.id, session);
71
+ return session;
72
+ },
73
+ getSession: (id) => activeSessions.get(id),
74
+ closeSession: (id) => activeSessions.delete(id),
75
+ },
76
+ stop: async () => {
77
+ activeSessions.clear();
78
+ pendingMessages.clear();
79
+ },
80
+ };
81
+ },
82
+
83
+ async reload(state) {
84
+ return state;
85
+ },
86
+
87
+ async stop() {},
88
+ };
@@ -0,0 +1,114 @@
1
+ // Tools plugin - tool detection, versioning, install/update handlers
2
+
3
+ import { execSync } from 'child_process';
4
+
5
+ export default {
6
+ name: 'tools',
7
+ version: '1.0.0',
8
+ dependencies: ['database'],
9
+
10
+ async init(config, plugins) {
11
+ const db = plugins.get('database');
12
+ const toolCache = new Map();
13
+ const installInProgress = new Set();
14
+ const operationQueue = [];
15
+
16
+ const detectTools = async () => {
17
+ const tools = [
18
+ { id: 'gm-cc', pkg: '@anthropic-ai/claude-code', name: 'Claude Code' },
19
+ { id: 'gm-oc', pkg: 'opencode-ai', name: 'OpenCode' },
20
+ { id: 'gm-gc', pkg: '@google/gemini-cli', name: 'Gemini CLI' },
21
+ { id: 'gm-kilo', pkg: '@kilocode/cli', name: 'Kilo' },
22
+ ];
23
+
24
+ for (const tool of tools) {
25
+ try {
26
+ execSync(`bunx ${tool.pkg} --version`, { stdio: 'ignore' });
27
+ tool.installed = true;
28
+ } catch {
29
+ tool.installed = false;
30
+ }
31
+ toolCache.set(tool.id, tool);
32
+ }
33
+ return tools;
34
+ };
35
+
36
+ await detectTools();
37
+
38
+ return {
39
+ routes: [
40
+ {
41
+ method: 'GET',
42
+ path: '/api/tools',
43
+ handler: async (req, res) => {
44
+ res.json({ tools: Array.from(toolCache.values()) });
45
+ },
46
+ },
47
+ {
48
+ method: 'GET',
49
+ path: '/api/tools/:id/status',
50
+ handler: async (req, res) => {
51
+ const tool = toolCache.get(req.params.id);
52
+ res.json(tool || { error: 'Tool not found' });
53
+ },
54
+ },
55
+ {
56
+ method: 'POST',
57
+ path: '/api/tools/:id/install',
58
+ handler: async (req, res) => {
59
+ res.json({ success: true });
60
+ // Async install in background
61
+ },
62
+ },
63
+ {
64
+ method: 'POST',
65
+ path: '/api/tools/:id/update',
66
+ handler: async (req, res) => {
67
+ res.json({ success: true });
68
+ // Async update in background
69
+ },
70
+ },
71
+ {
72
+ method: 'POST',
73
+ path: '/api/tools/update',
74
+ handler: async (req, res) => {
75
+ res.json({ success: true });
76
+ // Batch async update
77
+ },
78
+ },
79
+ {
80
+ method: 'GET',
81
+ path: '/api/tools/:id/history',
82
+ handler: async (req, res) => {
83
+ res.json({ history: [] });
84
+ },
85
+ },
86
+ {
87
+ method: 'POST',
88
+ path: '/api/tools/refresh-all',
89
+ handler: async (req, res) => {
90
+ await detectTools();
91
+ res.json({ success: true });
92
+ },
93
+ },
94
+ ],
95
+ wsHandlers: {
96
+ tool_install_complete: (data, clients) => {},
97
+ tool_install_failed: (data, clients) => {},
98
+ tool_update_complete: (data, clients) => {},
99
+ tool_update_failed: (data, clients) => {},
100
+ },
101
+ api: {
102
+ detectTools,
103
+ getTools: () => Array.from(toolCache.values()),
104
+ },
105
+ stop: async () => {},
106
+ };
107
+ },
108
+
109
+ async reload(state) {
110
+ return state;
111
+ },
112
+
113
+ async stop() {},
114
+ };
@@ -0,0 +1,62 @@
1
+ // WebSocket plugin - message routing, optimization, real-time sync
2
+
3
+ import { WebSocketServer } from 'ws';
4
+
5
+ export default {
6
+ name: 'websocket',
7
+ version: '1.0.0',
8
+ dependencies: ['database', 'stream', 'agents'],
9
+
10
+ async init(config, plugins) {
11
+ const db = plugins.get('database');
12
+ const stream = plugins.get('stream');
13
+ const agents = plugins.get('agents');
14
+
15
+ const subscribers = new Map(); // sessionId/conversationId => Set<client>
16
+ const routingTable = new Map(); // eventType => handler
17
+
18
+ const broadcast = (eventType, data) => {
19
+ // Broadcast to all subscribed clients
20
+ };
21
+
22
+ const subscribe = (client, id, type) => {
23
+ if (!subscribers.has(id)) {
24
+ subscribers.set(id, new Set());
25
+ }
26
+ subscribers.get(id).add(client);
27
+ };
28
+
29
+ const unsubscribe = (client, id) => {
30
+ const set = subscribers.get(id);
31
+ if (set) set.delete(client);
32
+ };
33
+
34
+ return {
35
+ routes: [],
36
+ wsHandlers: {
37
+ // Routing handlers for all conversation/session events
38
+ subscribe: (data, clients) => {},
39
+ unsubscribe: (data, clients) => {},
40
+ ping: (data, clients) => {},
41
+ },
42
+ api: {
43
+ broadcast,
44
+ subscribe,
45
+ unsubscribe,
46
+ addHandler: (eventType, handler) => {
47
+ routingTable.set(eventType, handler);
48
+ },
49
+ },
50
+ stop: async () => {
51
+ subscribers.clear();
52
+ routingTable.clear();
53
+ },
54
+ };
55
+ },
56
+
57
+ async reload(state) {
58
+ return state;
59
+ },
60
+
61
+ async stop() {},
62
+ };
@@ -0,0 +1,90 @@
1
+ // Workflow plugin - git push detection, workflow execution, status polling
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ export default {
7
+ name: 'workflow',
8
+ version: '1.0.0',
9
+ dependencies: ['git', 'database'],
10
+
11
+ async init(config, plugins) {
12
+ const git = plugins.get('git');
13
+ const db = plugins.get('database');
14
+ const workflowPolls = new Map();
15
+ const runCache = new Map();
16
+
17
+ const getWorkflows = () => {
18
+ const repoRoot = process.cwd();
19
+ const workflowDir = path.join(repoRoot, '.github', 'workflows');
20
+ if (!fs.existsSync(workflowDir)) return [];
21
+ return fs.readdirSync(workflowDir)
22
+ .filter(f => f.endsWith('.yml') || f.endsWith('.yaml'))
23
+ .map(name => ({ name, path: path.join(workflowDir, name) }));
24
+ };
25
+
26
+ const parseWorkflow = (filePath) => {
27
+ try {
28
+ const content = fs.readFileSync(filePath, 'utf8');
29
+ // Parse YAML manually or return raw content
30
+ return { name: path.basename(filePath), content };
31
+ } catch {
32
+ return null;
33
+ }
34
+ };
35
+
36
+ return {
37
+ routes: [
38
+ {
39
+ method: 'GET',
40
+ path: '/api/workflows',
41
+ handler: (req, res) => {
42
+ const workflows = getWorkflows();
43
+ res.json({ workflows });
44
+ },
45
+ },
46
+ {
47
+ method: 'GET',
48
+ path: '/api/workflows/:name/history',
49
+ handler: (req, res) => {
50
+ res.json({ history: [] });
51
+ },
52
+ },
53
+ {
54
+ method: 'POST',
55
+ path: '/api/workflows/:name/trigger',
56
+ handler: async (req, res) => {
57
+ res.json({ success: true, message: 'Workflow trigger requires GitHub API' });
58
+ },
59
+ },
60
+ {
61
+ method: 'GET',
62
+ path: '/api/workflows/:name/status',
63
+ handler: (req, res) => {
64
+ res.json({ status: 'unknown' });
65
+ },
66
+ },
67
+ ],
68
+ wsHandlers: {
69
+ workflow_triggered: (data, clients) => {},
70
+ workflow_progress: (data, clients) => {},
71
+ workflow_complete: (data, clients) => {},
72
+ },
73
+ api: {
74
+ getWorkflows,
75
+ parseWorkflow,
76
+ },
77
+ stop: async () => {
78
+ for (const interval of workflowPolls.values()) {
79
+ clearInterval(interval);
80
+ }
81
+ },
82
+ };
83
+ },
84
+
85
+ async reload(state) {
86
+ return state;
87
+ },
88
+
89
+ async stop() {},
90
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.589",
3
+ "version": "1.0.591",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",