@@ -457,6 +457,7 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
457457
458458 test ( "provider profile mutation rejection does not poison later queued mutations" , async ( ) => {
459459 const firstError = new Error ( "first profile failed" )
460+ const setValueSpy = vi . spyOn ( provider . contextProxy , "setValue" )
460461
461462 provider [ "providerSettingsManager" ] . activateProfile = vi
462463 . fn ( )
@@ -470,14 +471,27 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
470471
471472 await expect ( provider . activateProviderProfile ( { name : "first-profile" } ) ) . rejects . toThrow ( firstError )
472473 await expect ( provider . activateProviderProfile ( { name : "second-profile" } ) ) . resolves . toBeUndefined ( )
474+ expect ( setValueSpy ) . toHaveBeenCalledWith ( "currentApiConfigName" , "second-profile" )
473475 } )
474476
475- test ( "provider profile mutation timeout releases later queued mutations " , async ( ) => {
477+ test ( "timed-out provider profile mutations retain the queue boundary until they settle " , async ( ) => {
476478 vi . useFakeTimers ( )
477479 const logSpy = vi . spyOn ( provider , "log" )
480+ let resolveFirst ! : ( ) => void
481+ const firstActivation = new Promise < void > ( ( resolve ) => {
482+ resolveFirst = resolve
483+ } )
478484 provider [ "providerSettingsManager" ] . activateProfile = vi
479485 . fn ( )
480- . mockImplementationOnce ( ( ) => new Promise < never > ( ( ) => { } ) )
486+ . mockImplementationOnce ( async ( ) => {
487+ await firstActivation
488+ return {
489+ name : "first-profile" ,
490+ id : "first-id" ,
491+ apiProvider : "openrouter" ,
492+ openRouterModelId : "openai/gpt-4" ,
493+ }
494+ } )
481495 . mockResolvedValueOnce ( {
482496 name : "second-profile" ,
483497 id : "second-id" ,
@@ -488,17 +502,24 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
488502 try {
489503 const first = provider . activateProviderProfile ( { name : "first-profile" } )
490504 const firstResult = expect ( first ) . rejects . toThrow ( "Provider profile mutation timed out" )
491- await vi . advanceTimersByTimeAsync ( 30_000 )
505+ await vi . advanceTimersByTimeAsync ( ClineProvider . PENDING_OPERATION_TIMEOUT_MS )
492506 await firstResult
493507
494- await expect ( provider . activateProviderProfile ( { name : "second-profile" } ) ) . resolves . toBeUndefined ( )
495- expect ( logSpy ) . toHaveBeenCalledWith ( "Provider profile mutation timed out; releasing the mutation queue" )
508+ const second = provider . activateProviderProfile ( { name : "second-profile" } )
509+ expect ( provider [ "providerSettingsManager" ] . activateProfile ) . toHaveBeenCalledTimes ( 1 )
510+
511+ resolveFirst ( )
512+ await expect ( second ) . resolves . toBeUndefined ( )
513+ expect ( provider [ "providerSettingsManager" ] . activateProfile ) . toHaveBeenCalledTimes ( 2 )
514+ expect ( logSpy ) . toHaveBeenCalledWith (
515+ "Provider profile mutation timed out; waiting for the in-flight mutation to settle" ,
516+ )
496517 } finally {
497518 vi . useRealTimers ( )
498519 }
499520 } )
500521
501- test ( "mode switch resolves its default task when its queued mutation starts " , async ( ) => {
522+ test ( "mode switch preserves its default task when queued behind a profile mutation " , async ( ) => {
502523 let releaseProfileActivation ! : ( ) => void
503524 const profileActivation = new Promise < void > ( ( resolve ) => {
504525 releaseProfileActivation = resolve
@@ -515,6 +536,10 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
515536
516537 const firstTask = new Task ( defaultTaskOptions )
517538 const secondTask = new Task ( defaultTaskOptions )
539+ Object . defineProperty ( firstTask , "taskId" , { value : "first-task-id" } )
540+ Object . defineProperty ( secondTask , "taskId" , { value : "second-task-id" } )
541+ firstTask [ "_taskMode" ] = "code" as Mode
542+ secondTask [ "_taskMode" ] = "code" as Mode
518543 await provider . addClineToStack ( firstTask )
519544
520545 const profileSwitch = provider . activateProviderProfile ( { name : "first-profile" } )
@@ -525,8 +550,8 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
525550 await profileSwitch
526551 await modeSwitch
527552
528- expect ( firstTask [ "_taskMode" ] ) . not . toBe ( "ask" )
529- expect ( secondTask [ "_taskMode" ] ) . toBe ( "ask " )
553+ expect ( firstTask [ "_taskMode" ] ) . toBe ( "ask" )
554+ expect ( secondTask [ "_taskMode" ] ) . toBe ( "code " )
530555 } )
531556
532557 test ( "fan-out preparation leaves the focused task untouched" , async ( ) => {
@@ -570,6 +595,8 @@ describe("ClineProvider - API Handler Rebuild Guard", () => {
570595 expect ( postStateSpy ) . not . toHaveBeenCalled ( )
571596 expect ( setValueSpy ) . not . toHaveBeenCalledWith ( "currentApiConfigName" , "ask-profile" )
572597 expect ( setProviderSettingsSpy ) . not . toHaveBeenCalled ( )
598+ expect ( emitSpy ) . toHaveBeenCalledWith ( RooCodeEventName . ModeChanged , "ask" )
599+ expect ( provider [ "providerSettingsManager" ] . activateProfile ) . toHaveBeenCalledWith ( { name : "ask-profile" } )
573600 } )
574601
575602 test ( "calls updateApiConfiguration when provider/model unchanged but settings differ (explicit profile switch)" , async ( ) => {
0 commit comments