mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-14 13:53:02 -07:00
fix(cli)#21297: clear skills consent dialog before reload (#26431)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
@@ -149,6 +149,35 @@ describe('consent', () => {
|
||||
expect(consent).toBe(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it('should clear the active confirmation request before resolving', async () => {
|
||||
const clearConfirmationRequest = vi.fn();
|
||||
const steps: string[] = [];
|
||||
const addExtensionUpdateConfirmationRequest = vi
|
||||
.fn()
|
||||
.mockImplementation((request: ConfirmationRequest) => {
|
||||
steps.push('prompted');
|
||||
request.onConfirm(true);
|
||||
steps.push('confirmed');
|
||||
});
|
||||
|
||||
const consentPromise = requestConsentInteractive(
|
||||
'Test consent',
|
||||
addExtensionUpdateConfirmationRequest,
|
||||
() => {
|
||||
steps.push('cleared');
|
||||
clearConfirmationRequest();
|
||||
},
|
||||
).then((consent) => {
|
||||
steps.push('resolved');
|
||||
return consent;
|
||||
});
|
||||
|
||||
expect(clearConfirmationRequest).toHaveBeenCalledTimes(1);
|
||||
expect(steps).toEqual(['prompted', 'cleared', 'confirmed']);
|
||||
await expect(consentPromise).resolves.toBe(true);
|
||||
expect(steps).toEqual(['prompted', 'cleared', 'confirmed', 'resolved']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maybeRequestConsentOrFail', () => {
|
||||
|
||||
@@ -78,10 +78,12 @@ export async function requestConsentNonInteractive(
|
||||
export async function requestConsentInteractive(
|
||||
consentDescription: string,
|
||||
addExtensionUpdateConfirmationRequest: (value: ConfirmationRequest) => void,
|
||||
clearConfirmationRequest?: () => void,
|
||||
): Promise<boolean> {
|
||||
return promptForConsentInteractive(
|
||||
consentDescription + '\n\nDo you want to continue?',
|
||||
addExtensionUpdateConfirmationRequest,
|
||||
clearConfirmationRequest,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,12 +131,14 @@ export async function promptForConsentNonInteractive(
|
||||
async function promptForConsentInteractive(
|
||||
prompt: string,
|
||||
addExtensionUpdateConfirmationRequest: (value: ConfirmationRequest) => void,
|
||||
clearConfirmationRequest?: () => void,
|
||||
): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
addExtensionUpdateConfirmationRequest({
|
||||
prompt,
|
||||
onConfirm: (resolvedConfirmed) => {
|
||||
resolve(resolvedConfirmed);
|
||||
clearConfirmationRequest?.();
|
||||
setImmediate(() => resolve(resolvedConfirmed));
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,6 +37,7 @@ vi.mock('../../config/extensions/consent.js', async (importOriginal) => {
|
||||
});
|
||||
|
||||
import { linkSkill } from '../../utils/skillUtils.js';
|
||||
import { requestConsentInteractive } from '../../config/extensions/consent.js';
|
||||
|
||||
vi.mock('../../config/settings.js', async (importOriginal) => {
|
||||
const actual =
|
||||
@@ -253,6 +254,36 @@ describe('skillsCommand', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass a cleanup callback for interactive workspace consent', async () => {
|
||||
const linkCmd = skillsCommand.subCommands!.find(
|
||||
(s) => s.name === 'link',
|
||||
)!;
|
||||
context.ui.setConfirmationRequest = vi.fn();
|
||||
vi.mocked(linkSkill).mockImplementation(
|
||||
async (_sourcePath, _scope, _addItem, requestConsent) => {
|
||||
expect(requestConsent).toBeDefined();
|
||||
await requestConsent!(
|
||||
[{ name: 'test-skill', location: '/path' } as SkillDefinition],
|
||||
'/workspace/.gemini/skills',
|
||||
);
|
||||
return [{ name: 'test-skill', location: '/path' }];
|
||||
},
|
||||
);
|
||||
|
||||
await linkCmd.action!(context, '/some/path --scope workspace');
|
||||
|
||||
const requestConsentCall = vi
|
||||
.mocked(requestConsentInteractive)
|
||||
.mock.calls.at(-1);
|
||||
expect(requestConsentCall?.[1]).toEqual(expect.any(Function));
|
||||
|
||||
const clearConfirmationRequest = requestConsentCall?.[2];
|
||||
expect(clearConfirmationRequest).toBeTypeOf('function');
|
||||
|
||||
clearConfirmationRequest?.();
|
||||
expect(context.ui.setConfirmationRequest).toHaveBeenCalledWith(null);
|
||||
});
|
||||
|
||||
it('should show error if link fails', async () => {
|
||||
const linkCmd = skillsCommand.subCommands!.find(
|
||||
(s) => s.name === 'link',
|
||||
|
||||
@@ -118,6 +118,7 @@ async function linkAction(
|
||||
return requestConsentInteractive(
|
||||
consentString,
|
||||
context.ui.setConfirmationRequest.bind(context.ui),
|
||||
() => context.ui.setConfirmationRequest(null),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -89,7 +89,7 @@ export interface CommandContext {
|
||||
*
|
||||
* @param value The confirmation request details.
|
||||
*/
|
||||
setConfirmationRequest: (value: ConfirmationRequest) => void;
|
||||
setConfirmationRequest: (value: ConfirmationRequest | null) => void;
|
||||
removeComponent: () => void;
|
||||
toggleBackgroundTasks: () => void;
|
||||
toggleShortcutsHelp: () => void;
|
||||
|
||||
Reference in New Issue
Block a user