diff --git a/src/renderer/components/extensions/common/InstallButton.tsx b/src/renderer/components/extensions/common/InstallButton.tsx
index 93bdf907..2bc48112 100644
--- a/src/renderer/components/extensions/common/InstallButton.tsx
+++ b/src/renderer/components/extensions/common/InstallButton.tsx
@@ -13,6 +13,7 @@ import {
TooltipTrigger,
} from '@renderer/components/ui/tooltip';
import { useStore } from '@renderer/store';
+import { getExtensionActionDisableReason } from '@shared/utils/extensionNormalizers';
import { Check, Loader2, Trash2 } from 'lucide-react';
import { useShallow } from 'zustand/react/shallow';
@@ -43,18 +44,11 @@ export const InstallButton = ({
cliStatusLoading: s.cliStatusLoading,
}))
);
- const cliUnknown = cliStatus === null;
- const cliMissing = cliStatus?.installed === false;
- const authMissing = cliStatus?.installed === true && !cliStatus.authLoggedIn;
- const disableReason = cliStatusLoading
- ? 'Checking Claude CLI status...'
- : cliUnknown
- ? 'Checking Claude CLI availability...'
- : cliMissing
- ? 'Claude CLI required. Install it from the Dashboard.'
- : authMissing
- ? 'Claude CLI is installed but not signed in. Open the Dashboard to sign in.'
- : null;
+ const disableReason = getExtensionActionDisableReason({
+ isInstalled,
+ cliStatus,
+ cliStatusLoading,
+ });
const isDisabled = disabled || Boolean(disableReason);
const [lastAction, setLastAction] = useState<'install' | 'uninstall' | null>(null);
diff --git a/src/renderer/components/extensions/plugins/PluginCard.tsx b/src/renderer/components/extensions/plugins/PluginCard.tsx
index ee73899b..24ca2d87 100644
--- a/src/renderer/components/extensions/plugins/PluginCard.tsx
+++ b/src/renderer/components/extensions/plugins/PluginCard.tsx
@@ -5,6 +5,7 @@
import { Badge } from '@renderer/components/ui/badge';
import { useStore } from '@renderer/store';
import {
+ getInstallationSummaryLabel,
getCapabilityLabel,
hasInstallationInScope,
inferCapabilities,
@@ -31,6 +32,7 @@ export const PluginCard = ({ plugin, index, onClick }: PluginCardProps): React.J
const uninstallPlugin = useStore((s) => s.uninstallPlugin);
const installError = useStore((s) => s.installErrors[plugin.pluginId]);
const isUserInstalled = hasInstallationInScope(plugin.installations, 'user');
+ const installSummaryLabel = getInstallationSummaryLabel(plugin.installations);
const baseStriped = index % 2 === 0;
const smStriped = Math.floor(index / 2) % 2 === 0;
const xlStriped = Math.floor(index / 3) % 2 === 0;
@@ -83,12 +85,12 @@ export const PluginCard = ({ plugin, index, onClick }: PluginCardProps): React.J
- {plugin.isInstalled && (
+ {installSummaryLabel && (
- Installed
+ {installSummaryLabel}
)}
diff --git a/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx b/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx
index 1e40866a..9d501e81 100644
--- a/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx
+++ b/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx
@@ -25,6 +25,7 @@ import {
} from '@renderer/components/ui/select';
import { useStore } from '@renderer/store';
import {
+ getInstallationSummaryLabel,
getCapabilityLabel,
hasInstallationInScope,
inferCapabilities,
@@ -99,6 +100,7 @@ export const PluginDetailDialog = ({
const readme = readmes[plugin.pluginId];
const isReadmeLoading = readmeLoading[plugin.pluginId] ?? false;
const isInstalledForScope = hasInstallationInScope(plugin.installations, scope);
+ const installSummaryLabel = getInstallationSummaryLabel(plugin.installations);
return (