@@ -290,6 +290,11 @@ vi.mock("../../config/ContextProxy", () => {
290290 )
291291 } )
292292 setProviderSettings = vi . fn ( ) . mockImplementation ( ( settings : Record < string , any > ) => this . setValues ( settings ) )
293+ resetAllState = vi . fn ( ) . mockImplementation ( ( ) => {
294+ return Promise . all (
295+ Object . keys ( this . context ?. globalState ?? { } ) . map ( ( key ) => this . setValue ( key , undefined ) ) ,
296+ ) . then ( ( ) => undefined )
297+ } )
293298 }
294299 return { ContextProxy : MockContextProxy }
295300} )
@@ -475,6 +480,7 @@ vi.mock("../../config/ProviderSettingsManager", () => ({
475480 saveConfig : vi . fn ( ) . mockResolvedValue ( "test-id" ) ,
476481 listConfig : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
477482 getProfile : vi . fn ( ) . mockResolvedValue ( { } ) ,
483+ resetAllConfigs : vi . fn ( ) . mockResolvedValue ( undefined ) ,
478484 activateProfile : vi . fn ( ) . mockImplementation ( async ( args : { name ?: string ; id ?: string } ) => ( {
479485 name : args . name ?? "default" ,
480486 id : args . id ?? "test-id" ,
@@ -492,6 +498,7 @@ vi.mock("../../config/CustomModesManager", () => ({
492498 return {
493499 updateCustomMode : vi . fn ( ) . mockResolvedValue ( undefined ) ,
494500 getCustomModes : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
501+ resetCustomModes : vi . fn ( ) . mockResolvedValue ( undefined ) ,
495502 dispose : vi . fn ( ) ,
496503 }
497504 } ) ,
@@ -1071,4 +1078,107 @@ describe("ClineProvider - Parallel Mode Support", () => {
10711078 await provider . dispose ( )
10721079 } )
10731080 } )
1081+
1082+ describe ( "broadcastResetToAllInstances" , ( ) => {
1083+ it ( "should clear viewLocalState in other instances and post updated state" , async ( ) => {
1084+ const provider1 = new ClineProvider (
1085+ mockContext ,
1086+ mockOutputChannel ,
1087+ "sidebar" ,
1088+ new ContextProxy ( mockContext ) ,
1089+ )
1090+ const provider2 = new ClineProvider ( mockContext , mockOutputChannel , "editor" , new ContextProxy ( mockContext ) )
1091+ const postStateToWebview2 = vi . spyOn ( provider2 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1092+
1093+ await ( provider1 as any ) . saveViewState ( "mode" , "architect" )
1094+ await ( provider2 as any ) . saveViewState ( "mode" , "debugger" )
1095+
1096+ await provider1 . broadcastResetToAllInstances ( )
1097+
1098+ expect ( ( provider1 as any ) . viewLocalState . mode ) . toBe ( "architect" )
1099+ expect ( ( provider2 as any ) . viewLocalState ) . toEqual ( { } )
1100+ expect ( postStateToWebview2 ) . toHaveBeenCalledTimes ( 1 )
1101+
1102+ await provider1 . dispose ( )
1103+ await provider2 . dispose ( )
1104+ } )
1105+
1106+ it ( "should be a no-op for a single live instance" , async ( ) => {
1107+ const provider = new ClineProvider ( mockContext , mockOutputChannel , "sidebar" , new ContextProxy ( mockContext ) )
1108+ const postStateToWebview = vi . spyOn ( provider , "postStateToWebview" ) . mockResolvedValue ( undefined )
1109+
1110+ await ( provider as any ) . saveViewState ( "mode" , "architect" )
1111+
1112+ await provider . broadcastResetToAllInstances ( )
1113+
1114+ expect ( ( provider as any ) . viewLocalState . mode ) . toBe ( "architect" )
1115+ expect ( postStateToWebview ) . not . toHaveBeenCalled ( )
1116+
1117+ await provider . dispose ( )
1118+ } )
1119+
1120+ it ( "should broadcast to multiple other live instances" , async ( ) => {
1121+ const provider1 = new ClineProvider (
1122+ mockContext ,
1123+ mockOutputChannel ,
1124+ "sidebar" ,
1125+ new ContextProxy ( mockContext ) ,
1126+ )
1127+ const provider2 = new ClineProvider ( mockContext , mockOutputChannel , "editor" , new ContextProxy ( mockContext ) )
1128+ const provider3 = new ClineProvider ( mockContext , mockOutputChannel , "editor" , new ContextProxy ( mockContext ) )
1129+ const postStateToWebview1 = vi . spyOn ( provider1 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1130+ const postStateToWebview2 = vi . spyOn ( provider2 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1131+ const postStateToWebview3 = vi . spyOn ( provider3 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1132+
1133+ await ( provider1 as any ) . saveViewState ( "mode" , "code" )
1134+ await ( provider2 as any ) . saveViewState ( "mode" , "architect" )
1135+ await ( provider3 as any ) . saveViewState ( "currentApiConfigName" , "profile-c" )
1136+
1137+ await provider1 . broadcastResetToAllInstances ( )
1138+
1139+ expect ( ( provider1 as any ) . viewLocalState . mode ) . toBe ( "code" )
1140+ expect ( ( provider2 as any ) . viewLocalState ) . toEqual ( { } )
1141+ expect ( ( provider3 as any ) . viewLocalState ) . toEqual ( { } )
1142+ expect ( postStateToWebview1 ) . not . toHaveBeenCalled ( )
1143+ expect ( postStateToWebview2 ) . toHaveBeenCalledTimes ( 1 )
1144+ expect ( postStateToWebview3 ) . toHaveBeenCalledTimes ( 1 )
1145+
1146+ await provider1 . dispose ( )
1147+ await provider2 . dispose ( )
1148+ await provider3 . dispose ( )
1149+ } )
1150+ } )
1151+
1152+ describe ( "resetState cross-tab invalidation" , ( ) => {
1153+ it ( "should clear caller and other live instances during resetState flow" , async ( ) => {
1154+ const provider1 = new ClineProvider (
1155+ mockContext ,
1156+ mockOutputChannel ,
1157+ "sidebar" ,
1158+ new ContextProxy ( mockContext ) ,
1159+ )
1160+ const provider2 = new ClineProvider ( mockContext , mockOutputChannel , "editor" , new ContextProxy ( mockContext ) )
1161+ const postStateToWebview1 = vi . spyOn ( provider1 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1162+ const postStateToWebview2 = vi . spyOn ( provider2 , "postStateToWebview" ) . mockResolvedValue ( undefined )
1163+ vi . spyOn ( provider1 , "postMessageToWebview" ) . mockResolvedValue ( true )
1164+ vi . spyOn ( provider1 as any , "removeClineFromStack" ) . mockResolvedValue ( undefined )
1165+ ; ( vscode . window . showInformationMessage as any ) . mockImplementation ( async ( ...args : any [ ] ) => args [ 2 ] )
1166+
1167+ await ( provider1 as any ) . saveViewState ( "mode" , "architect" )
1168+ await ( provider2 as any ) . saveViewState ( "currentApiConfigName" , "profile-b" )
1169+
1170+ await provider1 . resetState ( )
1171+
1172+ expect ( ( provider1 as any ) . viewLocalState ) . toEqual ( { } )
1173+ expect ( ( provider2 as any ) . viewLocalState ) . toEqual ( { } )
1174+ expect ( ( provider1 . contextProxy as any ) . resetAllState ) . toHaveBeenCalledTimes ( 1 )
1175+ expect ( ( provider1 . providerSettingsManager as any ) . resetAllConfigs ) . toHaveBeenCalledTimes ( 1 )
1176+ expect ( ( provider1 . customModesManager as any ) . resetCustomModes ) . toHaveBeenCalledTimes ( 1 )
1177+ expect ( postStateToWebview1 ) . toHaveBeenCalledTimes ( 1 )
1178+ expect ( postStateToWebview2 ) . toHaveBeenCalledTimes ( 1 )
1179+
1180+ await provider1 . dispose ( )
1181+ await provider2 . dispose ( )
1182+ } )
1183+ } )
10741184} )
0 commit comments