fix(cli): implement --all flag for extensions uninstall (#21319)

This commit is contained in:
Sehoon Shon
2026-03-05 22:02:01 -05:00
committed by GitHub
parent 4d310dda68
commit 509d4ae0a9
6 changed files with 178 additions and 41 deletions

View File

@@ -160,6 +160,7 @@ vi.mock('./hooks/useIdeTrustListener.js');
vi.mock('./hooks/useMessageQueue.js');
vi.mock('./hooks/useApprovalModeIndicator.js');
vi.mock('./hooks/useGitBranchName.js');
vi.mock('./hooks/useExtensionUpdates.js');
vi.mock('./contexts/VimModeContext.js');
vi.mock('./contexts/SessionContext.js');
vi.mock('./components/shared/text-buffer.js');
@@ -218,6 +219,10 @@ import { useIdeTrustListener } from './hooks/useIdeTrustListener.js';
import { useMessageQueue } from './hooks/useMessageQueue.js';
import { useApprovalModeIndicator } from './hooks/useApprovalModeIndicator.js';
import { useGitBranchName } from './hooks/useGitBranchName.js';
import {
useConfirmUpdateRequests,
useExtensionUpdates,
} from './hooks/useExtensionUpdates.js';
import { useVimMode } from './contexts/VimModeContext.js';
import { useSessionStats } from './contexts/SessionContext.js';
import { useTextBuffer } from './components/shared/text-buffer.js';
@@ -299,6 +304,8 @@ describe('AppContainer State Management', () => {
const mockedUseMessageQueue = useMessageQueue as Mock;
const mockedUseApprovalModeIndicator = useApprovalModeIndicator as Mock;
const mockedUseGitBranchName = useGitBranchName as Mock;
const mockedUseConfirmUpdateRequests = useConfirmUpdateRequests as Mock;
const mockedUseExtensionUpdates = useExtensionUpdates as Mock;
const mockedUseVimMode = useVimMode as Mock;
const mockedUseSessionStats = useSessionStats as Mock;
const mockedUseTextBuffer = useTextBuffer as Mock;
@@ -451,6 +458,15 @@ describe('AppContainer State Management', () => {
isFocused: true,
hasReceivedFocusEvent: true,
});
mockedUseConfirmUpdateRequests.mockReturnValue({
addConfirmUpdateExtensionRequest: vi.fn(),
confirmUpdateExtensionRequests: [],
});
mockedUseExtensionUpdates.mockReturnValue({
extensionsUpdateState: new Map(),
extensionsUpdateStateInternal: new Map(),
dispatchExtensionStateUpdate: vi.fn(),
});
// Mock Config
mockConfig = makeFakeConfig();

View File

@@ -755,7 +755,7 @@ describe('extensionsCommand', () => {
await uninstallAction!(mockContext, '');
expect(mockContext.ui.addItem).toHaveBeenCalledWith({
type: MessageType.ERROR,
text: 'Usage: /extensions uninstall <extension-name>',
text: 'Usage: /extensions uninstall <extension-names...>|--all',
});
expect(mockUninstallExtension).not.toHaveBeenCalled();
});

View File

@@ -594,33 +594,53 @@ async function uninstallAction(context: CommandContext, args: string) {
return;
}
const name = args.trim();
if (!name) {
const uninstallArgs = args.split(' ').filter((value) => value.length > 0);
const all = uninstallArgs.includes('--all');
const names = uninstallArgs.filter((a) => !a.startsWith('--'));
if (!all && names.length === 0) {
context.ui.addItem({
type: MessageType.ERROR,
text: `Usage: /extensions uninstall <extension-name>`,
text: `Usage: /extensions uninstall <extension-names...>|--all`,
});
return;
}
context.ui.addItem({
type: MessageType.INFO,
text: `Uninstalling extension "${name}"...`,
});
let namesToUninstall: string[] = [];
if (all) {
namesToUninstall = extensionLoader.getExtensions().map((ext) => ext.name);
} else {
namesToUninstall = names;
}
try {
await extensionLoader.uninstallExtension(name, false);
if (namesToUninstall.length === 0) {
context.ui.addItem({
type: MessageType.INFO,
text: `Extension "${name}" uninstalled successfully.`,
text: all ? 'No extensions installed.' : 'No extension name provided.',
});
} catch (error) {
return;
}
for (const extensionName of namesToUninstall) {
context.ui.addItem({
type: MessageType.ERROR,
text: `Failed to uninstall extension "${name}": ${getErrorMessage(
error,
)}`,
type: MessageType.INFO,
text: `Uninstalling extension "${extensionName}"...`,
});
try {
await extensionLoader.uninstallExtension(extensionName, false);
context.ui.addItem({
type: MessageType.INFO,
text: `Extension "${extensionName}" uninstalled successfully.`,
});
} catch (error) {
context.ui.addItem({
type: MessageType.ERROR,
text: `Failed to uninstall extension "${extensionName}": ${getErrorMessage(
error,
)}`,
});
}
}
}