@@ -82,6 +82,7 @@ const main = async () => {
8282 print ( {
8383 usage : [
8484 'parchi-relay rpc <method> [--params=\'{...}\'] [--agentId=...]' ,
85+ 'parchi-relay doctor [--agentId=...] [--skipTool=true]' ,
8586 'parchi-relay agents' ,
8687 'parchi-relay default-agent get|set <agentId>' ,
8788 'parchi-relay tools [--agentId=...]' ,
@@ -102,6 +103,93 @@ const main = async () => {
102103 return ;
103104 }
104105
106+ if ( cmd === 'doctor' ) {
107+ const agentId = flags . agentId ;
108+ const skipTool = flags . skipTool === 'true' ;
109+
110+ const report : Record < string , any > = {
111+ ok : true ,
112+ target : { host, port } ,
113+ checks : { } ,
114+ } ;
115+
116+ const fail = ( name : string , err : unknown ) => {
117+ report . ok = false ;
118+ report . checks [ name ] = {
119+ ok : false ,
120+ error : err instanceof Error ? err . message : String ( err ?? 'error' ) ,
121+ } ;
122+ } ;
123+
124+ try {
125+ const ping = await fetchRpc ( { host, port, token, method : 'relay.ping' } ) ;
126+ report . checks . ping = { ok : true , result : ping } ;
127+ } catch ( err ) {
128+ fail ( 'ping' , err ) ;
129+ print ( report ) ;
130+ process . exit ( 2 ) ;
131+ }
132+
133+ let agents : any [ ] = [ ] ;
134+ try {
135+ agents = ( await fetchRpc ( { host, port, token, method : 'agents.list' } ) ) as any [ ] ;
136+ report . checks . agents = { ok : true , count : Array . isArray ( agents ) ? agents . length : 0 , agents } ;
137+ } catch ( err ) {
138+ fail ( 'agents' , err ) ;
139+ }
140+
141+ let resolvedAgentId : string | null = agentId || null ;
142+ if ( ! resolvedAgentId ) {
143+ try {
144+ const def = ( await fetchRpc ( { host, port, token, method : 'agents.default.get' } ) ) as any ;
145+ resolvedAgentId = typeof def ?. agentId === 'string' ? def . agentId : null ;
146+ report . checks . defaultAgent = { ok : true , agentId : resolvedAgentId } ;
147+ } catch ( err ) {
148+ fail ( 'defaultAgent' , err ) ;
149+ }
150+ } else {
151+ report . checks . defaultAgent = { ok : true , agentId : resolvedAgentId , source : 'flag' } ;
152+ }
153+
154+ const connected = Array . isArray ( agents ) ? agents . some ( ( a ) => a ?. agentId === resolvedAgentId ) : false ;
155+ if ( resolvedAgentId && ! connected ) {
156+ report . ok = false ;
157+ report . checks . agentConnected = {
158+ ok : false ,
159+ agentId : resolvedAgentId ,
160+ hint : 'AgentId not in agents.list. Ensure the extension is loaded from dist/ and Relay is enabled/applied.' ,
161+ } ;
162+ } else {
163+ report . checks . agentConnected = { ok : true , agentId : resolvedAgentId } ;
164+ }
165+
166+ try {
167+ const params = resolvedAgentId ? { agentId : resolvedAgentId } : undefined ;
168+ const tools = await fetchRpc ( { host, port, token, method : 'tools.list' , params } ) ;
169+ report . checks . tools = { ok : true , toolCount : Array . isArray ( tools ) ? tools . length : null , tools } ;
170+ } catch ( err ) {
171+ fail ( 'tools' , err ) ;
172+ }
173+
174+ if ( ! skipTool ) {
175+ try {
176+ const params = resolvedAgentId
177+ ? { agentId : resolvedAgentId , tool : 'getTabs' , args : { } }
178+ : { tool : 'getTabs' , args : { } } ;
179+ const result = await fetchRpc ( { host, port, token, method : 'tool.call' , params } ) ;
180+ report . checks . forwarding = { ok : true , tool : 'getTabs' , result } ;
181+ } catch ( err ) {
182+ fail ( 'forwarding' , err ) ;
183+ }
184+ } else {
185+ report . checks . forwarding = { ok : true , skipped : true } ;
186+ }
187+
188+ print ( report ) ;
189+ if ( ! report . ok ) process . exit ( 2 ) ;
190+ return ;
191+ }
192+
105193 if ( cmd === 'agents' ) {
106194 const result = await fetchRpc ( { host, port, token, method : 'agents.list' } ) ;
107195 print ( result ) ;
@@ -176,4 +264,3 @@ const main = async () => {
176264} ;
177265
178266await main ( ) ;
179-
0 commit comments