diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts index b30e9675cd..ca2ecf7bc1 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts @@ -26,6 +26,7 @@ import { ToolRegistry, COMMON_IGNORE_PATTERNS, GEMINI_IGNORE_FILE_NAME, + ApprovalMode, // DEFAULT_FILE_EXCLUDES, CoreToolCallStatus, type Config, @@ -146,6 +147,7 @@ describe('handleAtCommand', () => { getClient: () => undefined, }), getMessageBus: () => mockMessageBus, + getApprovalMode: () => ApprovalMode.DEFAULT, } as unknown as Config; const registry = new ToolRegistry(mockConfig, mockMessageBus); diff --git a/packages/cli/src/ui/hooks/atCommandProcessor_agents.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor_agents.test.ts index 90267e64c0..2dc5104a86 100644 --- a/packages/cli/src/ui/hooks/atCommandProcessor_agents.test.ts +++ b/packages/cli/src/ui/hooks/atCommandProcessor_agents.test.ts @@ -18,6 +18,7 @@ import { StandardFileSystemService, ToolRegistry, COMMON_IGNORE_PATTERNS, + ApprovalMode, } from '@google/gemini-cli-core'; import * as os from 'node:os'; import type { UseHistoryManagerReturn } from './useHistoryManager.js'; @@ -136,6 +137,7 @@ describe('handleAtCommand with Agents', () => { getMessageBus: () => mockMessageBus, interactive: true, getAgentRegistry: () => mockAgentRegistry, + getApprovalMode: () => ApprovalMode.DEFAULT, } as unknown as Config; const registry = new ToolRegistry(mockConfig, mockMessageBus); diff --git a/packages/core/src/tools/tool-registry.test.ts b/packages/core/src/tools/tool-registry.test.ts index 3d27171ad1..006bfcd894 100644 --- a/packages/core/src/tools/tool-registry.test.ts +++ b/packages/core/src/tools/tool-registry.test.ts @@ -22,6 +22,8 @@ import { ToolRegistry, DiscoveredTool } from './tool-registry.js'; import { DISCOVERED_TOOL_PREFIX, UPDATE_TOPIC_TOOL_NAME, + ENTER_PLAN_MODE_TOOL_NAME, + EXIT_PLAN_MODE_TOOL_NAME, } from './tool-names.js'; import { DiscoveredMCPTool } from './mcp-tool.js'; import { @@ -833,6 +835,40 @@ describe('ToolRegistry', () => { expect(toolRegistry.getAllToolNames()).toContain(UPDATE_TOPIC_TOOL_NAME); expect(toolRegistry.getTool(UPDATE_TOPIC_TOOL_NAME)).toBe(topicTool); }); + + it('should show enter_plan_mode only when NOT in plan mode', () => { + const enterTool = new MockTool({ name: ENTER_PLAN_MODE_TOOL_NAME }); + toolRegistry.registerTool(enterTool); + + // Not in plan mode + vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.DEFAULT); + expect(toolRegistry.getAllToolNames()).toContain( + ENTER_PLAN_MODE_TOOL_NAME, + ); + + // In plan mode + vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.PLAN); + expect(toolRegistry.getAllToolNames()).not.toContain( + ENTER_PLAN_MODE_TOOL_NAME, + ); + }); + + it('should show exit_plan_mode only when in plan mode', () => { + const exitTool = new MockTool({ name: EXIT_PLAN_MODE_TOOL_NAME }); + toolRegistry.registerTool(exitTool); + + // Not in plan mode + vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.DEFAULT); + expect(toolRegistry.getAllToolNames()).not.toContain( + EXIT_PLAN_MODE_TOOL_NAME, + ); + + // In plan mode + vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.PLAN); + expect(toolRegistry.getAllToolNames()).toContain( + EXIT_PLAN_MODE_TOOL_NAME, + ); + }); }); describe('DiscoveredToolInvocation', () => { diff --git a/packages/core/src/tools/tool-registry.ts b/packages/core/src/tools/tool-registry.ts index a059c964d0..f9551d75da 100644 --- a/packages/core/src/tools/tool-registry.ts +++ b/packages/core/src/tools/tool-registry.ts @@ -31,6 +31,8 @@ import { WRITE_FILE_TOOL_NAME, EDIT_TOOL_NAME, UPDATE_TOPIC_TOOL_NAME, + ENTER_PLAN_MODE_TOOL_NAME, + EXIT_PLAN_MODE_TOOL_NAME, } from './tool-names.js'; type ToolParams = Record; @@ -583,6 +585,14 @@ export class ToolRegistry { } } + const isPlanMode = this.config.getApprovalMode() === ApprovalMode.PLAN; + if ( + (tool.name === ENTER_PLAN_MODE_TOOL_NAME && isPlanMode) || + (tool.name === EXIT_PLAN_MODE_TOOL_NAME && !isPlanMode) + ) { + return false; + } + const normalizedClassName = tool.constructor.name.replace(/^_+/, ''); const possibleNames = [tool.name, normalizedClassName]; if (tool instanceof DiscoveredMCPTool) {