diff --git a/package.json b/package.json index 7c3272eeb..fda5a1518 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "babel-plugin-prismjs": "^2.1.0", "chai": "^4.1.2", "electron": "^22.0.0", - "electron-devtools-installer": "^3.2.0", + "electron-devtools-installer": "^3.1.1", "eslint": "6.5.1", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", diff --git a/src/background.ts b/src/background.ts index 0ef172ecf..78ffbab16 100644 --- a/src/background.ts +++ b/src/background.ts @@ -2,7 +2,6 @@ import 'reflect-metadata' // Required by TypoORM. ;('use strict') import { app, protocol, BrowserWindow, ipcMain, shell, Menu } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' -import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' import { quitAndRenameLogger } from './utils/logger' import { defaultWindowSize, restoreWindowState, saveWindowState } from './utils/windowStateManager' import rebuildDatabase from './database/rebuildDatabase' @@ -43,6 +42,9 @@ protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: tru const { ConnectionInit, ConnectionDestroy } = useConnection() +// Flag to track if connections have been destroyed +let connectionsDestroyed = false + function handleIpcMessages() { ipcMain.on('setting', (event: Electron.IpcMainEvent, ...args: any[]) => { event.sender.send('setting', ...args) @@ -120,10 +122,16 @@ function handleIpcMessages() { function beforeAppQuit() { // close all log appender and rename log file with date quitAndRenameLogger() - // close all SQLite connection - ConnectionDestroy() + + // close all SQLite connection - only if not already destroyed + if (!connectionsDestroyed) { + connectionsDestroyed = true + ConnectionDestroy() + } + // cleanup MCP connections cleanupMCPConnections() + // quit APP app.quit() } @@ -246,10 +254,12 @@ async function createWindow() { // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', async () => { + // Install Vue Devtools on development mode if (isDevelopment && !process.env.IS_TEST) { - // Install Vue Devtools try { - await installExtension(VUEJS_DEVTOOLS) + const installExtension = require('electron-devtools-installer').default + await installExtension('iaajmlceplecbljialhhkmedjlpdblhp') + console.log('Vue Devtools installed successfully') } catch (e) { console.error('Vue Devtools failed to install:', e) } diff --git a/src/components/ai/Copilot.vue b/src/components/ai/Copilot.vue index b4670a7af..1285283dc 100644 --- a/src/components/ai/Copilot.vue +++ b/src/components/ai/Copilot.vue @@ -205,6 +205,7 @@ export default class Copilot extends Vue { const throttledScroll = throttle(() => this.scrollToBottom(), 100) this.abortController = new AbortController() + this.$log.info(`[Copilot] AI response stream started with provider: "${this.model}" from "${this.openAIAPIHost}"`) const { textStream } = streamText({ model: getModelProvider({ model: this.model, @@ -226,8 +227,6 @@ export default class Copilot extends Vue { if (this.shouldProcessMCP) { const processedContent = await processMCPCalls(this.responseStreamText) responseMessage.content = processedContent - // AI TOOL CALL RESULT - console.log(processedContent) } else { responseMessage.content = this.responseStreamText } @@ -372,7 +371,7 @@ export default class Copilot extends Vue { } @keyframes rightbarPop { from { - right: -45%; + right: -50%; } to { right: 0px; @@ -382,7 +381,7 @@ export default class Copilot extends Vue { box-shadow: -2px 0px 8px 0px var(--color-shadow-leftlist); position: fixed; right: 0px; - width: 45%; + width: 50%; background: var(--color-bg-normal); border-radius: 0; top: 0; diff --git a/src/database/useConnection.ts b/src/database/useConnection.ts index a2d00a26c..5a43a2260 100644 --- a/src/database/useConnection.ts +++ b/src/database/useConnection.ts @@ -20,7 +20,16 @@ const useConnection = () => { } async function ConnectionDestroy() { if (sqlConnection) { - await sqlConnection.close() + try { + if (sqlConnection.isConnected) { + await sqlConnection.close() + } + } catch (error) { + console.error('[Database] Error closing database connection:', error) + // Gracefully handle errors during connection close + } finally { + sqlConnection = undefined + } } } return { diff --git a/src/main/ai/mcp/MCPManager.ts b/src/main/ai/mcp/MCPManager.ts index 1cf7d5407..f4567f86d 100644 --- a/src/main/ai/mcp/MCPManager.ts +++ b/src/main/ai/mcp/MCPManager.ts @@ -18,7 +18,7 @@ const activeClients: Map = new Map() export function initMCPHandlers(): void { // Test connection to a server ipcMain.handle('mcp:test-connection', async (_, serverConfig: MCPServer, serverName: string) => { - console.log(`Testing connection to MCP server: ${serverName}`) + console.log(`[MCP] Testing connection to MCP server: ${serverName}`) try { const client = new MCPClient() const connected = await client.connectToServer(serverConfig) @@ -60,16 +60,16 @@ export function initMCPHandlers(): void { // Call a tool on a specific server ipcMain.handle('mcp:call-tool', async (_, serverName: string, toolName: string, toolArgs: any) => { - console.log(`Calling tool ${toolName} on server ${serverName}`) + console.log(`[MCP] Calling tool ${toolName} on server ${serverName}`) try { const client = activeClients.get(serverName) if (!client) { - // 如果服务器未连接,尝试自动连接 + // If server is not connected, try to auto-connect await autoConnectToServer(serverName) const reconnectedClient = activeClients.get(serverName) if (!reconnectedClient) { - throw new Error(`No active connection to server: ${serverName} and auto-reconnect failed`) + throw new Error(`[MCP] No active connection to server: ${serverName} and auto-reconnect failed`) } const result = await reconnectedClient.callTool(toolName, toolArgs) @@ -80,7 +80,7 @@ export function initMCPHandlers(): void { } if (!client.isConnected()) { - throw new Error(`Connection to server ${serverName} has been lost`) + throw new Error(`[MCP] Connection to server ${serverName} has been lost`) } const result = await client.callTool(toolName, toolArgs) @@ -89,7 +89,7 @@ export function initMCPHandlers(): void { result, } } catch (error) { - console.error(`Error calling tool ${toolName} on server ${serverName}:`, error) + console.error(`[MCP] Error calling tool ${toolName} on server ${serverName}:`, error) return { success: false, message: error instanceof Error ? error.message : String(error), @@ -99,7 +99,7 @@ export function initMCPHandlers(): void { // Disconnect from a server ipcMain.handle('mcp:disconnect', async (_, serverName: string) => { - console.log(`Disconnecting from MCP server: ${serverName}`) + console.log(`[MCP] Disconnecting from MCP server: ${serverName}`) try { const client = activeClients.get(serverName) @@ -116,7 +116,7 @@ export function initMCPHandlers(): void { message: `No active connection to server: ${serverName}`, } } catch (error) { - console.error(`Error disconnecting from MCP server: ${serverName}`, error) + console.error(`[MCP] Error disconnecting from MCP server: ${serverName}`, error) return { success: false, message: error instanceof Error ? error.message : String(error), @@ -124,32 +124,32 @@ export function initMCPHandlers(): void { } }) - // 自动连接已启用的 MCP 服务器 + // Auto-connect to enabled MCP servers autoConnectToEnabledServers() } /** - * 自动连接到启用的 MCP 服务器 + * Automatically connect to enabled MCP servers */ async function autoConnectToEnabledServers(): Promise { - console.log('Checking for enabled MCP servers to auto-connect') + console.log('[MCP] Checking for enabled MCP servers to auto-connect') try { - // 从本地存储中读取 MCP 配置 + // Read MCP configuration from local storage const Store = require('electron-store') const store = new Store() - // 检查 MCP 是否启用 + // Check if MCP is enabled const mcpEnabled = store.get('mcpEnabled') if (mcpEnabled !== 'true') { - console.log('MCP is not enabled, skipping auto-connect') + console.log('[MCP] MCP is not enabled, skipping auto-connect') return } - // 获取 MCP 配置 + // Get MCP configuration const mcpConfigStr = store.get('mcpConfig') if (!mcpConfigStr) { - console.log('No MCP configuration found, skipping auto-connect') + console.log('[MCP] No MCP configuration found, skipping auto-connect') return } @@ -157,16 +157,16 @@ async function autoConnectToEnabledServers(): Promise { try { mcpConfig = JSON.parse(mcpConfigStr) } catch (err) { - console.error('Failed to parse MCP configuration:', err) + console.error('[MCP] Failed to parse MCP configuration:', err) return } if (!mcpConfig.mcpServers) { - console.log('No MCP servers configured, skipping auto-connect') + console.log('[MCP] No MCP servers configured, skipping auto-connect') return } - // 连接所有启用的服务器 + // Connect to all enabled servers for (const [serverName, serverConfig] of Object.entries(mcpConfig.mcpServers)) { const serverEnabled = store.get(`mcpServerEnabled:${serverName}`) if (serverEnabled === 'true') { @@ -174,23 +174,23 @@ async function autoConnectToEnabledServers(): Promise { } } - console.log(`Auto-connected to ${activeClients.size} MCP servers`) + console.log(`[MCP] Auto-connected to ${activeClients.size} MCP servers`) } catch (error) { - console.error('Error during MCP auto-connect:', error) + console.error('[MCP] Error during MCP auto-connect:', error) } } /** - * 自动连接到指定的 MCP 服务器 + * Automatically connect to a specific MCP server * - * @param serverName 服务器名称 - * @param serverConfig 服务器配置(可选) + * @param serverName Server name + * @param serverConfig Server configuration (optional) */ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer): Promise { - console.log(`Auto-connecting to MCP server: ${serverName}`) + console.log(`[MCP] Auto-connecting to MCP server: ${serverName}`) try { - // 如果没有提供服务器配置,从存储中获取 + // If server configuration is not provided, get it from storage if (!serverConfig) { const Store = require('electron-store') const store = new Store() @@ -205,35 +205,35 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer) serverConfig = mcpConfig.mcpServers[serverName] as MCPServer if (!serverConfig) { - console.error(`Server configuration for ${serverName} not found`) + console.error(`[MCP] Server configuration for ${serverName} not found`) return false } } catch (err) { - console.error('Failed to parse MCP configuration:', err) + console.error('[MCP] Failed to parse MCP configuration:', err) return false } } - // 检查是否已经有连接 + // Check if connection already exists if (activeClients.has(serverName)) { const existingClient = activeClients.get(serverName) if (existingClient && existingClient.isConnected()) { - console.log(`Server ${serverName} is already connected`) + console.log(`[MCP] Server ${serverName} is already connected`) return true } - // 如果存在但断开连接,先清理 + // If exists but disconnected, clean up first if (existingClient) { try { await existingClient.disconnect() } catch (err) { - console.error(`Error disconnecting existing client for ${serverName}:`, err) + console.error(`[MCP] Error disconnecting existing client for ${serverName}:`, err) } activeClients.delete(serverName) } } - // 创建并连接新客户端 + // Create and connect new client const client = new MCPClient() const connected = await client.connectToServer(serverConfig) @@ -245,11 +245,11 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer) activeClients.set(serverName, client) return true } else { - console.error(`Failed to connect to MCP server: ${serverName}`) + console.error(`[MCP] Failed to connect to MCP server: ${serverName}`) return false } } catch (error) { - console.error(`Error auto-connecting to MCP server ${serverName}:`, error) + console.error(`[MCP] Error auto-connecting to MCP server ${serverName}:`, error) return false } } @@ -258,14 +258,14 @@ async function autoConnectToServer(serverName: string, serverConfig?: MCPServer) * Clean up all active connections */ export async function cleanupMCPConnections(): Promise { - console.log(`Cleaning up ${activeClients.size} MCP connections`) + console.log(`[MCP] Cleaning up ${activeClients.size} MCP connections`) for (const [name, client] of activeClients.entries()) { try { await client.disconnect() - console.log(`Disconnected from MCP server: ${name}`) + console.log(`[MCP] Disconnected from MCP server: ${name}`) } catch (error) { - console.error(`Error disconnecting from MCP server: ${name}`, error) + console.error(`[MCP] Error disconnecting from MCP server: ${name}`, error) } } diff --git a/yarn.lock b/yarn.lock index 7ec834f45..5695ad33f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5282,10 +5282,10 @@ electron-builder@23.6.0, electron-builder@^22.2.0: simple-update-notifier "^1.0.7" yargs "^17.5.1" -electron-devtools-installer@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0" - integrity sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ== +electron-devtools-installer@^3.1.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.1.tgz#338a0ada7b4232ee42cd88fe5cf305c6be95cfe9" + integrity sha512-FaCi+oDCOBTw0gJUsuw5dXW32b2Ekh5jO8lI1NRCQigo3azh2VogsIi0eelMVrP1+LkN/bewyH3Xoo1USjO0eQ== dependencies: rimraf "^3.0.2" semver "^7.2.1"