@@ -202,6 +202,10 @@ async function startInteractiveServer(
202202 console . warn ( `[${ serverId } ] ${ data } ` ) ;
203203 } else if ( type === "stdout" && data && data . trim ( ) ) {
204204 console . info ( `[${ serverId } ] ${ data } ` ) ;
205+ // Detect when the axs proxy signals it's listening
206+ if ( / l i s t e n i n g o n / i. test ( data ) ) {
207+ signalServerReady ( serverId ) ;
208+ }
205209 }
206210 } ;
207211 const uuid = await executor . start ( command , callback , true ) ;
@@ -217,59 +221,68 @@ function sleep(ms: number): Promise<void> {
217221 return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
218222}
219223
224+ /**
225+ * Tracks servers that have signaled they're ready (listening)
226+ * Key: serverId, Value: timestamp when ready
227+ */
228+ const serverReadySignals = new Map < string , number > ( ) ;
229+
230+ /**
231+ * Called when stdout contains a "listening" message from the axs proxy.
232+ * This signals that the server is ready to accept connections.
233+ */
234+ export function signalServerReady ( serverId : string ) : void {
235+ serverReadySignals . set ( serverId , Date . now ( ) ) ;
236+ }
237+
238+ /**
239+ * Wait for the LSP server to be ready.
240+ *
241+ * This function polls for a ready signal (set when stdout contains "listening")
242+ */
220243async function waitForWebSocket (
221244 url : string ,
222245 options : WaitOptions = { } ,
223246) : Promise < void > {
224- const { attempts = 20 , delay = 200 , probeTimeout = 2000 } = options ;
247+ const {
248+ delay = 100 , // Poll interval
249+ probeTimeout = 5000 , // Max wait time
250+ } = options ;
251+
252+ // Extract server ID from URL (e.g., "ws://127.0.0.1:2090" -> check by port)
253+ const portMatch = url . match ( / : ( \d + ) / ) ;
254+ const port = portMatch ? portMatch [ 1 ] : null ;
255+
256+ // Find the server ID that's starting on this port
257+ let targetServerId : string | null = null ;
258+ const entries = Array . from ( managedServers . entries ( ) ) ;
259+ for ( const [ serverId , entry ] of entries ) {
260+ if (
261+ entry . command . includes ( `--port ${ port } ` ) ||
262+ entry . command . includes ( `:${ port } ` )
263+ ) {
264+ targetServerId = serverId ;
265+ break ;
266+ }
267+ }
225268
226- let lastError : Error | null = null ;
227- for ( let i = 0 ; i < attempts ; i ++ ) {
228- try {
229- await new Promise < void > ( ( resolve , reject ) => {
230- let socket : WebSocket | null = null ;
231- let timer : ReturnType < typeof setTimeout > | null = null ;
232- try {
233- socket = new WebSocket ( url ) ;
234- } catch ( error ) {
235- reject ( error ) ;
236- return ;
237- }
238-
239- const cleanup = ( cb ?: ( ) => void ) : void => {
240- if ( timer ) clearTimeout ( timer ) ;
241- if ( socket ) {
242- socket . onopen = null ;
243- socket . onerror = null ;
244- try {
245- socket . close ( ) ;
246- } catch ( _ ) {
247- // Ignore close errors
248- }
249- }
250- if ( cb ) cb ( ) ;
251- } ;
252-
253- socket . onopen = ( ) => cleanup ( resolve ) ;
254- socket . onerror = ( event : Event ) =>
255- cleanup ( ( ) =>
256- reject (
257- event instanceof Error ? event : new Error ( "websocket error" ) ,
258- ) ,
259- ) ;
260- timer = setTimeout (
261- ( ) => cleanup ( ( ) => reject ( new Error ( "timeout" ) ) ) ,
262- probeTimeout ,
263- ) ;
264- } ) ;
269+ const deadline = Date . now ( ) + probeTimeout ;
270+
271+ while ( Date . now ( ) < deadline ) {
272+ // Check if we got a ready signal
273+ if ( targetServerId && serverReadySignals . has ( targetServerId ) ) {
274+ // Server is ready, clear the signal and return
275+ serverReadySignals . delete ( targetServerId ) ;
265276 return ;
266- } catch ( error ) {
267- lastError = error instanceof Error ? error : new Error ( String ( error ) ) ;
268- await sleep ( delay ) ;
269277 }
278+
279+ await sleep ( delay ) ;
270280 }
271- const reason = lastError ? lastError . message || String ( lastError ) : "unknown" ;
272- throw new Error ( `WebSocket ${ url } did not become ready (${ reason } )` ) ;
281+
282+ // Timeout reached, proceed anyway (transport will retry if needed)
283+ console . debug (
284+ `[LSP] waitForWebSocket timed out for ${ url } , proceeding anyway` ,
285+ ) ;
273286}
274287
275288interface LspError extends Error {
0 commit comments