mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
Conditionally use consent flow (#8551)
This commit is contained in:
@@ -47,7 +47,7 @@ export async function handleInstall(args: InstallArgs) {
|
||||
throw new Error('Either --source or --path must be provided.');
|
||||
}
|
||||
|
||||
const name = await installExtension(installMetadata);
|
||||
const name = await installExtension(installMetadata, true);
|
||||
console.log(`Extension "${name}" installed successfully and enabled.`);
|
||||
} catch (error) {
|
||||
console.error(getErrorMessage(error));
|
||||
|
||||
@@ -596,7 +596,7 @@ describe('extension tests', () => {
|
||||
mockQuestion.mockImplementation((_query, callback) => callback('y'));
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
installExtension({ source: sourceExtDir, type: 'local' }, true),
|
||||
).resolves.toBe('my-local-extension');
|
||||
|
||||
expect(consoleInfoSpy).toHaveBeenCalledWith(
|
||||
@@ -629,7 +629,7 @@ describe('extension tests', () => {
|
||||
mockQuestion.mockImplementation((_query, callback) => callback('y'));
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
installExtension({ source: sourceExtDir, type: 'local' }, true),
|
||||
).resolves.toBe('my-local-extension');
|
||||
|
||||
expect(mockQuestion).toHaveBeenCalledWith(
|
||||
@@ -654,7 +654,7 @@ describe('extension tests', () => {
|
||||
mockQuestion.mockImplementation((_query, callback) => callback('n'));
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }),
|
||||
installExtension({ source: sourceExtDir, type: 'local' }, true),
|
||||
).rejects.toThrow('Installation cancelled by user.');
|
||||
|
||||
expect(mockQuestion).toHaveBeenCalledWith(
|
||||
@@ -662,6 +662,24 @@ describe('extension tests', () => {
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('should ignore consent flow if not required', async () => {
|
||||
const sourceExtDir = createExtension({
|
||||
extensionsDir: tempHomeDir,
|
||||
name: 'my-local-extension',
|
||||
version: '1.0.0',
|
||||
mcpServers: {
|
||||
'test-server': {
|
||||
command: 'node',
|
||||
args: ['server.js'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
installExtension({ source: sourceExtDir, type: 'local' }, false),
|
||||
).resolves.toBe('my-local-extension');
|
||||
});
|
||||
});
|
||||
|
||||
describe('uninstallExtension', () => {
|
||||
|
||||
@@ -418,6 +418,7 @@ async function promptForContinuation(prompt: string): Promise<boolean> {
|
||||
|
||||
export async function installExtension(
|
||||
installMetadata: ExtensionInstallMetadata,
|
||||
askConsent: boolean = false,
|
||||
cwd: string = process.cwd(),
|
||||
): Promise<string> {
|
||||
const logger = getClearcutLogger(cwd);
|
||||
@@ -482,30 +483,9 @@ export async function installExtension(
|
||||
`Extension "${newExtensionName}" is already installed. Please uninstall it first.`,
|
||||
);
|
||||
}
|
||||
|
||||
const mcpServerEntries = Object.entries(
|
||||
newExtensionConfig.mcpServers || {},
|
||||
);
|
||||
if (mcpServerEntries.length) {
|
||||
console.info('This extension will run the following MCP servers: ');
|
||||
for (const [key, mcpServer] of mcpServerEntries) {
|
||||
const isLocal = !!mcpServer.command;
|
||||
console.info(
|
||||
` * ${key} (${isLocal ? 'local' : 'remote'}): ${mcpServer.description}`,
|
||||
);
|
||||
}
|
||||
console.info(
|
||||
'The extension will append info to your gemini.md context',
|
||||
);
|
||||
|
||||
const shouldContinue = await promptForContinuation(
|
||||
'Do you want to continue? (y/n): ',
|
||||
);
|
||||
if (!shouldContinue) {
|
||||
throw new Error('Installation cancelled by user.');
|
||||
}
|
||||
if (askConsent) {
|
||||
await requestConsent(newExtensionConfig);
|
||||
}
|
||||
|
||||
await fs.promises.mkdir(destinationPath, { recursive: true });
|
||||
|
||||
if (installMetadata.type === 'local' || installMetadata.type === 'git') {
|
||||
@@ -556,6 +536,27 @@ export async function installExtension(
|
||||
}
|
||||
}
|
||||
|
||||
async function requestConsent(extensionConfig: ExtensionConfig) {
|
||||
const mcpServerEntries = Object.entries(extensionConfig.mcpServers || {});
|
||||
if (mcpServerEntries.length) {
|
||||
console.info('This extension will run the following MCP servers: ');
|
||||
for (const [key, mcpServer] of mcpServerEntries) {
|
||||
const isLocal = !!mcpServer.command;
|
||||
console.info(
|
||||
` * ${key} (${isLocal ? 'local' : 'remote'}): ${mcpServer.description}`,
|
||||
);
|
||||
}
|
||||
console.info('The extension will append info to your gemini.md context');
|
||||
|
||||
const shouldContinue = await promptForContinuation(
|
||||
'Do you want to continue? (y/n): ',
|
||||
);
|
||||
if (!shouldContinue) {
|
||||
throw new Error('Installation cancelled by user.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadExtensionConfig(
|
||||
context: LoadExtensionContext,
|
||||
): Promise<ExtensionConfig | null> {
|
||||
@@ -684,6 +685,7 @@ export async function updateExtension(
|
||||
type: extension.type,
|
||||
ref: extension.ref,
|
||||
},
|
||||
false,
|
||||
cwd,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user