@@ -7,6 +7,8 @@ import type {
77 InstallStatus ,
88 LauncherConfig ,
99 LspServerDefinition ,
10+ LspServerStats ,
11+ LspServerStatsFormatted ,
1012 ManagedServerEntry ,
1113 PortInfo ,
1214 WaitOptions ,
@@ -476,9 +478,9 @@ async function startInteractiveServer(
476478 const callback : ExecutorCallback = ( type , data ) => {
477479 if ( type === "stderr" ) {
478480 if ( / p r o o t w a r n i n g / i. test ( data ) ) return ;
479- console . warn ( `[${ serverId } ] ${ data } ` ) ;
481+ console . warn ( `[LSP: ${ serverId } ] ${ data } ` ) ;
480482 } else if ( type === "stdout" && data && data . trim ( ) ) {
481- console . info ( `[${ serverId } ] ${ data } ` ) ;
483+ console . info ( `[LSP: ${ serverId } ] ${ data } ` ) ;
482484 // Detect when the axs proxy signals it's listening
483485 if ( / l i s t e n i n g o n / i. test ( data ) ) {
484486 signalServerReady ( serverId ) ;
@@ -634,6 +636,11 @@ export async function ensureServerRunning(
634636 console . info (
635637 `[LSP:${ server . id } ] Auto-discovered port ${ discoveredPort } ` ,
636638 ) ;
639+ // Update managed server entry with the port
640+ const entry = managedServers . get ( key ) ;
641+ if ( entry ) {
642+ entry . port = discoveredPort ;
643+ }
637644 }
638645 } else if (
639646 server . transport ?. url &&
@@ -705,3 +712,96 @@ export function resetManagedServers(): void {
705712 . stopService ( )
706713 . catch ( ( ) => { } ) ;
707714}
715+
716+ /**
717+ * Get managed server info by server ID
718+ */
719+ export function getManagedServerInfo (
720+ serverId : string ,
721+ ) : ManagedServerEntry | null {
722+ return managedServers . get ( serverId ) ?? null ;
723+ }
724+
725+ /**
726+ * Get all managed servers
727+ */
728+ export function getAllManagedServers ( ) : Map < string , ManagedServerEntry > {
729+ return new Map ( managedServers ) ;
730+ }
731+
732+ function formatMemory ( bytes : number ) : string {
733+ if ( ! bytes || bytes <= 0 ) return "—" ;
734+ const mb = bytes / ( 1024 * 1024 ) ;
735+ if ( mb >= 1 ) return `${ mb . toFixed ( 1 ) } MB` ;
736+ const kb = bytes / 1024 ;
737+ return `${ kb . toFixed ( 0 ) } KB` ;
738+ }
739+
740+ function formatUptime ( seconds : number ) : string {
741+ if ( ! seconds || seconds <= 0 ) return "—" ;
742+ if ( seconds < 60 ) return `${ seconds } s` ;
743+ const mins = Math . floor ( seconds / 60 ) ;
744+ const secs = seconds % 60 ;
745+ if ( mins < 60 ) return `${ mins } m ${ secs } s` ;
746+ const hours = Math . floor ( mins / 60 ) ;
747+ const remainingMins = mins % 60 ;
748+ return `${ hours } h ${ remainingMins } m` ;
749+ }
750+
751+ /**
752+ * Fetch server stats from the axs proxy /status endpoint
753+ * @param serverId - The server ID to fetch stats for
754+ * @param timeout - Timeout in milliseconds (default: 2000)
755+ */
756+ export async function getServerStats (
757+ serverId : string ,
758+ timeout = 2000 ,
759+ ) : Promise < LspServerStatsFormatted | null > {
760+ const entry = managedServers . get ( serverId ) ;
761+ if ( ! entry ?. port ) {
762+ return null ;
763+ }
764+
765+ try {
766+ const controller = new AbortController ( ) ;
767+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , timeout ) ;
768+
769+ const response = await fetch ( `http://127.0.0.1:${ entry . port } /status` , {
770+ signal : controller . signal ,
771+ } ) ;
772+
773+ clearTimeout ( timeoutId ) ;
774+
775+ if ( ! response . ok ) {
776+ return null ;
777+ }
778+
779+ const data = ( await response . json ( ) ) as LspServerStats ;
780+
781+ // Aggregate stats from all processes
782+ let totalMemory = 0 ;
783+ let maxUptime = 0 ;
784+ let firstPid : number | null = null ;
785+
786+ for ( const proc of data . processes || [ ] ) {
787+ totalMemory += proc . memory_bytes || 0 ;
788+ if ( proc . uptime_secs > maxUptime ) {
789+ maxUptime = proc . uptime_secs ;
790+ }
791+ if ( firstPid === null && proc . pid ) {
792+ firstPid = proc . pid ;
793+ }
794+ }
795+
796+ return {
797+ memoryBytes : totalMemory ,
798+ memoryFormatted : formatMemory ( totalMemory ) ,
799+ uptimeSeconds : maxUptime ,
800+ uptimeFormatted : formatUptime ( maxUptime ) ,
801+ pid : firstPid ,
802+ processCount : data . processes ?. length ?? 0 ,
803+ } ;
804+ } catch {
805+ return null ;
806+ }
807+ }
0 commit comments