mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 04:54:25 -07:00
feat(cli): Suppress slash command execution and suggestions in shell … (#11380)
This commit is contained in:
@@ -121,6 +121,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -146,6 +147,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { completion, textBuffer };
|
||||
@@ -179,6 +181,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -207,6 +210,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -233,6 +237,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -246,6 +251,56 @@ describe('useCommandCompletion', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
shellModeActive: false,
|
||||
expectedSuggestions: 1,
|
||||
expectedShowSuggestions: true,
|
||||
description:
|
||||
'should show slash command suggestions when shellModeActive is false',
|
||||
},
|
||||
{
|
||||
shellModeActive: true,
|
||||
expectedSuggestions: 0,
|
||||
expectedShowSuggestions: false,
|
||||
description:
|
||||
'should not show slash command suggestions when shellModeActive is true',
|
||||
},
|
||||
])(
|
||||
'$description',
|
||||
async ({
|
||||
shellModeActive,
|
||||
expectedSuggestions,
|
||||
expectedShowSuggestions,
|
||||
}) => {
|
||||
setupMocks({
|
||||
slashSuggestions: [{ label: 'clear', value: 'clear' }],
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => {
|
||||
const textBuffer = useTextBufferForTest('/');
|
||||
const completion = useCommandCompletion(
|
||||
textBuffer,
|
||||
testDirs,
|
||||
testRootDir,
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
shellModeActive, // Parameterized shellModeActive
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.suggestions.length).toBe(expectedSuggestions);
|
||||
expect(result.current.showSuggestions).toBe(
|
||||
expectedShowSuggestions,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Navigation', () => {
|
||||
@@ -272,6 +327,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -293,6 +349,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -313,6 +370,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -339,6 +397,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -368,6 +427,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -405,6 +465,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
),
|
||||
);
|
||||
@@ -435,6 +496,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -465,6 +527,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -498,6 +561,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -530,6 +594,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -562,6 +627,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -594,6 +660,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -619,6 +686,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
@@ -644,6 +712,7 @@ describe('useCommandCompletion', () => {
|
||||
[],
|
||||
mockCommandContext,
|
||||
false,
|
||||
false,
|
||||
mockConfig,
|
||||
);
|
||||
return { ...completion, textBuffer };
|
||||
|
||||
@@ -51,6 +51,7 @@ export function useCommandCompletion(
|
||||
slashCommands: readonly SlashCommand[],
|
||||
commandContext: CommandContext,
|
||||
reverseSearchActive: boolean = false,
|
||||
shellModeActive: boolean,
|
||||
config?: Config,
|
||||
): UseCommandCompletionReturn {
|
||||
const {
|
||||
@@ -163,7 +164,7 @@ export function useCommandCompletion(
|
||||
});
|
||||
|
||||
const slashCompletionRange = useSlashCompletion({
|
||||
enabled: completionMode === CompletionMode.SLASH,
|
||||
enabled: completionMode === CompletionMode.SLASH && !shellModeActive,
|
||||
query,
|
||||
slashCommands,
|
||||
commandContext,
|
||||
|
||||
@@ -1207,6 +1207,39 @@ describe('useGeminiStream', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not call handleSlashCommand is shell mode is active', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useGeminiStream(
|
||||
new MockedGeminiClientClass(mockConfig),
|
||||
[],
|
||||
mockAddItem,
|
||||
mockConfig,
|
||||
mockLoadedSettings,
|
||||
() => {},
|
||||
mockHandleSlashCommand,
|
||||
true,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
() => Promise.resolve(),
|
||||
false,
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('/about');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockHandleSlashCommand).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Memory Refresh on save_memory', () => {
|
||||
|
||||
@@ -327,41 +327,43 @@ export const useGeminiStream = (
|
||||
onDebugMessage(`User query: '${trimmedQuery}'`);
|
||||
await logger?.logMessage(MessageSenderType.USER, trimmedQuery);
|
||||
|
||||
// Handle UI-only commands first
|
||||
const slashCommandResult = isSlashCommand(trimmedQuery)
|
||||
? await handleSlashCommand(trimmedQuery)
|
||||
: false;
|
||||
if (!shellModeActive) {
|
||||
// Handle UI-only commands first
|
||||
const slashCommandResult = isSlashCommand(trimmedQuery)
|
||||
? await handleSlashCommand(trimmedQuery)
|
||||
: false;
|
||||
|
||||
if (slashCommandResult) {
|
||||
switch (slashCommandResult.type) {
|
||||
case 'schedule_tool': {
|
||||
const { toolName, toolArgs } = slashCommandResult;
|
||||
const toolCallRequest: ToolCallRequestInfo = {
|
||||
callId: `${toolName}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
||||
name: toolName,
|
||||
args: toolArgs,
|
||||
isClientInitiated: true,
|
||||
prompt_id,
|
||||
};
|
||||
scheduleToolCalls([toolCallRequest], abortSignal);
|
||||
return { queryToSend: null, shouldProceed: false };
|
||||
}
|
||||
case 'submit_prompt': {
|
||||
localQueryToSendToGemini = slashCommandResult.content;
|
||||
if (slashCommandResult) {
|
||||
switch (slashCommandResult.type) {
|
||||
case 'schedule_tool': {
|
||||
const { toolName, toolArgs } = slashCommandResult;
|
||||
const toolCallRequest: ToolCallRequestInfo = {
|
||||
callId: `${toolName}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
||||
name: toolName,
|
||||
args: toolArgs,
|
||||
isClientInitiated: true,
|
||||
prompt_id,
|
||||
};
|
||||
scheduleToolCalls([toolCallRequest], abortSignal);
|
||||
return { queryToSend: null, shouldProceed: false };
|
||||
}
|
||||
case 'submit_prompt': {
|
||||
localQueryToSendToGemini = slashCommandResult.content;
|
||||
|
||||
return {
|
||||
queryToSend: localQueryToSendToGemini,
|
||||
shouldProceed: true,
|
||||
};
|
||||
}
|
||||
case 'handled': {
|
||||
return { queryToSend: null, shouldProceed: false };
|
||||
}
|
||||
default: {
|
||||
const unreachable: never = slashCommandResult;
|
||||
throw new Error(
|
||||
`Unhandled slash command result type: ${unreachable}`,
|
||||
);
|
||||
return {
|
||||
queryToSend: localQueryToSendToGemini,
|
||||
shouldProceed: true,
|
||||
};
|
||||
}
|
||||
case 'handled': {
|
||||
return { queryToSend: null, shouldProceed: false };
|
||||
}
|
||||
default: {
|
||||
const unreachable: never = slashCommandResult;
|
||||
throw new Error(
|
||||
`Unhandled slash command result type: ${unreachable}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user