@@ -37,6 +37,10 @@ function supportsSystemRun(commands?: string[]): boolean {
3737 return Array . isArray ( commands ) && commands . includes ( "system.run" ) ;
3838}
3939
40+ function supportsSystemWhich ( commands ?: string [ ] ) : boolean {
41+ return Array . isArray ( commands ) && commands . includes ( "system.which" ) ;
42+ }
43+
4044function upsertNode ( record : {
4145 nodeId : string ;
4246 displayName ?: string ;
@@ -136,6 +140,27 @@ function buildBinProbeScript(bins: string[]): string {
136140 return `for b in ${ escaped } ; do if command -v "$b" >/dev/null 2>&1; then echo "$b"; fi; done` ;
137141}
138142
143+ function parseBinProbePayload ( payloadJSON : string | null | undefined ) : string [ ] {
144+ if ( ! payloadJSON ) return [ ] ;
145+ try {
146+ const parsed = JSON . parse ( payloadJSON ) as { stdout ?: unknown ; bins ?: unknown } ;
147+ if ( Array . isArray ( parsed . bins ) ) {
148+ return parsed . bins
149+ . map ( ( bin ) => String ( bin ) . trim ( ) )
150+ . filter ( Boolean ) ;
151+ }
152+ if ( typeof parsed . stdout === "string" ) {
153+ return parsed . stdout
154+ . split ( / \r ? \n / )
155+ . map ( ( line ) => line . trim ( ) )
156+ . filter ( Boolean ) ;
157+ }
158+ } catch {
159+ return [ ] ;
160+ }
161+ return [ ] ;
162+ }
163+
139164export async function refreshRemoteNodeBins ( params : {
140165 nodeId : string ;
141166 platform ?: string ;
@@ -146,7 +171,9 @@ export async function refreshRemoteNodeBins(params: {
146171} ) {
147172 if ( ! remoteBridge ) return ;
148173 if ( ! isMacPlatform ( params . platform , params . deviceFamily ) ) return ;
149- if ( ! supportsSystemRun ( params . commands ) ) return ;
174+ const canWhich = supportsSystemWhich ( params . commands ) ;
175+ const canRun = supportsSystemRun ( params . commands ) ;
176+ if ( ! canWhich && ! canRun ) return ;
150177
151178 const workspaceDirs = listWorkspaceDirs ( params . cfg ) ;
152179 const requiredBins = new Set < string > ( ) ;
@@ -158,31 +185,30 @@ export async function refreshRemoteNodeBins(params: {
158185 }
159186 if ( requiredBins . size === 0 ) return ;
160187
161- const script = buildBinProbeScript ( [ ...requiredBins ] ) ;
162- const payload = {
163- command : [ "/bin/sh" , "-lc" , script ] ,
164- } ;
165188 try {
166- const res = await remoteBridge . invoke ( {
167- nodeId : params . nodeId ,
168- command : "system.run" ,
169- paramsJSON : JSON . stringify ( payload ) ,
170- timeoutMs : params . timeoutMs ?? 15_000 ,
171- } ) ;
189+ const binsList = [ ...requiredBins ] ;
190+ const res = await remoteBridge . invoke (
191+ canWhich
192+ ? {
193+ nodeId : params . nodeId ,
194+ command : "system.which" ,
195+ paramsJSON : JSON . stringify ( { bins : binsList } ) ,
196+ timeoutMs : params . timeoutMs ?? 15_000 ,
197+ }
198+ : {
199+ nodeId : params . nodeId ,
200+ command : "system.run" ,
201+ paramsJSON : JSON . stringify ( {
202+ command : [ "/bin/sh" , "-lc" , buildBinProbeScript ( binsList ) ] ,
203+ } ) ,
204+ timeoutMs : params . timeoutMs ?? 15_000 ,
205+ } ,
206+ ) ;
172207 if ( ! res . ok ) {
173208 log . warn ( `remote bin probe failed (${ params . nodeId } ): ${ res . error ?. message ?? "unknown" } ` ) ;
174209 return ;
175210 }
176- const raw = typeof res . payloadJSON === "string" ? res . payloadJSON : "" ;
177- const parsed =
178- raw && raw . trim ( ) . length > 0
179- ? ( JSON . parse ( raw ) as { stdout ?: string } )
180- : ( { stdout : "" } as { stdout ?: string } ) ;
181- const stdout = typeof parsed . stdout === "string" ? parsed . stdout : "" ;
182- const bins = stdout
183- . split ( / \r ? \n / )
184- . map ( ( line ) => line . trim ( ) )
185- . filter ( Boolean ) ;
211+ const bins = parseBinProbePayload ( res . payloadJSON ) ;
186212 recordRemoteNodeBins ( params . nodeId , bins ) ;
187213 await updatePairedNodeMetadata ( params . nodeId , { bins } ) ;
188214 bumpSkillsSnapshotVersion ( { reason : "remote-node" } ) ;
0 commit comments