@@ -22,7 +22,7 @@ import { hasKey } from '../../../../base/common/types.js';
2222import { NullLogService } from '../../../log/common/log.js' ;
2323import { FileService } from '../../../files/common/fileService.js' ;
2424import { InMemoryFileSystemProvider } from '../../../files/common/inMemoryFilesystemProvider.js' ;
25- import { AgentSession , GITHUB_COPILOT_PROTECTED_RESOURCE , IRestoredSubagentSession , SubagentChatSignal , type IAgent , type IAgentChatDataChange , type IAgentChats , type IAgentCreateChatForkSource , type IAgentCreateChatOptions , type IAgentCreateChatResult , type IAgentCreateSessionResult , type IAgentLegacyChat , type IAgentSessionMetadata , type IAgentSpawnChatEvent } from '../../common/agentService.js' ;
25+ import { AgentSession , GITHUB_COPILOT_PROTECTED_RESOURCE , IRestoredSubagentSession , SubagentChatSignal , type IAgent , type IAgentChatDataChange , type IAgentChats , type IAgentCreateChatForkSource , type IAgentCreateChatOptions , type IAgentCreateChatResult , type IAgentCreateSessionConfig , type IAgentCreateSessionResult , type IAgentLegacyChat , type IAgentSessionMetadata , type IAgentSpawnChatEvent } from '../../common/agentService.js' ;
2626import { ISessionDatabase , ISessionDataService } from '../../common/sessionDataService.js' ;
2727import { SessionConfigKey } from '../../common/sessionConfigKeys.js' ;
2828import { SessionDatabase } from '../../node/sessionDatabase.js' ;
@@ -427,6 +427,84 @@ suite('AgentService (node dispatcher)', () => {
427427 } ) ;
428428 } ) ;
429429
430+ test ( 'reconciles pending worktree isolation when creating session config changes' , async ( ) => {
431+ const gitService = createNoopGitService ( ) ;
432+ const sessionDataService = createSessionDataService ( new TestSessionDatabase ( ) ) ;
433+ const localService = disposables . add ( new AgentService ( new NullLogService ( ) , fileService , sessionDataService , { _serviceBrand : undefined } as IProductService , gitService ) ) ;
434+ const isolation = disposables . add ( new WorktreeIsolation (
435+ { generateBranchName : async ( ) => 'agents/test' } ,
436+ gitService ,
437+ new TestCopilotApiService ( ) ,
438+ sessionDataService ,
439+ new NullLogService ( ) ,
440+ ) ) ;
441+ localService . setWorktreeIsolation ( isolation ) ;
442+
443+ class ProvisionalAgent extends MockAgent {
444+ override async createSession ( config ?: IAgentCreateSessionConfig ) : Promise < IAgentCreateSessionResult > {
445+ return { ...await super . createSession ( config ) , provisional : true } ;
446+ }
447+ }
448+
449+ const provisionalAgent = new ProvisionalAgent ( 'codex' ) ;
450+ const readyAgent = new MockAgent ( 'copilot' ) ;
451+ disposables . add ( toDisposable ( ( ) => provisionalAgent . dispose ( ) ) ) ;
452+ disposables . add ( toDisposable ( ( ) => readyAgent . dispose ( ) ) ) ;
453+ localService . registerProvider ( provisionalAgent ) ;
454+ localService . registerProvider ( readyAgent ) ;
455+
456+ const creatingSession = await localService . createSession ( {
457+ provider : 'codex' ,
458+ workingDirectory : URI . file ( '/workspace/repo' ) ,
459+ config : { [ SessionConfigKey . Isolation ] : 'folder' } ,
460+ } ) ;
461+ const readySession = await localService . createSession ( {
462+ provider : 'copilot' ,
463+ workingDirectory : URI . file ( '/workspace/repo' ) ,
464+ config : { [ SessionConfigKey . Isolation ] : 'folder' } ,
465+ } ) ;
466+ const creatingInitially = localService . configurationService . isWorkingDirectoryPending ( creatingSession . toString ( ) ) ;
467+ const readyInitially = localService . configurationService . isWorkingDirectoryPending ( readySession . toString ( ) ) ;
468+ const creatingLifecycle = localService . stateManager . getSessionState ( creatingSession . toString ( ) ) ?. lifecycle ;
469+ const readyLifecycle = localService . stateManager . getSessionState ( readySession . toString ( ) ) ?. lifecycle ;
470+
471+ localService . dispatchAction ( creatingSession . toString ( ) , {
472+ type : ActionType . SessionConfigChanged ,
473+ config : { [ SessionConfigKey . Isolation ] : 'worktree' } ,
474+ } , 'test-client' , 1 ) ;
475+ const creatingAfterWorktree = localService . configurationService . isWorkingDirectoryPending ( creatingSession . toString ( ) ) ;
476+
477+ localService . dispatchAction ( creatingSession . toString ( ) , {
478+ type : ActionType . SessionConfigChanged ,
479+ config : { [ SessionConfigKey . Isolation ] : 'folder' } ,
480+ } , 'test-client' , 2 ) ;
481+ const creatingAfterFolder = localService . configurationService . isWorkingDirectoryPending ( creatingSession . toString ( ) ) ;
482+
483+ localService . dispatchAction ( readySession . toString ( ) , {
484+ type : ActionType . SessionConfigChanged ,
485+ config : { [ SessionConfigKey . Isolation ] : 'worktree' } ,
486+ } , 'test-client' , 3 ) ;
487+ const readyAfterWorktree = localService . configurationService . isWorkingDirectoryPending ( readySession . toString ( ) ) ;
488+
489+ assert . deepStrictEqual ( {
490+ creatingInitially,
491+ readyInitially,
492+ creatingLifecycle,
493+ readyLifecycle,
494+ creatingAfterWorktree,
495+ creatingAfterFolder,
496+ readyAfterWorktree,
497+ } , {
498+ creatingInitially : false ,
499+ readyInitially : false ,
500+ creatingLifecycle : SessionLifecycle . Creating ,
501+ readyLifecycle : SessionLifecycle . Ready ,
502+ creatingAfterWorktree : true ,
503+ creatingAfterFolder : false ,
504+ readyAfterWorktree : false ,
505+ } ) ;
506+ } ) ;
507+
430508 suite ( 'resourceRead' , ( ) => {
431509
432510 test ( 'maps missing files to NotFound' , async ( ) => {
0 commit comments