@@ -546,6 +546,98 @@ describe("devices cli approve", () => {
546546 expect ( errorOutput ) . not . toContain ( "secret-token" ) ;
547547 expect ( runtime . exit ) . toHaveBeenCalledWith ( 1 ) ;
548548 } ) ;
549+
550+ it ( "does not suggest node approval for a wrong-layer device IP when only display names match" , async ( ) => {
551+ callGateway
552+ . mockResolvedValueOnce ( {
553+ pending : [ ] ,
554+ paired : [
555+ pairedDevice ( {
556+ deviceId : "android-node" ,
557+ displayName : "Shared Phone" ,
558+ remoteIp : "192.168.0.202" ,
559+ roles : [ "node" ] ,
560+ } ) ,
561+ ] ,
562+ } )
563+ . mockRejectedValueOnce ( new Error ( "device pairing approval denied" ) )
564+ . mockRejectedValueOnce ( { message : "unknown requestId" , gatewayCode : "INVALID_REQUEST" } )
565+ . mockResolvedValueOnce ( {
566+ nodes : [
567+ {
568+ nodeId : "unrelated-node" ,
569+ displayName : "Shared Phone" ,
570+ remoteIp : "10.0.0.50" ,
571+ approvalState : "pending-reapproval" ,
572+ pendingRequestId : "node-req-unrelated" ,
573+ } ,
574+ ] ,
575+ } )
576+ . mockResolvedValueOnce ( {
577+ pending : [ ] ,
578+ paired : [
579+ pairedDevice ( {
580+ deviceId : "android-node" ,
581+ displayName : "Shared Phone" ,
582+ remoteIp : "192.168.0.202" ,
583+ roles : [ "node" ] ,
584+ } ) ,
585+ ] ,
586+ } ) ;
587+
588+ await runDevicesApprove ( [ "192.168.0.202" ] ) ;
589+
590+ expectGatewayCall ( 3 , { method : "node.list" } ) ;
591+ expectGatewayCall ( 4 , { method : "device.pair.list" } ) ;
592+ const errorOutput = readRuntimeErrorOutput ( ) ;
593+ expect ( errorOutput ) . toContain ( "unknown requestId" ) ;
594+ expect ( errorOutput ) . not . toContain ( "node-req-unrelated" ) ;
595+ expect ( errorOutput ) . not . toContain ( "openclaw nodes approve" ) ;
596+ } ) ;
597+
598+ it ( "does not suggest node approval when the query only matches a paired device display name" , async ( ) => {
599+ callGateway
600+ . mockResolvedValueOnce ( {
601+ pending : [ ] ,
602+ paired : [
603+ pairedDevice ( {
604+ deviceId : "paired-node" ,
605+ displayName : "Shared Phone" ,
606+ roles : [ "node" ] ,
607+ } ) ,
608+ ] ,
609+ } )
610+ . mockRejectedValueOnce ( { message : "unknown requestId" , gatewayCode : "INVALID_REQUEST" } )
611+ . mockResolvedValueOnce ( {
612+ nodes : [
613+ {
614+ nodeId : "paired-node" ,
615+ displayName : "Shared Phone" ,
616+ approvalState : "pending-approval" ,
617+ pendingRequestId : "node-req-display-name" ,
618+ } ,
619+ ] ,
620+ } )
621+ . mockResolvedValueOnce ( {
622+ pending : [ ] ,
623+ paired : [
624+ pairedDevice ( {
625+ deviceId : "paired-node" ,
626+ displayName : "Shared Phone" ,
627+ roles : [ "node" ] ,
628+ } ) ,
629+ ] ,
630+ } ) ;
631+
632+ await runDevicesApprove ( [ "Shared Phone" ] ) ;
633+
634+ expectGatewayCall ( 2 , { method : "node.list" } ) ;
635+ expectGatewayCall ( 3 , { method : "device.pair.list" } ) ;
636+ const errorOutput = readRuntimeErrorOutput ( ) ;
637+ expect ( errorOutput ) . toContain ( "unknown requestId" ) ;
638+ expect ( errorOutput ) . not . toContain ( "node-req-display-name" ) ;
639+ expect ( errorOutput ) . not . toContain ( "openclaw nodes approve" ) ;
640+ } ) ;
549641} ) ;
550642
551643describe ( "devices cli remove" , ( ) => {
@@ -1443,6 +1535,40 @@ describe("devices cli list", () => {
14431535 expect ( output ) . not . toContain ( "secret-token" ) ;
14441536 } ) ;
14451537
1538+ it ( "does not show node approval commands for paired node devices when only display names match" , async ( ) => {
1539+ callGateway
1540+ . mockResolvedValueOnce ( {
1541+ pending : [ ] ,
1542+ paired : [
1543+ pairedDevice ( {
1544+ deviceId : "android-node" ,
1545+ displayName : "Shared Phone" ,
1546+ remoteIp : "192.168.0.202" ,
1547+ role : "node" ,
1548+ roles : [ ] ,
1549+ } ) ,
1550+ ] ,
1551+ } )
1552+ . mockResolvedValueOnce ( {
1553+ nodes : [
1554+ {
1555+ nodeId : "unrelated-node" ,
1556+ displayName : "Shared Phone" ,
1557+ remoteIp : "10.0.0.50" ,
1558+ approvalState : "pending-reapproval" ,
1559+ pendingRequestId : "node-req-unrelated" ,
1560+ } ,
1561+ ] ,
1562+ } ) ;
1563+
1564+ await runDevicesCommand ( [ "list" ] ) ;
1565+
1566+ expectGatewayCall ( 1 , { method : "node.list" } ) ;
1567+ const output = readRuntimeOutput ( ) ;
1568+ expect ( output ) . not . toContain ( "node-req-unrelated" ) ;
1569+ expect ( output ) . not . toContain ( "openclaw nodes approve" ) ;
1570+ } ) ;
1571+
14461572 it ( "does not show upgrade context for key-mismatched pending requests" , async ( ) => {
14471573 mockGatewayPairingList ( { publicKey : "new-key" } , { publicKey : "old-key" } ) ;
14481574
0 commit comments