diff --git a/packages/core/src/scheduler/policy.test.ts b/packages/core/src/scheduler/policy.test.ts index c228ead10d..1618db0701 100644 --- a/packages/core/src/scheduler/policy.test.ts +++ b/packages/core/src/scheduler/policy.test.ts @@ -766,6 +766,33 @@ describe('policy.ts', () => { }), ); }); + + it('should map ProceedAlways to ProceedOnce in Plan Mode', async () => { + const mockConfig = { + getApprovalMode: vi.fn().mockReturnValue(ApprovalMode.PLAN), + setApprovalMode: vi.fn(), + getSessionId: vi.fn().mockReturnValue('test-session-id'), + } as unknown as Mocked; + (mockConfig as unknown as { config: Config }).config = + mockConfig as Config; + const mockMessageBus = { + publish: vi.fn(), + } as unknown as Mocked; + (mockConfig as unknown as { messageBus: MessageBus }).messageBus = + mockMessageBus; + const tool = { name: 'replace' } as AnyDeclarativeTool; + + await updatePolicy( + tool, + ToolConfirmationOutcome.ProceedAlways, + undefined, + mockConfig, + mockMessageBus, + ); + + expect(mockConfig.setApprovalMode).not.toHaveBeenCalled(); + expect(mockMessageBus.publish).not.toHaveBeenCalled(); + }); }); describe('getPolicyDenialError', () => { diff --git a/packages/core/src/scheduler/policy.ts b/packages/core/src/scheduler/policy.ts index 69e2a69e6c..c99b5e2998 100644 --- a/packages/core/src/scheduler/policy.ts +++ b/packages/core/src/scheduler/policy.ts @@ -119,6 +119,17 @@ export async function updatePolicy( messageBus: MessageBus, toolInvocation?: AnyToolInvocation, ): Promise { + const currentMode = context.config.getApprovalMode(); + + // If in Plan Mode, map 'Proceed Always' (Allow for this session) to 'Proceed Once' (Allow once) + // to prevent transitioning to AUTO_EDIT mode and updating policy. + if ( + currentMode === ApprovalMode.PLAN && + outcome === ToolConfirmationOutcome.ProceedAlways + ) { + outcome = ToolConfirmationOutcome.ProceedOnce; + } + // Mode Transitions (AUTO_EDIT) if (isAutoEditTransition(tool, outcome)) { context.config.setApprovalMode(ApprovalMode.AUTO_EDIT); @@ -128,7 +139,6 @@ export async function updatePolicy( // Determine persist scope if we are persisting. let persistScope: 'workspace' | 'user' | undefined; let modes: ApprovalMode[] | undefined; - const currentMode = context.config.getApprovalMode(); // If this is an 'Always Allow' selection, we restrict it to the current mode // and more permissive modes.