agentgui 1.0.588 → 1.0.590

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,132 @@
1
+ // Auth plugin - OAuth2, provider config, agentauth integration
2
+
3
+ import http from 'http';
4
+
5
+ export default {
6
+ name: 'auth',
7
+ version: '1.0.0',
8
+ dependencies: ['database'],
9
+
10
+ async init(config, plugins) {
11
+ const db = plugins.get('database');
12
+ const providerConfigs = new Map();
13
+ const oauthClients = new Map();
14
+ const sessions = new Map();
15
+
16
+ // Detect provider configs on startup
17
+ const detectProviders = () => {
18
+ const providers = [
19
+ { id: 'anthropic', name: 'Anthropic', configured: false },
20
+ { id: 'google', name: 'Google', configured: false },
21
+ { id: 'github', name: 'GitHub', configured: false },
22
+ ];
23
+ providers.forEach(p => providerConfigs.set(p.id, p));
24
+ return providers;
25
+ };
26
+
27
+ detectProviders();
28
+
29
+ // Agentauth integration
30
+ const agentauthStart = async (provider, scopes) => {
31
+ return new Promise((resolve, reject) => {
32
+ const options = {
33
+ hostname: 'localhost',
34
+ port: 8765,
35
+ path: '/auth/start',
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ };
39
+
40
+ const req = http.request(options, (res) => {
41
+ let data = '';
42
+ res.on('data', chunk => data += chunk);
43
+ res.on('end', () => {
44
+ try {
45
+ resolve(JSON.parse(data));
46
+ } catch (e) {
47
+ reject(new Error('Agentauth unavailable'));
48
+ }
49
+ });
50
+ });
51
+
52
+ req.on('error', () => reject(new Error('Agentauth service not running')));
53
+ req.write(JSON.stringify({ provider, scopes }));
54
+ req.end();
55
+ });
56
+ };
57
+
58
+ return {
59
+ routes: [
60
+ {
61
+ method: 'GET',
62
+ path: '/api/auth/status',
63
+ handler: (req, res) => {
64
+ res.json({ authenticated: sessions.size > 0, sessions: Array.from(sessions.keys()) });
65
+ },
66
+ },
67
+ {
68
+ method: 'GET',
69
+ path: '/api/auth/configs',
70
+ handler: (req, res) => {
71
+ const masked = Array.from(providerConfigs.values()).map(p => ({
72
+ id: p.id,
73
+ name: p.name,
74
+ configured: p.configured,
75
+ }));
76
+ res.json({ providers: masked });
77
+ },
78
+ },
79
+ {
80
+ method: 'POST',
81
+ path: '/api/auth/callback',
82
+ handler: (req, res) => {
83
+ const { code } = req.body;
84
+ res.json({ success: true, code });
85
+ },
86
+ },
87
+ {
88
+ method: 'POST',
89
+ path: '/api/auth/logout',
90
+ handler: (req, res) => {
91
+ sessions.clear();
92
+ res.json({ success: true });
93
+ },
94
+ },
95
+ {
96
+ method: 'POST',
97
+ path: '/api/auth/agentauth-start',
98
+ handler: async (req, res) => {
99
+ const { provider, scopes } = req.body;
100
+ try {
101
+ const result = await agentauthStart(provider, scopes);
102
+ res.json(result);
103
+ } catch (e) {
104
+ res.status(503).json({ error: e.message });
105
+ }
106
+ },
107
+ },
108
+ {
109
+ method: 'GET',
110
+ path: '/api/auth/agentauth-status',
111
+ handler: async (req, res) => {
112
+ const { code } = req.query;
113
+ res.json({ status: 'polling-not-implemented' });
114
+ },
115
+ },
116
+ ],
117
+ wsHandlers: {},
118
+ api: {
119
+ getProviders: () => Array.from(providerConfigs.values()),
120
+ },
121
+ stop: async () => {
122
+ sessions.clear();
123
+ },
124
+ };
125
+ },
126
+
127
+ async reload(state) {
128
+ return state;
129
+ },
130
+
131
+ async stop() {},
132
+ };
@@ -0,0 +1,43 @@
1
+ // Database plugin - SQLite init, schema, checkpoint recovery
2
+
3
+ import * as dbModule from '../database.js';
4
+
5
+ export default {
6
+ name: 'database',
7
+ version: '1.0.0',
8
+ dependencies: [],
9
+
10
+ async init(config, plugins) {
11
+ // Initialize database schema
12
+ if (dbModule.initializeSchema) dbModule.initializeSchema();
13
+
14
+ // Return API for other plugins
15
+ return {
16
+ routes: [],
17
+ wsHandlers: {},
18
+ api: {
19
+ // Query functions from database.js
20
+ queries: dbModule.queries || {},
21
+
22
+ // Checkpoint/recovery
23
+ checkpoint: (label) => {
24
+ console.log(`[Database] Checkpoint: ${label}`);
25
+ },
26
+
27
+ recover: async (label) => {
28
+ console.log(`[Database] Recover from: ${label}`);
29
+ },
30
+
31
+ // Direct DB access
32
+ db: dbModule.dataDir,
33
+ },
34
+ stop: async () => {},
35
+ };
36
+ },
37
+
38
+ async reload(state) {
39
+ return state;
40
+ },
41
+
42
+ async stop() {},
43
+ };
@@ -0,0 +1,83 @@
1
+ // Files plugin - file browser, upload handler, drag-drop support
2
+
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+
6
+ export default {
7
+ name: 'files',
8
+ version: '1.0.0',
9
+ dependencies: ['database'],
10
+
11
+ async init(config, plugins) {
12
+ const db = plugins.get('database');
13
+ const uploadedFiles = new Map();
14
+
15
+ const browseDirectory = (dir) => {
16
+ try {
17
+ const entries = fs.readdirSync(dir);
18
+ return entries.map(entry => {
19
+ const fullPath = path.join(dir, entry);
20
+ const stat = fs.statSync(fullPath);
21
+ return {
22
+ name: entry,
23
+ path: fullPath,
24
+ isDirectory: stat.isDirectory(),
25
+ size: stat.size,
26
+ };
27
+ });
28
+ } catch (e) {
29
+ return [];
30
+ }
31
+ };
32
+
33
+ return {
34
+ routes: [
35
+ {
36
+ method: 'GET',
37
+ path: '/files/:conversationId',
38
+ handler: (req, res) => {
39
+ const { conversationId } = req.params;
40
+ const { dir } = req.query;
41
+ const entries = browseDirectory(dir || process.cwd());
42
+ res.json({ entries, currentDir: dir || process.cwd() });
43
+ },
44
+ },
45
+ {
46
+ method: 'POST',
47
+ path: '/api/upload/:conversationId',
48
+ handler: async (req, res) => {
49
+ const { conversationId } = req.params;
50
+ uploadedFiles.set(conversationId, Date.now());
51
+ res.json({ success: true, conversationId });
52
+ },
53
+ },
54
+ {
55
+ method: 'POST',
56
+ path: '/api/folders',
57
+ handler: async (req, res) => {
58
+ const { path: folderPath } = req.body;
59
+ try {
60
+ fs.mkdirSync(folderPath, { recursive: true });
61
+ res.json({ success: true, path: folderPath });
62
+ } catch (e) {
63
+ res.status(400).json({ error: e.message });
64
+ }
65
+ },
66
+ },
67
+ ],
68
+ wsHandlers: {},
69
+ api: {
70
+ browseDirectory,
71
+ },
72
+ stop: async () => {
73
+ uploadedFiles.clear();
74
+ },
75
+ };
76
+ },
77
+
78
+ async reload(state) {
79
+ return state;
80
+ },
81
+
82
+ async stop() {},
83
+ };
@@ -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
+ };