config.ts
1 import type { PluginError } from '../../types/plugin.js' 2 import { logForDebugging } from '../../utils/debug.js' 3 import { errorMessage, toError } from '../../utils/errors.js' 4 import { logError } from '../../utils/log.js' 5 import { getPluginLspServers } from '../../utils/plugins/lspPluginIntegration.js' 6 import { loadAllPluginsCacheOnly } from '../../utils/plugins/pluginLoader.js' 7 import type { ScopedLspServerConfig } from './types.js' 8 9 /** 10 * Get all configured LSP servers from plugins. 11 * LSP servers are only supported via plugins, not user/project settings. 12 * 13 * @returns Object containing servers configuration keyed by scoped server name 14 */ 15 export async function getAllLspServers(): Promise<{ 16 servers: Record<string, ScopedLspServerConfig> 17 }> { 18 const allServers: Record<string, ScopedLspServerConfig> = {} 19 20 try { 21 // Get all enabled plugins 22 const { enabled: plugins } = await loadAllPluginsCacheOnly() 23 24 // Load LSP servers from each plugin in parallel. 25 // Each plugin is independent — results are merged in original order so 26 // Object.assign collision precedence (later plugins win) is preserved. 27 const results = await Promise.all( 28 plugins.map(async plugin => { 29 const errors: PluginError[] = [] 30 try { 31 const scopedServers = await getPluginLspServers(plugin, errors) 32 return { plugin, scopedServers, errors } 33 } catch (e) { 34 // Defensive: if one plugin throws, don't lose results from the 35 // others. The previous serial loop implicitly tolerated this. 36 logForDebugging( 37 `Failed to load LSP servers for plugin ${plugin.name}: ${e}`, 38 { level: 'error' }, 39 ) 40 return { plugin, scopedServers: undefined, errors } 41 } 42 }), 43 ) 44 45 for (const { plugin, scopedServers, errors } of results) { 46 const serverCount = scopedServers ? Object.keys(scopedServers).length : 0 47 if (serverCount > 0) { 48 // Merge into all servers (already scoped by getPluginLspServers) 49 Object.assign(allServers, scopedServers) 50 51 logForDebugging( 52 `Loaded ${serverCount} LSP server(s) from plugin: ${plugin.name}`, 53 ) 54 } 55 56 // Log any errors encountered 57 if (errors.length > 0) { 58 logForDebugging( 59 `${errors.length} error(s) loading LSP servers from plugin: ${plugin.name}`, 60 ) 61 } 62 } 63 64 logForDebugging( 65 `Total LSP servers loaded: ${Object.keys(allServers).length}`, 66 ) 67 } catch (error) { 68 // Log error for monitoring production issues. 69 // LSP is optional, so we don't throw - but we need visibility 70 // into why plugin loading fails to improve the feature. 71 logError(toError(error)) 72 73 logForDebugging(`Error loading LSP servers: ${errorMessage(error)}`) 74 } 75 76 return { 77 servers: allServers, 78 } 79 }