diff --git a/packages/cli/src/ui/commands/extensionsCommand.test.ts b/packages/cli/src/ui/commands/extensionsCommand.test.ts index ffbd4bb722..fbbd5d900d 100644 --- a/packages/cli/src/ui/commands/extensionsCommand.test.ts +++ b/packages/cli/src/ui/commands/extensionsCommand.test.ts @@ -134,6 +134,21 @@ describe('extensionsCommand', () => { expect.any(Number), ); }); + + it('should show a message if no extensions are installed', async () => { + mockGetExtensions.mockReturnValue([]); + const command = extensionsCommand(); + if (!command.action) throw new Error('Action not defined'); + await command.action(mockContext, ''); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: 'No extensions installed. Run `/extensions explore` to check out the gallery.', + }, + expect.any(Number), + ); + }); }); describe('completeExtensions', () => { @@ -216,6 +231,19 @@ describe('extensionsCommand', () => { ); }); + it('should show a message if no extensions are installed', async () => { + mockGetExtensions.mockReturnValue([]); + await updateAction(mockContext, 'ext-one'); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: 'No extensions installed. Run `/extensions explore` to check out the gallery.', + }, + expect.any(Number), + ); + }); + it('should inform user if there are no extensions to update with --all', async () => { mockDispatchExtensionState.mockImplementationOnce( (action: ExtensionUpdateAction) => { @@ -607,6 +635,25 @@ describe('extensionsCommand', () => { mockContext.invocation!.name = 'restart'; }); + it('should show a message if no extensions are installed', async () => { + mockContext.services.config!.getExtensionLoader = vi + .fn() + .mockImplementation(() => ({ + getExtensions: () => [], + restartExtension: mockRestartExtension, + })); + + await restartAction!(mockContext, '--all'); + + expect(mockContext.ui.addItem).toHaveBeenCalledWith( + { + type: MessageType.INFO, + text: 'No extensions installed. Run `/extensions explore` to check out the gallery.', + }, + expect.any(Number), + ); + }); + it('restarts all active extensions when --all is provided', async () => { const mockExtensions = [ { name: 'ext1', isActive: true }, diff --git a/packages/cli/src/ui/commands/extensionsCommand.ts b/packages/cli/src/ui/commands/extensionsCommand.ts index 8157ce3b2c..c523c536e0 100644 --- a/packages/cli/src/ui/commands/extensionsCommand.ts +++ b/packages/cli/src/ui/commands/extensionsCommand.ts @@ -24,12 +24,35 @@ import { ExtensionManager } from '../../config/extension-manager.js'; import { SettingScope } from '../../config/settings.js'; import { theme } from '../semantic-colors.js'; +function showMessageIfNoExtensions( + context: CommandContext, + extensions: unknown[], +): boolean { + if (extensions.length === 0) { + context.ui.addItem( + { + type: MessageType.INFO, + text: 'No extensions installed. Run `/extensions explore` to check out the gallery.', + }, + Date.now(), + ); + return true; + } + return false; +} + async function listAction(context: CommandContext) { + const extensions = context.services.config + ? listExtensions(context.services.config) + : []; + + if (showMessageIfNoExtensions(context, extensions)) { + return; + } + const historyItem: HistoryItemExtensionsList = { type: MessageType.EXTENSIONS_LIST, - extensions: context.services.config - ? listExtensions(context.services.config) - : [], + extensions, }; context.ui.addItem(historyItem, Date.now()); @@ -56,11 +79,17 @@ function updateAction(context: CommandContext, args: string): Promise { (resolve) => (resolveUpdateComplete = resolve), ); + const extensions = context.services.config + ? listExtensions(context.services.config) + : []; + + if (showMessageIfNoExtensions(context, extensions)) { + return Promise.resolve(); + } + const historyItem: HistoryItemExtensionsList = { type: MessageType.EXTENSIONS_LIST, - extensions: context.services.config - ? listExtensions(context.services.config) - : [], + extensions, }; updateComplete.then((updateInfos) => { @@ -138,6 +167,11 @@ async function restartAction( return; } + const extensions = extensionLoader.getExtensions(); + if (showMessageIfNoExtensions(context, extensions)) { + return; + } + const restartArgs = args.split(' ').filter((value) => value.length > 0); const all = restartArgs.length === 1 && restartArgs[0] === '--all'; const names = all ? null : restartArgs;