agentgui 1.0.916 → 1.0.918

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.
Files changed (53) hide show
  1. package/CLAUDE.md +1 -382
  2. package/database-schema.js +0 -58
  3. package/lib/db-queries-cleanup.js +0 -12
  4. package/lib/db-queries-del.js +0 -1
  5. package/lib/db-queries.js +0 -4
  6. package/lib/http-handler.js +1 -10
  7. package/lib/plugins/database-plugin.js +1 -1
  8. package/lib/process-message.js +2 -2
  9. package/lib/provider-config.js +0 -16
  10. package/lib/recovery.js +2 -12
  11. package/lib/routes-agent-actions.js +2 -58
  12. package/lib/routes-debug.js +1 -7
  13. package/lib/routes-registry.js +5 -17
  14. package/lib/server-startup.js +1 -59
  15. package/lib/stream-event-handler.js +1 -3
  16. package/lib/ws-handlers-session2.js +2 -23
  17. package/lib/ws-handlers-util.js +106 -175
  18. package/lib/ws-legacy-handlers.js +1 -104
  19. package/lib/ws-setup.js +1 -3
  20. package/package.json +1 -15
  21. package/server.js +9 -26
  22. package/test.js +1 -21
  23. package/ecosystem.config.cjs +0 -22
  24. package/lib/checkpoint-manager.js +0 -182
  25. package/lib/db-queries-tools.js +0 -131
  26. package/lib/db-queries-voice.js +0 -85
  27. package/lib/oauth-codex.js +0 -164
  28. package/lib/oauth-common.js +0 -92
  29. package/lib/oauth-gemini.js +0 -199
  30. package/lib/plugins/auth-plugin.js +0 -132
  31. package/lib/plugins/speech-plugin.js +0 -72
  32. package/lib/plugins/tools-plugin.js +0 -120
  33. package/lib/pm2-manager.js +0 -170
  34. package/lib/routes-oauth.js +0 -105
  35. package/lib/routes-speech.js +0 -173
  36. package/lib/routes-tools.js +0 -184
  37. package/lib/speech-manager.js +0 -200
  38. package/lib/speech.js +0 -50
  39. package/lib/tool-install-machine.js +0 -157
  40. package/lib/tool-manager.js +0 -98
  41. package/lib/tool-provisioner.js +0 -98
  42. package/lib/tool-spawner.js +0 -163
  43. package/lib/tool-version-check.js +0 -196
  44. package/lib/tool-version-fetch.js +0 -68
  45. package/lib/ws-handlers-oauth.js +0 -76
  46. package/static/js/agent-auth-oauth.js +0 -159
  47. package/static/js/pm2-monitor.js +0 -151
  48. package/static/js/stt-handler.js +0 -147
  49. package/static/js/tool-install-machine.js +0 -155
  50. package/static/js/tools-manager-ui.js +0 -124
  51. package/static/js/tools-manager.js +0 -172
  52. package/static/js/voice-machine.js +0 -145
  53. package/static/js/voice.js +0 -134
package/lib/recovery.js CHANGED
@@ -1,4 +1,4 @@
1
- export function createRecovery({ activeExecutions, processMessageWithStreaming, queries, broadcastSync, checkpointManager, drainMessageQueue, stuckThresholdMs, noPidGracePeriodMs }) {
1
+ export function createRecovery({ activeExecutions, processMessageWithStreaming, queries, broadcastSync, drainMessageQueue, stuckThresholdMs, noPidGracePeriodMs }) {
2
2
  function isProcessAlive(pid) {
3
3
  try {
4
4
  process.kill(pid, 0);
@@ -45,15 +45,11 @@ export function createRecovery({ activeExecutions, processMessageWithStreaming,
45
45
  async function resumeConversation(conversationId, previousSessionId, reason) {
46
46
  const conv = queries.getConversation(conversationId);
47
47
  if (!conv) throw new Error('Conversation not found');
48
- const checkpoint = previousSessionId ? checkpointManager.loadCheckpoint(previousSessionId) : null;
49
48
  if (previousSessionId) {
50
49
  const prev = queries.getSession ? queries.getSession(previousSessionId) : null;
51
50
  if (prev && prev.status !== 'interrupted') {
52
51
  queries.updateSession(previousSessionId, { status: 'interrupted', error: reason || 'Restarting', completed_at: Date.now() });
53
52
  }
54
- if (checkpoint) {
55
- checkpointManager.markSessionResumed(previousSessionId);
56
- }
57
53
  }
58
54
  const lastMsg = queries.getLastUserMessage(conversationId);
59
55
  const promptText = typeof lastMsg?.content === 'string' ? lastMsg.content : JSON.stringify(lastMsg?.content || 'continue');
@@ -61,8 +57,7 @@ export function createRecovery({ activeExecutions, processMessageWithStreaming,
61
57
  queries.createEvent('session.created', {
62
58
  sessionId: session.id,
63
59
  resumeReason: 'interrupted',
64
- claudeSessionId: conv.claudeSessionId,
65
- checkpointFrom: previousSessionId || null
60
+ claudeSessionId: conv.claudeSessionId
66
61
  }, conversationId, session.id);
67
62
  activeExecutions.set(conversationId, {
68
63
  pid: null,
@@ -76,13 +71,8 @@ export function createRecovery({ activeExecutions, processMessageWithStreaming,
76
71
  conversationId,
77
72
  agentId: conv.agentType,
78
73
  resumed: true,
79
- checkpointAvailable: !!checkpoint,
80
74
  timestamp: Date.now()
81
75
  });
82
- if (checkpoint) {
83
- checkpointManager.storeCheckpointForDelay(conversationId, checkpoint);
84
- console.log(`[RESUME] Checkpoint stored for conv ${conversationId}`);
85
- }
86
76
  console.log(`[RESUME] Restarting conv ${conversationId} (reason: ${reason})`);
87
77
  await processMessageWithStreaming(conversationId, lastMsg?.id || null, session.id, promptText, conv.agentType, conv.model, conv.subAgent);
88
78
  }
@@ -2,7 +2,7 @@ import os from 'os';
2
2
  import { spawn } from 'child_process';
3
3
 
4
4
  export function register(deps) {
5
- const { sendJSON, queries, broadcastSync, discoveredAgents, activeScripts, startGeminiOAuth, startCodexOAuth, getGeminiOAuthState, getCodexOAuthState, modelCache, PORT, BASE_URL, rootDir } = deps;
5
+ const { sendJSON, queries, broadcastSync, discoveredAgents, activeScripts, modelCache } = deps;
6
6
 
7
7
  const routes = {};
8
8
 
@@ -17,68 +17,12 @@ export function register(deps) {
17
17
  const agent = discoveredAgents.find(a => a.id === agentId);
18
18
  if (!agent) { sendJSON(req, res, 404, { error: 'Agent not found' }); return; }
19
19
 
20
- if (agentId === 'codex' || agentId === 'cli-codex') {
21
- try {
22
- const result = await startCodexOAuth(req, { PORT, BASE_URL });
23
- const conversationId = '__agent_auth__';
24
- broadcastSync({ type: 'script_started', conversationId, script: 'auth-codex', agentId: 'codex', timestamp: Date.now() });
25
- broadcastSync({ type: 'script_output', conversationId, data: `\x1b[36mOpening OpenAI OAuth in your browser...\x1b[0m\r\n\r\nIf it doesn't open automatically, visit:\r\n${result.authUrl}\r\n`, stream: 'stdout', timestamp: Date.now() });
26
- const pollId = setInterval(() => {
27
- const state = getCodexOAuthState();
28
- if (state.status === 'success') {
29
- clearInterval(pollId);
30
- const email = state.email || '';
31
- broadcastSync({ type: 'script_output', conversationId, data: `\r\n\x1b[32mAuthentication successful${email ? ' (' + email + ')' : ''}\x1b[0m\r\n`, stream: 'stdout', timestamp: Date.now() });
32
- broadcastSync({ type: 'script_stopped', conversationId, code: 0, timestamp: Date.now() });
33
- } else if (state.status === 'error') {
34
- clearInterval(pollId);
35
- broadcastSync({ type: 'script_output', conversationId, data: `\r\n\x1b[31mAuthentication failed: ${state.error}\x1b[0m\r\n`, stream: 'stderr', timestamp: Date.now() });
36
- broadcastSync({ type: 'script_stopped', conversationId, code: 1, error: state.error, timestamp: Date.now() });
37
- }
38
- }, 1000);
39
- setTimeout(() => clearInterval(pollId), 5 * 60 * 1000);
40
- sendJSON(req, res, 200, { ok: true, agentId, authUrl: result.authUrl, mode: result.mode });
41
- } catch (e) {
42
- console.error('[codex-oauth] /api/agents/codex/auth failed:', e);
43
- sendJSON(req, res, 500, { error: e.message });
44
- }
45
- return;
46
- }
47
-
48
- if (agentId === 'gemini') {
49
- try {
50
- const result = await startGeminiOAuth(req, { PORT, BASE_URL, rootDir });
51
- const conversationId = '__agent_auth__';
52
- broadcastSync({ type: 'script_started', conversationId, script: 'auth-gemini', agentId: 'gemini', timestamp: Date.now() });
53
- broadcastSync({ type: 'script_output', conversationId, data: `\x1b[36mOpening Google OAuth in your browser...\x1b[0m\r\n\r\nIf it doesn't open automatically, visit:\r\n${result.authUrl}\r\n`, stream: 'stdout', timestamp: Date.now() });
54
- const pollId = setInterval(() => {
55
- const state = getGeminiOAuthState();
56
- if (state.status === 'success') {
57
- clearInterval(pollId);
58
- const email = state.email || '';
59
- broadcastSync({ type: 'script_output', conversationId, data: `\r\n\x1b[32mAuthentication successful${email ? ' (' + email + ')' : ''}\x1b[0m\r\n`, stream: 'stdout', timestamp: Date.now() });
60
- broadcastSync({ type: 'script_stopped', conversationId, code: 0, timestamp: Date.now() });
61
- } else if (state.status === 'error') {
62
- clearInterval(pollId);
63
- broadcastSync({ type: 'script_output', conversationId, data: `\r\n\x1b[31mAuthentication failed: ${state.error}\x1b[0m\r\n`, stream: 'stderr', timestamp: Date.now() });
64
- broadcastSync({ type: 'script_stopped', conversationId, code: 1, error: state.error, timestamp: Date.now() });
65
- }
66
- }, 1000);
67
- setTimeout(() => clearInterval(pollId), 5 * 60 * 1000);
68
- sendJSON(req, res, 200, { ok: true, agentId, authUrl: result.authUrl, mode: result.mode });
69
- } catch (e) {
70
- console.error('[gemini-oauth] /api/agents/gemini/auth failed:', e);
71
- sendJSON(req, res, 500, { error: e.message });
72
- }
73
- return;
74
- }
75
-
76
20
  const authCommands = {
77
21
  'claude-code': { cmd: 'claude', args: ['setup-token'] },
78
22
  'opencode': { cmd: 'opencode', args: ['auth', 'login'] },
79
23
  };
80
24
  const authCmd = authCommands[agentId];
81
- if (!authCmd) { sendJSON(req, res, 400, { error: 'No auth command for this agent' }); return; }
25
+ if (!authCmd) { sendJSON(req, res, 400, { error: 'No auth command for this agent (OAuth flows removed; configure provider key via /api/auth/save-config)' }); return; }
82
26
  const conversationId = '__agent_auth__';
83
27
  if (activeScripts.has(conversationId)) { sendJSON(req, res, 409, { error: 'Auth process already running' }); return; }
84
28
  const child = spawn(authCmd.cmd, authCmd.args, { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, FORCE_COLOR: '1' }, shell: os.platform() === 'win32' });
@@ -1,16 +1,10 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
- import * as toolInstallMachine from './tool-install-machine.js';
5
4
  import * as execMachine from './execution-machine.js';
6
5
  import * as acpServerMachine from './acp-server-machine.js';
7
6
 
8
7
  function collectMachineSnapshots(activeExecutions) {
9
- const toolInstall = {};
10
- for (const [id, actor] of toolInstallMachine.getMachineActors()) {
11
- const s = actor.getSnapshot();
12
- toolInstall[id] = { state: s.value, context: s.context };
13
- }
14
8
  const execution = {};
15
9
  for (const id of activeExecutions.keys()) {
16
10
  const s = execMachine.snapshot(id);
@@ -21,7 +15,7 @@ function collectMachineSnapshots(activeExecutions) {
21
15
  const s = actor.getSnapshot();
22
16
  acpServer[id] = { state: s.value, context: { pid: s.context.pid, healthy: s.context.healthy, startedAt: s.context.startedAt, lastUsed: s.context.lastUsed, restarts: s.context.restarts?.length || 0, providerInfo: s.context.providerInfo } };
23
17
  }
24
- return { toolInstall, execution, acpServer };
18
+ return { execution, acpServer };
25
19
  }
26
20
 
27
21
  function readRecentErrors(errLogPath, limit = 50) {
@@ -1,7 +1,4 @@
1
- import { register as registerSpeechRoutes } from './routes-speech.js';
2
- import { register as registerOAuthRoutes } from './routes-oauth.js';
3
1
  import { register as registerUtilRoutes } from './routes-util.js';
4
- import { register as registerToolRoutes } from './routes-tools.js';
5
2
  import { register as registerThreadRoutes } from './routes-threads.js';
6
3
  import { register as registerDebugRoutes } from './routes-debug.js';
7
4
  import { register as registerConvRoutes } from './routes-conversations.js';
@@ -18,24 +15,16 @@ import { register as registerSessionHandlers } from './ws-handlers-session.js';
18
15
  import { register as registerSessionHandlers2 } from './ws-handlers-session2.js';
19
16
  import { register as registerRunHandlers } from './ws-handlers-run.js';
20
17
  import { register as registerUtilHandlers } from './ws-handlers-util.js';
21
- import { register as registerOAuthHandlers } from './ws-handlers-oauth.js';
22
18
  import { register as registerScriptHandlers } from './ws-handlers-scripts.js';
23
19
  import { register as registerQueueHandlers } from './ws-handlers-queue.js';
24
20
  import { register as registerMsgHandlers } from './ws-handlers-msg.js';
25
- import { initSpeechManager, getSpeech, voiceCacheManager, modelDownloadState, ensureModelsDownloaded } from './speech-manager.js';
26
21
  import { getAgentDescriptor } from './agent-descriptors.js';
27
- import { startGeminiOAuth, exchangeGeminiOAuthCode, getGeminiOAuthState } from './oauth-gemini.js';
28
- import { startCodexOAuth, exchangeCodexOAuthCode, getCodexOAuthState } from './oauth-codex.js';
29
22
  import { getProviderConfigs, saveProviderConfig } from './provider-config.js';
30
23
 
31
24
  export function createRegistry(wsRouter, deps) {
32
- const { queries, sendJSON, parseBody, broadcastSync, debugLog, PORT, BASE_URL, rootDir, STARTUP_CWD, PKG_VERSION, processMessageWithStreaming, activeExecutions, activeProcessesByRunId, activeScripts, messageQueues, rateLimitState, cleanupExecution, discoveredAgents, getACPStatus, modelCache, getModelsForAgent, logError, toolManager, syncClients, wsOptimizer, errLogPath, getJsonlWatcher, routes } = deps;
25
+ const { queries, sendJSON, parseBody, broadcastSync, debugLog, PORT, BASE_URL, rootDir, STARTUP_CWD, PKG_VERSION, processMessageWithStreaming, activeExecutions, activeProcessesByRunId, activeScripts, messageQueues, rateLimitState, cleanupExecution, discoveredAgents, getACPStatus, modelCache, getModelsForAgent, logError, syncClients, wsOptimizer, errLogPath, getJsonlWatcher, routes } = deps;
33
26
 
34
- initSpeechManager({ broadcastSync, syncClients, queries });
35
- routes.speech = registerSpeechRoutes({ sendJSON, parseBody, broadcastSync, debugLog });
36
- routes.oauth = registerOAuthRoutes({ sendJSON, parseBody, PORT, BASE_URL, rootDir });
37
27
  routes.util = registerUtilRoutes({ sendJSON, parseBody, queries, STARTUP_CWD, PKG_VERSION });
38
- routes.tools = registerToolRoutes({ sendJSON, parseBody, queries, broadcastSync, logError, toolManager });
39
28
  routes.threads = registerThreadRoutes({ sendJSON, parseBody, queries });
40
29
  routes.debug = registerDebugRoutes({ sendJSON, queries, activeExecutions, messageQueues, syncClients, wsOptimizer, _errLogPath: errLogPath });
41
30
  routes.conv = registerConvRoutes({ sendJSON, parseBody, queries, activeExecutions, broadcastSync });
@@ -44,7 +33,7 @@ export function createRegistry(wsRouter, deps) {
44
33
  routes.sessions = registerSessionsRoutes({ queries, sendJSON, activeExecutions, rateLimitState, debugLog });
45
34
  routes.runs = registerRunsRoutes({ sendJSON, parseBody, queries, broadcastSync, processMessageWithStreaming, activeExecutions, activeProcessesByRunId, discoveredAgents, STARTUP_CWD });
46
35
  routes.scripts = registerScriptsRoutes({ sendJSON, parseBody, queries, broadcastSync, activeScripts, activeExecutions, processMessageWithStreaming, STARTUP_CWD });
47
- routes.agentActions = registerAgentActionsRoutes({ sendJSON, queries, broadcastSync, discoveredAgents, activeScripts, startGeminiOAuth, startCodexOAuth, getGeminiOAuthState, getCodexOAuthState, modelCache, PORT, BASE_URL, rootDir });
36
+ routes.agentActions = registerAgentActionsRoutes({ sendJSON, queries, broadcastSync, discoveredAgents, activeScripts, modelCache, PORT, BASE_URL, rootDir });
48
37
  routes.authConfig = registerAuthConfigRoutes({ sendJSON, parseBody, getProviderConfigs, saveProviderConfig });
49
38
 
50
39
  registerConvHandlers(wsRouter, { queries, activeExecutions, rateLimitState, broadcastSync, processMessageWithStreaming, cleanupExecution, getJsonlWatcher });
@@ -52,11 +41,10 @@ export function createRegistry(wsRouter, deps) {
52
41
  registerMsgHandlers(wsRouter, { queries, activeExecutions, messageQueues, broadcastSync, processMessageWithStreaming, logError });
53
42
  registerQueueHandlers(wsRouter, { queries, messageQueues, broadcastSync });
54
43
  debugLog('[INIT] registerSessionHandlers, agents: ' + discoveredAgents.length);
55
- registerSessionHandlers(wsRouter, { db: queries, discoveredAgents, modelCache, getAgentDescriptor, activeScripts, broadcastSync, startGeminiOAuth: (req) => startGeminiOAuth(req, { PORT, BASE_URL, rootDir }), geminiOAuthState: getGeminiOAuthState });
56
- registerSessionHandlers2(wsRouter, { discoveredAgents, modelCache, activeScripts, broadcastSync, startGeminiOAuth: (req) => startGeminiOAuth(req, { PORT, BASE_URL, rootDir }), geminiOAuthState: getGeminiOAuthState });
44
+ registerSessionHandlers(wsRouter, { db: queries, discoveredAgents, modelCache, getAgentDescriptor, activeScripts, broadcastSync });
45
+ registerSessionHandlers2(wsRouter, { discoveredAgents, modelCache, activeScripts, broadcastSync });
57
46
  debugLog('[INIT] registerSessionHandlers completed');
58
47
  registerRunHandlers(wsRouter, { queries, discoveredAgents, activeExecutions, activeProcessesByRunId, broadcastSync, processMessageWithStreaming, cleanupExecution });
59
- registerUtilHandlers(wsRouter, { queries, wsOptimizer, modelDownloadState, ensureModelsDownloaded, broadcastSync, getSpeech, getProviderConfigs, saveProviderConfig, STARTUP_CWD, voiceCacheManager, toolManager, discoveredAgents });
48
+ registerUtilHandlers(wsRouter, { queries, wsOptimizer, broadcastSync, getProviderConfigs, saveProviderConfig, STARTUP_CWD, discoveredAgents });
60
49
  registerScriptHandlers(wsRouter, { queries, broadcastSync, STARTUP_CWD, activeScripts });
61
- registerOAuthHandlers(wsRouter, { startGeminiOAuth: (req) => startGeminiOAuth(req, { PORT, BASE_URL, rootDir }), exchangeGeminiOAuthCode, geminiOAuthState: getGeminiOAuthState, startCodexOAuth: (req) => startCodexOAuth(req, { PORT, BASE_URL }), exchangeCodexOAuthCode, codexOAuthState: getCodexOAuthState });
62
50
  }
@@ -1,12 +1,11 @@
1
1
  import { JsonlWatcher } from './jsonl-watcher.js';
2
2
 
3
- export function createOnServerReady({ queries, broadcastSync, warmAssetCache, staticDir, toolManager, discoveredAgents, PORT, BASE_URL, watch, setWatcher, resumeInterruptedStreams, activeExecutions, debugLog, installGMAgentConfigs, startACPTools, getACPStatus, execMachine, toolInstallMachine, getSpeech, ensureModelsDownloaded, performAutoImport, performAgentHealthCheck, pm2Manager, pm2Subscribers, recoverStaleSessions }) {
3
+ export function createOnServerReady({ queries, broadcastSync, warmAssetCache, staticDir, discoveredAgents, PORT, BASE_URL, watch, setWatcher, resumeInterruptedStreams, activeExecutions, debugLog, installGMAgentConfigs, startACPTools, getACPStatus, execMachine, performAutoImport, performAgentHealthCheck, recoverStaleSessions }) {
4
4
  let jsonlWatcher = null;
5
5
 
6
6
  function getJsonlWatcher() { return jsonlWatcher; }
7
7
 
8
8
  function onServerReady() {
9
- toolManager.clearStatusCache();
10
9
  console.log(`GMGUI running on http://localhost:${PORT}${BASE_URL}/`);
11
10
  console.log(`Agents: ${discoveredAgents.map(a => a.name).join(', ') || 'none'}`);
12
11
  console.log(`Hot reload: ${watch ? 'on' : 'off'}`);
@@ -55,66 +54,9 @@ export function createOnServerReady({ queries, broadcastSync, warmAssetCache, st
55
54
  }, 6000);
56
55
  }).catch(err => console.error('[ACP] Startup error:', err.message));
57
56
 
58
- const toolIds = ['cli-claude', 'cli-opencode', 'cli-gemini', 'cli-kilo', 'cli-codex', 'cli-agent-browser', 'gm-cc', 'gm-oc', 'gm-gc', 'gm-kilo', 'gm-codex'];
59
- queries.initializeToolInstallations(toolIds.map(id => ({ id })));
60
- console.log('[TOOLS] Starting background provisioning...');
61
-
62
- const toolBroadcaster = (evt) => {
63
- broadcastSync(evt);
64
- if (evt.type === 'tool_install_complete' || evt.type === 'tool_update_complete') {
65
- const d = evt.data || {};
66
- queries.updateToolStatus(evt.toolId, { status: 'installed', version: d.version || null, installed_at: Date.now() });
67
- queries.addToolInstallHistory(evt.toolId, evt.type.includes('update') ? 'update' : 'install', 'success', null);
68
- } else if (evt.type === 'tool_install_failed' || evt.type === 'tool_update_failed') {
69
- queries.updateToolStatus(evt.toolId, { status: 'failed', error_message: evt.data?.error });
70
- queries.addToolInstallHistory(evt.toolId, evt.type.includes('update') ? 'update' : 'install', 'failed', evt.data?.error);
71
- } else if (evt.type === 'tool_status_update') {
72
- const d = evt.data || {};
73
- if (d.installed) queries.updateToolStatus(evt.toolId, { status: 'installed', version: d.installedVersion || null, installed_at: Date.now() });
74
- }
75
- };
76
-
77
- toolManager.autoProvision(toolBroadcaster)
78
- .catch(err => console.error('[TOOLS] Auto-provision error:', err.message))
79
- .then(() => {
80
- const acpActors = ['opencode', 'kilo', 'codex'];
81
- console.log(`[MACHINES] tool-install: ${toolInstallMachine.getMachineActors().size} actors, acp-server: ${acpActors.length} configured`);
82
- console.log('[TOOLS] Starting periodic update checker...');
83
- toolManager.startPeriodicUpdateCheck(toolBroadcaster);
84
- });
85
-
86
- ensureModelsDownloaded().then(async ok => {
87
- if (ok) console.log('[MODELS] Speech models ready');
88
- else console.log('[MODELS] Speech model download failed');
89
- try { const { getVoices } = await getSpeech(); broadcastSync({ type: 'voice_list', voices: getVoices() }); }
90
- catch (err) { debugLog('[VOICE] Failed to broadcast voices: ' + err.message); broadcastSync({ type: 'voice_list', voices: [] }); }
91
- }).catch(async err => {
92
- console.error('[MODELS] Download error:', err.message);
93
- try { const { getVoices } = await getSpeech(); broadcastSync({ type: 'voice_list', voices: getVoices() }); }
94
- catch (err2) { debugLog('[VOICE] Failed to broadcast voices: ' + err2.message); broadcastSync({ type: 'voice_list', voices: [] }); }
95
- });
96
-
97
- getSpeech().then(s => s.preloadTTS()).catch(e => debugLog('[TTS] Preload failed: ' + e.message));
98
57
  performAutoImport();
99
58
  setInterval(performAutoImport, 30000);
100
59
  setInterval(performAgentHealthCheck, 30000);
101
-
102
- const broadcastPM2 = (update) => {
103
- const msg = JSON.stringify(update);
104
- for (const client of pm2Subscribers) { if (client.readyState === 1) { try { client.send(msg); } catch (_) {} } }
105
- };
106
-
107
- const startPM2Monitoring = async () => {
108
- try { await pm2Manager.connect(); await pm2Manager.startMonitoring(broadcastPM2); console.log('[PM2] Monitoring started'); }
109
- catch (err) { console.log('[PM2] Not available:', err.message); broadcastPM2({ type: 'pm2_unavailable', reason: err.message, timestamp: Date.now() }); }
110
- };
111
-
112
- setTimeout(startPM2Monitoring, 2000);
113
- setInterval(async () => {
114
- if (!pm2Manager.connected && !pm2Manager.monitoring) {
115
- try { const healed = await pm2Manager.heal(); if (healed.success) await pm2Manager.startMonitoring(broadcastPM2); } catch (_) {}
116
- }
117
- }, 30000);
118
60
  }
119
61
 
120
62
  return { onServerReady, getJsonlWatcher };
@@ -11,7 +11,7 @@
11
11
  * No JSONL file is written. This handler broadcasts streaming_start,
12
12
  * streaming_progress blocks, and persists chunks to the DB.
13
13
  */
14
- export function createEventHandler({ queries, activeExecutions, broadcastSync, rateLimitState, batcherRef, sessionId, conversationId, messageId, content, agentId, model, subAgent, isJsonlBacked, getJsonlWatcher, scheduleRetry, eagerTTS, debugLog, parseRateLimitResetTime }) {
14
+ export function createEventHandler({ queries, activeExecutions, broadcastSync, rateLimitState, batcherRef, sessionId, conversationId, messageId, content, agentId, model, subAgent, isJsonlBacked, getJsonlWatcher, scheduleRetry, debugLog, parseRateLimitResetTime }) {
15
15
  return function onEvent(parsed) {
16
16
  batcherRef.eventCount++;
17
17
  const entry = activeExecutions.get(conversationId);
@@ -91,7 +91,6 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
91
91
  }, retryAfterSec * 1000);
92
92
  return;
93
93
  }
94
- eagerTTS(block.text, conversationId, sessionId);
95
94
  }
96
95
  }
97
96
  }
@@ -125,7 +124,6 @@ export function createEventHandler({ queries, activeExecutions, broadcastSync, r
125
124
  }, retryAfterSec * 1000);
126
125
  return;
127
126
  }
128
- if (resultText) eagerTTS(resultText, conversationId, sessionId);
129
127
  }
130
128
  };
131
129
  }
@@ -61,35 +61,14 @@ function checkAgentAuth(agent) {
61
61
  }
62
62
 
63
63
  export function register(router, deps) {
64
- const { discoveredAgents, modelCache, activeScripts, broadcastSync,
65
- startGeminiOAuth, geminiOAuthState } = deps;
64
+ const { discoveredAgents, modelCache, activeScripts, broadcastSync } = deps;
66
65
 
67
66
  router.handle('agent.auth', async (p) => {
68
67
  const agentId = p.id;
69
68
  if (!discoveredAgents.find(a => a.id === agentId)) throw { code: 404, message: 'Agent not found' };
70
- if (agentId === 'gemini') {
71
- const result = await startGeminiOAuth();
72
- const cid = '__agent_auth__';
73
- broadcastSync({ type: 'script_started', conversationId: cid, script: 'auth-gemini', agentId: 'gemini', timestamp: Date.now() });
74
- broadcastSync({ type: 'script_output', conversationId: cid, data: `\x1b[36mOpening Google OAuth...\x1b[0m\r\n\r\nVisit:\r\n${result.authUrl}\r\n`, stream: 'stdout', timestamp: Date.now() });
75
- const pollId = setInterval(() => {
76
- const st = geminiOAuthState();
77
- if (st.status === 'success') {
78
- clearInterval(pollId);
79
- broadcastSync({ type: 'script_output', conversationId: cid, data: `\r\n\x1b[32mAuth OK${st.email ? ' (' + st.email + ')' : ''}\x1b[0m\r\n`, stream: 'stdout', timestamp: Date.now() });
80
- broadcastSync({ type: 'script_stopped', conversationId: cid, code: 0, timestamp: Date.now() });
81
- } else if (st.status === 'error') {
82
- clearInterval(pollId);
83
- broadcastSync({ type: 'script_output', conversationId: cid, data: `\r\n\x1b[31mAuth failed: ${st.error}\x1b[0m\r\n`, stream: 'stderr', timestamp: Date.now() });
84
- broadcastSync({ type: 'script_stopped', conversationId: cid, code: 1, error: st.error, timestamp: Date.now() });
85
- }
86
- }, 1000);
87
- setTimeout(() => clearInterval(pollId), 5 * 60 * 1000);
88
- return { ok: true, agentId, authUrl: result.authUrl, mode: result.mode };
89
- }
90
69
  const cmds = { 'claude-code': { cmd: 'claude', args: ['setup-token'] }, 'opencode': { cmd: 'opencode', args: ['auth', 'login'] } };
91
70
  const c = cmds[agentId];
92
- if (!c) throw { code: 400, message: 'No auth command for this agent' };
71
+ if (!c) throw { code: 400, message: 'No auth command for this agent (OAuth flows removed; configure provider key via /api/auth/save-config)' };
93
72
  const pid = spawnScript(c.cmd, c.args, '__agent_auth__', 'auth-' + agentId, agentId, { activeScripts, broadcastSync });
94
73
  return { ok: true, agentId, pid };
95
74
  });