claudeup 1.8.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/claudeup.js +20 -2
- package/package.json +10 -19
- package/src/data/cli-tools.js +123 -0
- package/src/data/cli-tools.ts +140 -0
- package/{dist → src}/data/marketplaces.js +23 -24
- package/src/data/marketplaces.ts +95 -0
- package/src/data/mcp-servers.js +509 -0
- package/src/data/mcp-servers.ts +526 -0
- package/src/data/statuslines.js +159 -0
- package/src/data/statuslines.ts +188 -0
- package/src/index.js +4 -0
- package/src/index.ts +5 -0
- package/{dist → src}/main.js +46 -47
- package/src/main.tsx +145 -0
- package/src/opentui.d.ts +191 -0
- package/{dist → src}/prerunner/index.js +31 -41
- package/src/prerunner/index.ts +124 -0
- package/{dist → src}/services/claude-runner.js +9 -10
- package/src/services/claude-runner.ts +31 -0
- package/{dist → src}/services/claude-settings.js +72 -33
- package/src/services/claude-settings.ts +934 -0
- package/src/services/local-marketplace.js +339 -0
- package/src/services/local-marketplace.ts +489 -0
- package/{dist → src}/services/mcp-registry.js +13 -14
- package/src/services/mcp-registry.ts +105 -0
- package/{dist → src}/services/plugin-manager.js +61 -13
- package/src/services/plugin-manager.ts +693 -0
- package/{dist → src}/services/plugin-mcp-config.js +19 -18
- package/src/services/plugin-mcp-config.ts +242 -0
- package/{dist → src}/services/update-cache.js +0 -1
- package/src/services/update-cache.ts +78 -0
- package/{dist → src}/services/version-check.js +15 -14
- package/src/services/version-check.ts +122 -0
- package/src/types/index.js +1 -0
- package/src/types/index.ts +141 -0
- package/src/ui/App.js +213 -0
- package/src/ui/App.tsx +359 -0
- package/src/ui/components/CategoryHeader.js +9 -0
- package/src/ui/components/CategoryHeader.tsx +41 -0
- package/{dist → src}/ui/components/ScrollableList.js +19 -6
- package/src/ui/components/ScrollableList.tsx +98 -0
- package/src/ui/components/SearchInput.js +19 -0
- package/src/ui/components/SearchInput.tsx +56 -0
- package/src/ui/components/StyledText.js +39 -0
- package/src/ui/components/StyledText.tsx +70 -0
- package/src/ui/components/TabBar.js +38 -0
- package/src/ui/components/TabBar.tsx +88 -0
- package/src/ui/components/layout/Panel.js +6 -0
- package/src/ui/components/layout/Panel.tsx +62 -0
- package/src/ui/components/layout/ProgressBar.js +14 -0
- package/src/ui/components/layout/ProgressBar.tsx +47 -0
- package/src/ui/components/layout/ScopeTabs.js +6 -0
- package/src/ui/components/layout/ScopeTabs.tsx +53 -0
- package/src/ui/components/layout/ScreenLayout.js +21 -0
- package/src/ui/components/layout/ScreenLayout.tsx +147 -0
- package/src/ui/components/layout/index.js +4 -0
- package/src/ui/components/layout/index.ts +4 -0
- package/src/ui/components/modals/ConfirmModal.js +14 -0
- package/src/ui/components/modals/ConfirmModal.tsx +59 -0
- package/src/ui/components/modals/InputModal.js +16 -0
- package/src/ui/components/modals/InputModal.tsx +68 -0
- package/src/ui/components/modals/LoadingModal.js +14 -0
- package/src/ui/components/modals/LoadingModal.tsx +40 -0
- package/src/ui/components/modals/MessageModal.js +16 -0
- package/src/ui/components/modals/MessageModal.tsx +64 -0
- package/src/ui/components/modals/ModalContainer.js +56 -0
- package/src/ui/components/modals/ModalContainer.tsx +104 -0
- package/src/ui/components/modals/SelectModal.js +26 -0
- package/src/ui/components/modals/SelectModal.tsx +82 -0
- package/src/ui/components/modals/index.js +6 -0
- package/src/ui/components/modals/index.ts +6 -0
- package/src/ui/hooks/index.js +3 -0
- package/src/ui/hooks/index.ts +3 -0
- package/{dist → src}/ui/hooks/useAsyncData.js +21 -22
- package/src/ui/hooks/useAsyncData.ts +127 -0
- package/src/ui/hooks/useKeyboard.js +13 -0
- package/src/ui/hooks/useKeyboard.ts +26 -0
- package/src/ui/hooks/useKeyboardHandler.js +39 -0
- package/src/ui/hooks/useKeyboardHandler.ts +63 -0
- package/{dist → src}/ui/screens/CliToolsScreen.js +60 -54
- package/src/ui/screens/CliToolsScreen.tsx +468 -0
- package/src/ui/screens/EnvVarsScreen.js +154 -0
- package/src/ui/screens/EnvVarsScreen.tsx +269 -0
- package/{dist → src}/ui/screens/McpRegistryScreen.js +56 -55
- package/src/ui/screens/McpRegistryScreen.tsx +331 -0
- package/{dist → src}/ui/screens/McpScreen.js +46 -47
- package/src/ui/screens/McpScreen.tsx +392 -0
- package/src/ui/screens/ModelSelectorScreen.js +292 -0
- package/src/ui/screens/ModelSelectorScreen.tsx +441 -0
- package/{dist → src}/ui/screens/PluginsScreen.js +305 -293
- package/src/ui/screens/PluginsScreen.tsx +1231 -0
- package/src/ui/screens/StatusLineScreen.js +200 -0
- package/src/ui/screens/StatusLineScreen.tsx +411 -0
- package/src/ui/screens/index.js +7 -0
- package/src/ui/screens/index.ts +7 -0
- package/src/ui/state/AnimationContext.js +34 -0
- package/src/ui/state/AnimationContext.tsx +76 -0
- package/{dist → src}/ui/state/AppContext.js +31 -32
- package/src/ui/state/AppContext.tsx +235 -0
- package/{dist → src}/ui/state/DimensionsContext.js +16 -17
- package/src/ui/state/DimensionsContext.tsx +144 -0
- package/{dist → src}/ui/state/reducer.js +89 -90
- package/src/ui/state/reducer.ts +467 -0
- package/src/ui/state/types.js +1 -0
- package/src/ui/state/types.ts +273 -0
- package/{dist → src}/utils/command-utils.js +3 -4
- package/src/utils/command-utils.ts +20 -0
- package/{dist → src}/utils/fuzzy-search.js +2 -3
- package/src/utils/fuzzy-search.ts +138 -0
- package/{dist → src}/utils/string-utils.js +6 -6
- package/src/utils/string-utils.ts +88 -0
- package/dist/data/cli-tools.d.ts +0 -13
- package/dist/data/cli-tools.d.ts.map +0 -1
- package/dist/data/cli-tools.js +0 -124
- package/dist/data/cli-tools.js.map +0 -1
- package/dist/data/marketplaces.d.ts +0 -6
- package/dist/data/marketplaces.d.ts.map +0 -1
- package/dist/data/marketplaces.js.map +0 -1
- package/dist/data/mcp-servers.d.ts +0 -8
- package/dist/data/mcp-servers.d.ts.map +0 -1
- package/dist/data/mcp-servers.js +0 -503
- package/dist/data/mcp-servers.js.map +0 -1
- package/dist/data/statuslines.d.ts +0 -10
- package/dist/data/statuslines.d.ts.map +0 -1
- package/dist/data/statuslines.js +0 -160
- package/dist/data/statuslines.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -90
- package/dist/index.js.map +0 -1
- package/dist/main.d.ts +0 -3
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/prerunner/index.d.ts +0 -7
- package/dist/prerunner/index.d.ts.map +0 -1
- package/dist/prerunner/index.js.map +0 -1
- package/dist/services/claude-runner.d.ts +0 -7
- package/dist/services/claude-runner.d.ts.map +0 -1
- package/dist/services/claude-runner.js.map +0 -1
- package/dist/services/claude-settings.d.ts +0 -73
- package/dist/services/claude-settings.d.ts.map +0 -1
- package/dist/services/claude-settings.js.map +0 -1
- package/dist/services/local-marketplace.d.ts +0 -111
- package/dist/services/local-marketplace.d.ts.map +0 -1
- package/dist/services/local-marketplace.js +0 -599
- package/dist/services/local-marketplace.js.map +0 -1
- package/dist/services/mcp-registry.d.ts +0 -10
- package/dist/services/mcp-registry.d.ts.map +0 -1
- package/dist/services/mcp-registry.js.map +0 -1
- package/dist/services/plugin-manager.d.ts +0 -65
- package/dist/services/plugin-manager.d.ts.map +0 -1
- package/dist/services/plugin-manager.js.map +0 -1
- package/dist/services/plugin-mcp-config.d.ts +0 -52
- package/dist/services/plugin-mcp-config.d.ts.map +0 -1
- package/dist/services/plugin-mcp-config.js.map +0 -1
- package/dist/services/update-cache.d.ts +0 -21
- package/dist/services/update-cache.d.ts.map +0 -1
- package/dist/services/update-cache.js.map +0 -1
- package/dist/services/version-check.d.ts +0 -20
- package/dist/services/version-check.d.ts.map +0 -1
- package/dist/services/version-check.js.map +0 -1
- package/dist/types/index.d.ts +0 -105
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/ui/InkApp.d.ts +0 -5
- package/dist/ui/InkApp.d.ts.map +0 -1
- package/dist/ui/InkApp.js +0 -188
- package/dist/ui/InkApp.js.map +0 -1
- package/dist/ui/components/CategoryHeader.d.ts +0 -16
- package/dist/ui/components/CategoryHeader.d.ts.map +0 -1
- package/dist/ui/components/CategoryHeader.js +0 -11
- package/dist/ui/components/CategoryHeader.js.map +0 -1
- package/dist/ui/components/ScrollableList.d.ts +0 -16
- package/dist/ui/components/ScrollableList.d.ts.map +0 -1
- package/dist/ui/components/ScrollableList.js.map +0 -1
- package/dist/ui/components/SearchInput.d.ts +0 -18
- package/dist/ui/components/SearchInput.d.ts.map +0 -1
- package/dist/ui/components/SearchInput.js +0 -30
- package/dist/ui/components/SearchInput.js.map +0 -1
- package/dist/ui/components/TabBar.d.ts +0 -8
- package/dist/ui/components/TabBar.d.ts.map +0 -1
- package/dist/ui/components/TabBar.js +0 -18
- package/dist/ui/components/TabBar.js.map +0 -1
- package/dist/ui/components/layout/Footer.d.ts +0 -14
- package/dist/ui/components/layout/Footer.d.ts.map +0 -1
- package/dist/ui/components/layout/Footer.js +0 -23
- package/dist/ui/components/layout/Footer.js.map +0 -1
- package/dist/ui/components/layout/Header.d.ts +0 -4
- package/dist/ui/components/layout/Header.d.ts.map +0 -1
- package/dist/ui/components/layout/Header.js +0 -25
- package/dist/ui/components/layout/Header.js.map +0 -1
- package/dist/ui/components/layout/Panel.d.ts +0 -22
- package/dist/ui/components/layout/Panel.d.ts.map +0 -1
- package/dist/ui/components/layout/Panel.js +0 -8
- package/dist/ui/components/layout/Panel.js.map +0 -1
- package/dist/ui/components/layout/ProgressBar.d.ts +0 -12
- package/dist/ui/components/layout/ProgressBar.d.ts.map +0 -1
- package/dist/ui/components/layout/ProgressBar.js +0 -16
- package/dist/ui/components/layout/ProgressBar.js.map +0 -1
- package/dist/ui/components/layout/ScopeTabs.d.ts +0 -12
- package/dist/ui/components/layout/ScopeTabs.d.ts.map +0 -1
- package/dist/ui/components/layout/ScopeTabs.js +0 -8
- package/dist/ui/components/layout/ScopeTabs.js.map +0 -1
- package/dist/ui/components/layout/ScreenLayout.d.ts +0 -30
- package/dist/ui/components/layout/ScreenLayout.d.ts.map +0 -1
- package/dist/ui/components/layout/ScreenLayout.js +0 -23
- package/dist/ui/components/layout/ScreenLayout.js.map +0 -1
- package/dist/ui/components/layout/index.d.ts +0 -7
- package/dist/ui/components/layout/index.d.ts.map +0 -1
- package/dist/ui/components/layout/index.js +0 -7
- package/dist/ui/components/layout/index.js.map +0 -1
- package/dist/ui/components/modals/ConfirmModal.d.ts +0 -14
- package/dist/ui/components/modals/ConfirmModal.d.ts.map +0 -1
- package/dist/ui/components/modals/ConfirmModal.js +0 -15
- package/dist/ui/components/modals/ConfirmModal.js.map +0 -1
- package/dist/ui/components/modals/InputModal.d.ts +0 -16
- package/dist/ui/components/modals/InputModal.d.ts.map +0 -1
- package/dist/ui/components/modals/InputModal.js +0 -23
- package/dist/ui/components/modals/InputModal.js.map +0 -1
- package/dist/ui/components/modals/LoadingModal.d.ts +0 -8
- package/dist/ui/components/modals/LoadingModal.d.ts.map +0 -1
- package/dist/ui/components/modals/LoadingModal.js +0 -8
- package/dist/ui/components/modals/LoadingModal.js.map +0 -1
- package/dist/ui/components/modals/MessageModal.d.ts +0 -14
- package/dist/ui/components/modals/MessageModal.d.ts.map +0 -1
- package/dist/ui/components/modals/MessageModal.js +0 -17
- package/dist/ui/components/modals/MessageModal.js.map +0 -1
- package/dist/ui/components/modals/ModalContainer.d.ts +0 -7
- package/dist/ui/components/modals/ModalContainer.d.ts.map +0 -1
- package/dist/ui/components/modals/ModalContainer.js +0 -38
- package/dist/ui/components/modals/ModalContainer.js.map +0 -1
- package/dist/ui/components/modals/SelectModal.d.ts +0 -17
- package/dist/ui/components/modals/SelectModal.d.ts.map +0 -1
- package/dist/ui/components/modals/SelectModal.js +0 -33
- package/dist/ui/components/modals/SelectModal.js.map +0 -1
- package/dist/ui/components/modals/index.d.ts +0 -7
- package/dist/ui/components/modals/index.d.ts.map +0 -1
- package/dist/ui/components/modals/index.js +0 -7
- package/dist/ui/components/modals/index.js.map +0 -1
- package/dist/ui/hooks/index.d.ts +0 -3
- package/dist/ui/hooks/index.d.ts.map +0 -1
- package/dist/ui/hooks/index.js +0 -3
- package/dist/ui/hooks/index.js.map +0 -1
- package/dist/ui/hooks/useAsyncData.d.ts +0 -40
- package/dist/ui/hooks/useAsyncData.d.ts.map +0 -1
- package/dist/ui/hooks/useAsyncData.js.map +0 -1
- package/dist/ui/hooks/useKeyboardNavigation.d.ts +0 -27
- package/dist/ui/hooks/useKeyboardNavigation.d.ts.map +0 -1
- package/dist/ui/hooks/useKeyboardNavigation.js +0 -82
- package/dist/ui/hooks/useKeyboardNavigation.js.map +0 -1
- package/dist/ui/screens/CliToolsScreen.d.ts +0 -4
- package/dist/ui/screens/CliToolsScreen.d.ts.map +0 -1
- package/dist/ui/screens/CliToolsScreen.js.map +0 -1
- package/dist/ui/screens/EnvVarsScreen.d.ts +0 -4
- package/dist/ui/screens/EnvVarsScreen.d.ts.map +0 -1
- package/dist/ui/screens/EnvVarsScreen.js +0 -145
- package/dist/ui/screens/EnvVarsScreen.js.map +0 -1
- package/dist/ui/screens/McpRegistryScreen.d.ts +0 -4
- package/dist/ui/screens/McpRegistryScreen.d.ts.map +0 -1
- package/dist/ui/screens/McpRegistryScreen.js.map +0 -1
- package/dist/ui/screens/McpScreen.d.ts +0 -4
- package/dist/ui/screens/McpScreen.d.ts.map +0 -1
- package/dist/ui/screens/McpScreen.js.map +0 -1
- package/dist/ui/screens/ModelSelectorScreen.d.ts +0 -4
- package/dist/ui/screens/ModelSelectorScreen.d.ts.map +0 -1
- package/dist/ui/screens/ModelSelectorScreen.js +0 -143
- package/dist/ui/screens/ModelSelectorScreen.js.map +0 -1
- package/dist/ui/screens/PluginsScreen.d.ts +0 -4
- package/dist/ui/screens/PluginsScreen.d.ts.map +0 -1
- package/dist/ui/screens/PluginsScreen.js.map +0 -1
- package/dist/ui/screens/StatusLineScreen.d.ts +0 -4
- package/dist/ui/screens/StatusLineScreen.d.ts.map +0 -1
- package/dist/ui/screens/StatusLineScreen.js +0 -197
- package/dist/ui/screens/StatusLineScreen.js.map +0 -1
- package/dist/ui/screens/index.d.ts +0 -8
- package/dist/ui/screens/index.d.ts.map +0 -1
- package/dist/ui/screens/index.js +0 -8
- package/dist/ui/screens/index.js.map +0 -1
- package/dist/ui/state/AppContext.d.ts +0 -40
- package/dist/ui/state/AppContext.d.ts.map +0 -1
- package/dist/ui/state/AppContext.js.map +0 -1
- package/dist/ui/state/DimensionsContext.d.ts +0 -27
- package/dist/ui/state/DimensionsContext.d.ts.map +0 -1
- package/dist/ui/state/DimensionsContext.js.map +0 -1
- package/dist/ui/state/reducer.d.ts +0 -4
- package/dist/ui/state/reducer.d.ts.map +0 -1
- package/dist/ui/state/reducer.js.map +0 -1
- package/dist/ui/state/types.d.ts +0 -266
- package/dist/ui/state/types.d.ts.map +0 -1
- package/dist/ui/state/types.js +0 -2
- package/dist/ui/state/types.js.map +0 -1
- package/dist/utils/command-utils.d.ts +0 -8
- package/dist/utils/command-utils.d.ts.map +0 -1
- package/dist/utils/command-utils.js.map +0 -1
- package/dist/utils/fuzzy-search.d.ts +0 -33
- package/dist/utils/fuzzy-search.d.ts.map +0 -1
- package/dist/utils/fuzzy-search.js.map +0 -1
- package/dist/utils/string-utils.d.ts +0 -24
- package/dist/utils/string-utils.d.ts.map +0 -1
- package/dist/utils/string-utils.js.map +0 -1
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useCallback, useMemo } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { ScreenLayout } from
|
|
7
|
-
import { CategoryHeader } from
|
|
8
|
-
import { ScrollableList } from
|
|
9
|
-
import { fuzzyFilter, highlightMatches } from
|
|
10
|
-
import { getAllMarketplaces } from
|
|
11
|
-
import { getAvailablePlugins, refreshAllMarketplaces, clearMarketplaceCache, saveInstalledPluginVersion, removeInstalledPluginVersion, getLocalMarketplacesInfo, } from
|
|
12
|
-
import {
|
|
13
|
-
import { getPluginEnvRequirements, getPluginSourcePath, } from
|
|
14
|
-
import { cloneMarketplace, deleteMarketplace, addToKnownMarketplaces, removeFromKnownMarketplaces, } from '../../services/local-marketplace.js';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { useEffect, useCallback, useMemo } from "react";
|
|
3
|
+
import { useApp, useModal, useProgress } from "../state/AppContext.js";
|
|
4
|
+
import { useDimensions } from "../state/DimensionsContext.js";
|
|
5
|
+
import { useKeyboard } from "../hooks/useKeyboard.js";
|
|
6
|
+
import { ScreenLayout } from "../components/layout/index.js";
|
|
7
|
+
import { CategoryHeader } from "../components/CategoryHeader.js";
|
|
8
|
+
import { ScrollableList } from "../components/ScrollableList.js";
|
|
9
|
+
import { fuzzyFilter, highlightMatches } from "../../utils/fuzzy-search.js";
|
|
10
|
+
import { getAllMarketplaces } from "../../data/marketplaces.js";
|
|
11
|
+
import { getAvailablePlugins, refreshAllMarketplaces, clearMarketplaceCache, saveInstalledPluginVersion, removeInstalledPluginVersion, getLocalMarketplacesInfo, } from "../../services/plugin-manager.js";
|
|
12
|
+
import { enablePlugin, enableGlobalPlugin, enableLocalPlugin, saveGlobalInstalledPluginVersion, removeGlobalInstalledPluginVersion, saveLocalInstalledPluginVersion, removeLocalInstalledPluginVersion, setMcpEnvVar, getMcpEnvVars, } from "../../services/claude-settings.js";
|
|
13
|
+
import { getPluginEnvRequirements, getPluginSourcePath, } from "../../services/plugin-mcp-config.js";
|
|
15
14
|
export function PluginsScreen() {
|
|
16
15
|
const { state, dispatch } = useApp();
|
|
17
16
|
const { plugins: pluginsState } = state;
|
|
18
17
|
const modal = useModal();
|
|
19
18
|
const progress = useProgress();
|
|
20
19
|
const dimensions = useDimensions();
|
|
21
|
-
const isSearchActive = state.isSearching &&
|
|
20
|
+
const isSearchActive = state.isSearching &&
|
|
21
|
+
state.currentRoute.screen === "plugins" &&
|
|
22
|
+
!state.modal;
|
|
22
23
|
// Fetch data (always fetches all scopes)
|
|
23
24
|
const fetchData = useCallback(async () => {
|
|
24
|
-
dispatch({ type:
|
|
25
|
+
dispatch({ type: "PLUGINS_DATA_LOADING" });
|
|
25
26
|
try {
|
|
26
27
|
const localMarketplaces = await getLocalMarketplacesInfo();
|
|
27
28
|
const allMarketplaces = getAllMarketplaces(localMarketplaces);
|
|
28
29
|
// Always use getAvailablePlugins which fetches all scope data
|
|
29
30
|
const pluginData = await getAvailablePlugins(state.projectPath);
|
|
30
31
|
dispatch({
|
|
31
|
-
type:
|
|
32
|
+
type: "PLUGINS_DATA_SUCCESS",
|
|
32
33
|
marketplaces: allMarketplaces,
|
|
33
34
|
plugins: pluginData,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
38
|
dispatch({
|
|
38
|
-
type:
|
|
39
|
+
type: "PLUGINS_DATA_ERROR",
|
|
39
40
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
40
41
|
});
|
|
41
42
|
}
|
|
@@ -46,7 +47,8 @@ export function PluginsScreen() {
|
|
|
46
47
|
}, [fetchData, state.dataRefreshVersion]);
|
|
47
48
|
// Build list items (categories + plugins)
|
|
48
49
|
const allItems = useMemo(() => {
|
|
49
|
-
if (pluginsState.marketplaces.status !==
|
|
50
|
+
if (pluginsState.marketplaces.status !== "success" ||
|
|
51
|
+
pluginsState.plugins.status !== "success") {
|
|
50
52
|
return [];
|
|
51
53
|
}
|
|
52
54
|
const marketplaces = pluginsState.marketplaces.data;
|
|
@@ -60,8 +62,8 @@ export function PluginsScreen() {
|
|
|
60
62
|
}
|
|
61
63
|
// Sort marketplaces: deprecated ones go to the bottom
|
|
62
64
|
const sortedMarketplaces = [...marketplaces].sort((a, b) => {
|
|
63
|
-
const aDeprecated = a.name ===
|
|
64
|
-
const bDeprecated = b.name ===
|
|
65
|
+
const aDeprecated = a.name === "claude-code-plugins" ? 1 : 0;
|
|
66
|
+
const bDeprecated = b.name === "claude-code-plugins" ? 1 : 0;
|
|
65
67
|
return aDeprecated - bDeprecated;
|
|
66
68
|
});
|
|
67
69
|
const items = [];
|
|
@@ -73,7 +75,7 @@ export function PluginsScreen() {
|
|
|
73
75
|
// Category header (marketplace)
|
|
74
76
|
items.push({
|
|
75
77
|
id: `mp:${marketplace.name}`,
|
|
76
|
-
type:
|
|
78
|
+
type: "category",
|
|
77
79
|
label: marketplace.displayName,
|
|
78
80
|
marketplace,
|
|
79
81
|
marketplaceEnabled: isEnabled,
|
|
@@ -85,7 +87,7 @@ export function PluginsScreen() {
|
|
|
85
87
|
for (const plugin of marketplacePlugins) {
|
|
86
88
|
items.push({
|
|
87
89
|
id: `pl:${plugin.id}`,
|
|
88
|
-
type:
|
|
90
|
+
type: "plugin",
|
|
89
91
|
label: plugin.name,
|
|
90
92
|
plugin,
|
|
91
93
|
});
|
|
@@ -93,15 +95,19 @@ export function PluginsScreen() {
|
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
return items;
|
|
96
|
-
}, [
|
|
98
|
+
}, [
|
|
99
|
+
pluginsState.marketplaces,
|
|
100
|
+
pluginsState.plugins,
|
|
101
|
+
pluginsState.collapsedMarketplaces,
|
|
102
|
+
]);
|
|
97
103
|
// Filter items by search query
|
|
98
104
|
const filteredItems = useMemo(() => {
|
|
99
105
|
const query = pluginsState.searchQuery.trim();
|
|
100
106
|
if (!query)
|
|
101
107
|
return allItems;
|
|
102
108
|
// Only search plugins, not categories
|
|
103
|
-
const pluginItems = allItems.filter(item => item.type ===
|
|
104
|
-
const fuzzyResults = fuzzyFilter(pluginItems, query, item => item.label);
|
|
109
|
+
const pluginItems = allItems.filter((item) => item.type === "plugin");
|
|
110
|
+
const fuzzyResults = fuzzyFilter(pluginItems, query, (item) => item.label);
|
|
105
111
|
// Include parent categories for matched plugins
|
|
106
112
|
const matchedMarketplaces = new Set();
|
|
107
113
|
for (const result of fuzzyResults) {
|
|
@@ -112,7 +118,7 @@ export function PluginsScreen() {
|
|
|
112
118
|
const result = [];
|
|
113
119
|
let currentMarketplace = null;
|
|
114
120
|
for (const item of allItems) {
|
|
115
|
-
if (item.type ===
|
|
121
|
+
if (item.type === "category" && item.marketplace) {
|
|
116
122
|
if (matchedMarketplaces.has(item.marketplace.name)) {
|
|
117
123
|
result.push(item);
|
|
118
124
|
currentMarketplace = item.marketplace.name;
|
|
@@ -121,10 +127,10 @@ export function PluginsScreen() {
|
|
|
121
127
|
currentMarketplace = null;
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
|
-
else if (item.type ===
|
|
130
|
+
else if (item.type === "plugin" && item.plugin) {
|
|
125
131
|
if (currentMarketplace === item.plugin.marketplace) {
|
|
126
132
|
// Check if this plugin matched
|
|
127
|
-
const matched = fuzzyResults.find(r => r.item.id === item.id);
|
|
133
|
+
const matched = fuzzyResults.find((r) => r.item.id === item.id);
|
|
128
134
|
if (matched) {
|
|
129
135
|
result.push({ ...item, _matches: matched.matches });
|
|
130
136
|
}
|
|
@@ -135,158 +141,159 @@ export function PluginsScreen() {
|
|
|
135
141
|
}, [allItems, pluginsState.searchQuery]);
|
|
136
142
|
// Only selectable items (plugins, not categories)
|
|
137
143
|
const selectableItems = useMemo(() => {
|
|
138
|
-
return filteredItems.filter(item => item.type ===
|
|
144
|
+
return filteredItems.filter((item) => item.type === "plugin" || item.type === "category");
|
|
139
145
|
}, [filteredItems]);
|
|
140
146
|
// Keyboard handling
|
|
141
|
-
|
|
147
|
+
useKeyboard((event) => {
|
|
142
148
|
// Handle search mode
|
|
143
149
|
if (isSearchActive) {
|
|
144
|
-
if (
|
|
145
|
-
dispatch({ type:
|
|
146
|
-
dispatch({ type:
|
|
150
|
+
if (event.name === "escape") {
|
|
151
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
152
|
+
dispatch({ type: "PLUGINS_SET_SEARCH", query: "" });
|
|
147
153
|
}
|
|
148
|
-
else if (
|
|
149
|
-
dispatch({ type:
|
|
154
|
+
else if (event.name === "enter") {
|
|
155
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
150
156
|
// Keep the search query, just exit search mode
|
|
151
157
|
}
|
|
152
|
-
else if (
|
|
153
|
-
dispatch({
|
|
158
|
+
else if (event.name === "backspace" || event.name === "delete") {
|
|
159
|
+
dispatch({
|
|
160
|
+
type: "PLUGINS_SET_SEARCH",
|
|
161
|
+
query: pluginsState.searchQuery.slice(0, -1),
|
|
162
|
+
});
|
|
154
163
|
}
|
|
155
|
-
else if (
|
|
156
|
-
dispatch({
|
|
164
|
+
else if (event.name.length === 1 && !event.ctrl && !event.meta) {
|
|
165
|
+
dispatch({
|
|
166
|
+
type: "PLUGINS_SET_SEARCH",
|
|
167
|
+
query: pluginsState.searchQuery + event.name,
|
|
168
|
+
});
|
|
157
169
|
}
|
|
158
170
|
return;
|
|
159
171
|
}
|
|
160
172
|
if (state.modal)
|
|
161
173
|
return;
|
|
162
174
|
// Start search with /
|
|
163
|
-
if (
|
|
164
|
-
dispatch({ type:
|
|
175
|
+
if (event.name === "/") {
|
|
176
|
+
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
165
177
|
return;
|
|
166
178
|
}
|
|
167
179
|
// Navigation
|
|
168
|
-
if (
|
|
180
|
+
if (event.name === "up" || event.name === "k") {
|
|
169
181
|
const newIndex = Math.max(0, pluginsState.selectedIndex - 1);
|
|
170
|
-
dispatch({ type:
|
|
182
|
+
dispatch({ type: "PLUGINS_SELECT", index: newIndex });
|
|
171
183
|
}
|
|
172
|
-
else if (
|
|
184
|
+
else if (event.name === "down" || event.name === "j") {
|
|
173
185
|
const newIndex = Math.min(selectableItems.length - 1, pluginsState.selectedIndex + 1);
|
|
174
|
-
dispatch({ type:
|
|
186
|
+
dispatch({ type: "PLUGINS_SELECT", index: newIndex });
|
|
175
187
|
}
|
|
176
188
|
// Collapse/expand marketplace
|
|
177
|
-
else if ((
|
|
189
|
+
else if ((event.name === "left" || event.name === "right" || event.name === "<" || event.name === ">") &&
|
|
190
|
+
selectableItems[pluginsState.selectedIndex]?.marketplace) {
|
|
178
191
|
const item = selectableItems[pluginsState.selectedIndex];
|
|
179
192
|
if (item?.marketplace) {
|
|
180
|
-
dispatch({
|
|
193
|
+
dispatch({
|
|
194
|
+
type: "PLUGINS_TOGGLE_MARKETPLACE",
|
|
195
|
+
name: item.marketplace.name,
|
|
196
|
+
});
|
|
181
197
|
}
|
|
182
198
|
}
|
|
183
199
|
// Refresh
|
|
184
|
-
else if (
|
|
200
|
+
else if (event.name === "r") {
|
|
185
201
|
handleRefresh();
|
|
186
202
|
}
|
|
187
|
-
// New marketplace
|
|
188
|
-
else if (
|
|
189
|
-
|
|
203
|
+
// New marketplace (show instructions)
|
|
204
|
+
else if (event.name === "n") {
|
|
205
|
+
handleShowAddMarketplaceInstructions();
|
|
206
|
+
}
|
|
207
|
+
// Team config help
|
|
208
|
+
else if (event.name === "t") {
|
|
209
|
+
handleShowTeamConfigHelp();
|
|
190
210
|
}
|
|
191
211
|
// Scope-specific toggle shortcuts (u/p/l)
|
|
192
|
-
else if (
|
|
193
|
-
handleScopeToggle(
|
|
212
|
+
else if (event.name === "u") {
|
|
213
|
+
handleScopeToggle("user");
|
|
194
214
|
}
|
|
195
|
-
else if (
|
|
196
|
-
handleScopeToggle(
|
|
215
|
+
else if (event.name === "p") {
|
|
216
|
+
handleScopeToggle("project");
|
|
197
217
|
}
|
|
198
|
-
else if (
|
|
199
|
-
handleScopeToggle(
|
|
218
|
+
else if (event.name === "l") {
|
|
219
|
+
handleScopeToggle("local");
|
|
200
220
|
}
|
|
201
221
|
// Update plugin (Shift+U)
|
|
202
|
-
else if (
|
|
222
|
+
else if (event.name === "U") {
|
|
203
223
|
handleUpdate();
|
|
204
224
|
}
|
|
205
225
|
// Update all
|
|
206
|
-
else if (
|
|
226
|
+
else if (event.name === "a") {
|
|
207
227
|
handleUpdateAll();
|
|
208
228
|
}
|
|
209
229
|
// Delete/uninstall
|
|
210
|
-
else if (
|
|
230
|
+
else if (event.name === "d") {
|
|
211
231
|
handleUninstall();
|
|
212
232
|
}
|
|
213
233
|
// Enter for selection
|
|
214
|
-
else if (
|
|
234
|
+
else if (event.name === "enter") {
|
|
215
235
|
handleSelect();
|
|
216
236
|
}
|
|
217
237
|
});
|
|
218
238
|
// Handle actions
|
|
219
239
|
const handleRefresh = async () => {
|
|
220
|
-
progress.show(
|
|
240
|
+
progress.show("Refreshing cache...");
|
|
221
241
|
try {
|
|
222
242
|
const result = await refreshAllMarketplaces((p) => {
|
|
223
|
-
progress.show(
|
|
243
|
+
progress.show(`${p.name}`, p.current, p.total);
|
|
224
244
|
});
|
|
225
245
|
clearMarketplaceCache();
|
|
226
246
|
progress.hide();
|
|
227
|
-
// Build
|
|
228
|
-
let message =
|
|
247
|
+
// Build message
|
|
248
|
+
let message = "Cache refreshed.\n\n" +
|
|
249
|
+
"To update marketplaces from GitHub, run in Claude Code:\n" +
|
|
250
|
+
" /plugin marketplace update\n\n" +
|
|
251
|
+
"Then refresh claudeup again with 'r'.";
|
|
229
252
|
if (result.repair.length > 0) {
|
|
230
253
|
const totalRepaired = result.repair.reduce((sum, r) => sum + r.repaired.length, 0);
|
|
231
254
|
message += `\n\nAuto-repaired ${totalRepaired} plugin(s) with missing agents/commands.`;
|
|
232
|
-
for (const mp of result.repair) {
|
|
233
|
-
for (const plugin of mp.repaired) {
|
|
234
|
-
const parts = [];
|
|
235
|
-
if (plugin.added.agents.length > 0)
|
|
236
|
-
parts.push(`${plugin.added.agents.length} agents`);
|
|
237
|
-
if (plugin.added.commands.length > 0)
|
|
238
|
-
parts.push(`${plugin.added.commands.length} commands`);
|
|
239
|
-
if (plugin.added.skills.length > 0)
|
|
240
|
-
parts.push(`${plugin.added.skills.length} skills`);
|
|
241
|
-
message += `\n • ${plugin.pluginName}: added ${parts.join(', ')}`;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
255
|
}
|
|
245
|
-
await modal.message(
|
|
256
|
+
await modal.message("Refreshed", message, "success");
|
|
246
257
|
fetchData();
|
|
247
258
|
}
|
|
248
259
|
catch (error) {
|
|
249
260
|
progress.hide();
|
|
250
|
-
await modal.message(
|
|
261
|
+
await modal.message("Error", `Refresh failed: ${error}`, "error");
|
|
251
262
|
}
|
|
252
263
|
};
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
catch (error) {
|
|
287
|
-
progress.hide();
|
|
288
|
-
await modal.message('Error', `Failed to add marketplace: ${error}`, 'error');
|
|
289
|
-
}
|
|
264
|
+
const handleShowAddMarketplaceInstructions = async () => {
|
|
265
|
+
await modal.message("Add Marketplace", "To add a marketplace, run this command in your terminal:\n\n" +
|
|
266
|
+
" claude marketplace add owner/repo\n\n" +
|
|
267
|
+
"Examples:\n" +
|
|
268
|
+
" claude marketplace add MadAppGang/claude-code\n" +
|
|
269
|
+
" claude marketplace add anthropics/claude-plugins-official\n\n" +
|
|
270
|
+
"Auto-update is enabled by default for new marketplaces.\n\n" +
|
|
271
|
+
"After adding, refresh claudeup with 'r' to see the new marketplace.", "info");
|
|
272
|
+
};
|
|
273
|
+
const handleShowTeamConfigHelp = async () => {
|
|
274
|
+
const helpText = "TEAM CONFIGURATION FOR MARKETPLACES\n\n" +
|
|
275
|
+
"To configure marketplaces for your entire team:\n\n" +
|
|
276
|
+
"1. Add to .claude/settings.json (committed to git):\n\n" +
|
|
277
|
+
" {\n" +
|
|
278
|
+
' "extraKnownMarketplaces": {\n' +
|
|
279
|
+
' "company-tools": {\n' +
|
|
280
|
+
' "source": {\n' +
|
|
281
|
+
' "source": "github",\n' +
|
|
282
|
+
' "repo": "your-org/claude-plugins"\n' +
|
|
283
|
+
" }\n" +
|
|
284
|
+
" }\n" +
|
|
285
|
+
" },\n" +
|
|
286
|
+
' "enabledPlugins": {\n' +
|
|
287
|
+
' "code-formatter@company-tools": true\n' +
|
|
288
|
+
" }\n" +
|
|
289
|
+
" }\n\n" +
|
|
290
|
+
"2. Team members get prompted to install when they trust the folder\n\n" +
|
|
291
|
+
"3. Marketplaces are GLOBAL ONLY (managed by Claude Code)\n" +
|
|
292
|
+
" - Not project-specific\n" +
|
|
293
|
+
" - All team members share the same marketplace cache\n\n" +
|
|
294
|
+
"NOTE: Individual plugin enablement is still project-specific.\n" +
|
|
295
|
+
'Use "Project" scope in claudeup to enable for the team.';
|
|
296
|
+
await modal.message("Team Configuration", helpText, "info");
|
|
290
297
|
};
|
|
291
298
|
/**
|
|
292
299
|
* Collect environment variables required by a plugin's MCP servers
|
|
@@ -304,14 +311,14 @@ export function PluginsScreen() {
|
|
|
304
311
|
return true; // No env vars needed
|
|
305
312
|
// Get existing env vars
|
|
306
313
|
const existingEnvVars = await getMcpEnvVars(state.projectPath);
|
|
307
|
-
const missingVars = requirements.filter(req => !existingEnvVars[req.name] && !process.env[req.name]);
|
|
314
|
+
const missingVars = requirements.filter((req) => !existingEnvVars[req.name] && !process.env[req.name]);
|
|
308
315
|
if (missingVars.length === 0)
|
|
309
316
|
return true; // All vars already configured
|
|
310
317
|
// Ask user if they want to configure MCP server env vars now
|
|
311
|
-
const serverNames = [...new Set(missingVars.map(v => v.serverName))];
|
|
312
|
-
const wantToConfigure = await modal.confirm(
|
|
318
|
+
const serverNames = [...new Set(missingVars.map((v) => v.serverName))];
|
|
319
|
+
const wantToConfigure = await modal.confirm("Configure MCP Servers?", `This plugin includes MCP servers (${serverNames.join(", ")}) that need ${missingVars.length} environment variable(s).\n\nConfigure now?`);
|
|
313
320
|
if (!wantToConfigure) {
|
|
314
|
-
await modal.message(
|
|
321
|
+
await modal.message("Skipped Configuration", "You can configure these variables later in the Environment Variables screen (press 4).", "info");
|
|
315
322
|
return true; // Still installed, just not configured
|
|
316
323
|
}
|
|
317
324
|
// Collect each missing env var
|
|
@@ -327,10 +334,10 @@ export function PluginsScreen() {
|
|
|
327
334
|
}
|
|
328
335
|
}
|
|
329
336
|
// Prompt for value
|
|
330
|
-
const value = await modal.input(`Configure ${req.serverName}`, `${req.label} (required):`,
|
|
337
|
+
const value = await modal.input(`Configure ${req.serverName}`, `${req.label} (required):`, "");
|
|
331
338
|
if (value === null) {
|
|
332
339
|
// User cancelled
|
|
333
|
-
await modal.message(
|
|
340
|
+
await modal.message("Configuration Incomplete", `Skipped remaining configuration.\nYou can configure these later in Environment Variables (press 4).`, "info");
|
|
334
341
|
return true; // Still installed
|
|
335
342
|
}
|
|
336
343
|
if (value) {
|
|
@@ -340,7 +347,7 @@ export function PluginsScreen() {
|
|
|
340
347
|
return true;
|
|
341
348
|
}
|
|
342
349
|
catch (error) {
|
|
343
|
-
console.error(
|
|
350
|
+
console.error("Error collecting plugin env vars:", error);
|
|
344
351
|
return true; // Don't block installation on config errors
|
|
345
352
|
}
|
|
346
353
|
};
|
|
@@ -348,72 +355,44 @@ export function PluginsScreen() {
|
|
|
348
355
|
const item = selectableItems[pluginsState.selectedIndex];
|
|
349
356
|
if (!item)
|
|
350
357
|
return;
|
|
351
|
-
if (item.type ===
|
|
358
|
+
if (item.type === "category" && item.marketplace) {
|
|
352
359
|
const mp = item.marketplace;
|
|
353
|
-
const isGlobal = pluginsState.scope === 'global';
|
|
354
360
|
if (item.marketplaceEnabled) {
|
|
355
361
|
const isCollapsed = pluginsState.collapsedMarketplaces.has(mp.name);
|
|
356
362
|
// If collapsed, expand first (even if no plugins - they might load)
|
|
357
363
|
if (isCollapsed) {
|
|
358
|
-
dispatch({ type:
|
|
364
|
+
dispatch({ type: "PLUGINS_TOGGLE_MARKETPLACE", name: mp.name });
|
|
359
365
|
}
|
|
360
366
|
else if (item.pluginCount && item.pluginCount > 0) {
|
|
361
367
|
// If expanded with plugins, collapse
|
|
362
|
-
dispatch({ type:
|
|
368
|
+
dispatch({ type: "PLUGINS_TOGGLE_MARKETPLACE", name: mp.name });
|
|
363
369
|
}
|
|
364
370
|
else {
|
|
365
|
-
// If expanded with no plugins,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
try {
|
|
370
|
-
if (isGlobal) {
|
|
371
|
-
await removeGlobalMarketplace(mp.name);
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
await removeMarketplace(mp.name, state.projectPath);
|
|
375
|
-
}
|
|
376
|
-
await deleteMarketplace(mp.name);
|
|
377
|
-
await removeFromKnownMarketplaces(mp.name);
|
|
378
|
-
clearMarketplaceCache();
|
|
379
|
-
modal.hideModal();
|
|
380
|
-
await modal.message('Removed', `${mp.displayName} removed.`, 'success');
|
|
381
|
-
fetchData();
|
|
382
|
-
}
|
|
383
|
-
catch (error) {
|
|
384
|
-
modal.hideModal();
|
|
385
|
-
await modal.message('Error', `Failed to remove: ${error}`, 'error');
|
|
386
|
-
}
|
|
387
|
-
}
|
|
371
|
+
// If expanded with no plugins, show removal instructions
|
|
372
|
+
await modal.message(`Remove ${mp.displayName}?`, `To remove this marketplace, run in Claude Code:\n\n` +
|
|
373
|
+
` /plugin marketplace remove ${mp.name}\n\n` +
|
|
374
|
+
`After removing, refresh claudeup with 'r' to update the display.`, "info");
|
|
388
375
|
}
|
|
389
376
|
}
|
|
390
377
|
else {
|
|
391
|
-
//
|
|
392
|
-
modal.
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
await addMarketplace(mp, state.projectPath);
|
|
399
|
-
}
|
|
400
|
-
modal.hideModal();
|
|
401
|
-
fetchData();
|
|
402
|
-
}
|
|
403
|
-
catch (error) {
|
|
404
|
-
modal.hideModal();
|
|
405
|
-
await modal.message('Error', `Failed to add: ${error}`, 'error');
|
|
406
|
-
}
|
|
378
|
+
// Show add marketplace instructions
|
|
379
|
+
await modal.message(`Add ${mp.displayName}?`, `To add this marketplace, run in your terminal:\n\n` +
|
|
380
|
+
` claude marketplace add ${mp.source.repo || mp.name}\n\n` +
|
|
381
|
+
`Auto-update is enabled by default.\n\n` +
|
|
382
|
+
`After adding, refresh claudeup with 'r' to see it.`, "info");
|
|
407
383
|
}
|
|
408
384
|
}
|
|
409
|
-
else if (item.type ===
|
|
385
|
+
else if (item.type === "plugin" && item.plugin) {
|
|
410
386
|
const plugin = item.plugin;
|
|
411
|
-
const latestVersion = plugin.version ||
|
|
387
|
+
const latestVersion = plugin.version || "0.0.0";
|
|
412
388
|
// Build scope options with status info
|
|
413
389
|
const buildScopeLabel = (name, scope, desc) => {
|
|
414
390
|
const installed = scope?.enabled;
|
|
415
391
|
const ver = scope?.version;
|
|
416
|
-
const hasUpdate = ver &&
|
|
392
|
+
const hasUpdate = ver &&
|
|
393
|
+
latestVersion &&
|
|
394
|
+
ver !== latestVersion &&
|
|
395
|
+
latestVersion !== "0.0.0";
|
|
417
396
|
let label = installed ? `● ${name}` : `○ ${name}`;
|
|
418
397
|
label += ` (${desc})`;
|
|
419
398
|
if (ver)
|
|
@@ -423,47 +402,65 @@ export function PluginsScreen() {
|
|
|
423
402
|
return label;
|
|
424
403
|
};
|
|
425
404
|
const scopeOptions = [
|
|
426
|
-
{
|
|
427
|
-
|
|
428
|
-
|
|
405
|
+
{
|
|
406
|
+
label: buildScopeLabel("User", plugin.userScope, "global"),
|
|
407
|
+
value: "user",
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
label: buildScopeLabel("Project", plugin.projectScope, "team"),
|
|
411
|
+
value: "project",
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
label: buildScopeLabel("Local", plugin.localScope, "private"),
|
|
415
|
+
value: "local",
|
|
416
|
+
},
|
|
429
417
|
];
|
|
430
418
|
const scopeValue = await modal.select(plugin.name, `Select scope to toggle:`, scopeOptions);
|
|
431
419
|
if (scopeValue === null)
|
|
432
420
|
return; // Cancelled
|
|
433
421
|
// Determine action based on selected scope's current state
|
|
434
|
-
const selectedScope = scopeValue ===
|
|
435
|
-
|
|
436
|
-
|
|
422
|
+
const selectedScope = scopeValue === "user"
|
|
423
|
+
? plugin.userScope
|
|
424
|
+
: scopeValue === "project"
|
|
425
|
+
? plugin.projectScope
|
|
426
|
+
: plugin.localScope;
|
|
437
427
|
const isInstalledInScope = selectedScope?.enabled;
|
|
438
428
|
const installedVersion = selectedScope?.version;
|
|
439
|
-
const scopeLabel = scopeValue ===
|
|
429
|
+
const scopeLabel = scopeValue === "user"
|
|
430
|
+
? "User"
|
|
431
|
+
: scopeValue === "project"
|
|
432
|
+
? "Project"
|
|
433
|
+
: "Local";
|
|
440
434
|
// Check if this scope has an update available
|
|
441
|
-
const hasUpdateInScope = isInstalledInScope &&
|
|
442
|
-
|
|
435
|
+
const hasUpdateInScope = isInstalledInScope &&
|
|
436
|
+
installedVersion &&
|
|
437
|
+
latestVersion !== "0.0.0" &&
|
|
443
438
|
installedVersion !== latestVersion;
|
|
444
439
|
// Determine action: update if available, otherwise toggle
|
|
445
440
|
let action;
|
|
446
441
|
if (isInstalledInScope && hasUpdateInScope) {
|
|
447
|
-
action =
|
|
442
|
+
action = "update";
|
|
448
443
|
}
|
|
449
444
|
else if (isInstalledInScope) {
|
|
450
|
-
action =
|
|
445
|
+
action = "uninstall";
|
|
451
446
|
}
|
|
452
447
|
else {
|
|
453
|
-
action =
|
|
448
|
+
action = "install";
|
|
454
449
|
}
|
|
455
|
-
const actionLabel = action ===
|
|
456
|
-
|
|
457
|
-
|
|
450
|
+
const actionLabel = action === "update"
|
|
451
|
+
? `Updating ${scopeLabel}`
|
|
452
|
+
: action === "install"
|
|
453
|
+
? `Installing to ${scopeLabel}`
|
|
454
|
+
: `Uninstalling from ${scopeLabel}`;
|
|
458
455
|
modal.loading(`${actionLabel}...`);
|
|
459
456
|
try {
|
|
460
|
-
if (action ===
|
|
457
|
+
if (action === "uninstall") {
|
|
461
458
|
// Uninstall from this scope
|
|
462
|
-
if (scopeValue ===
|
|
459
|
+
if (scopeValue === "user") {
|
|
463
460
|
await enableGlobalPlugin(plugin.id, false);
|
|
464
461
|
await removeGlobalInstalledPluginVersion(plugin.id);
|
|
465
462
|
}
|
|
466
|
-
else if (scopeValue ===
|
|
463
|
+
else if (scopeValue === "project") {
|
|
467
464
|
await enablePlugin(plugin.id, false, state.projectPath);
|
|
468
465
|
await removeInstalledPluginVersion(plugin.id, state.projectPath);
|
|
469
466
|
}
|
|
@@ -474,11 +471,11 @@ export function PluginsScreen() {
|
|
|
474
471
|
}
|
|
475
472
|
else {
|
|
476
473
|
// Install or update (both save the latest version)
|
|
477
|
-
if (scopeValue ===
|
|
474
|
+
if (scopeValue === "user") {
|
|
478
475
|
await enableGlobalPlugin(plugin.id, true);
|
|
479
476
|
await saveGlobalInstalledPluginVersion(plugin.id, latestVersion);
|
|
480
477
|
}
|
|
481
|
-
else if (scopeValue ===
|
|
478
|
+
else if (scopeValue === "project") {
|
|
482
479
|
await enablePlugin(plugin.id, true, state.projectPath);
|
|
483
480
|
await saveInstalledPluginVersion(plugin.id, latestVersion, state.projectPath);
|
|
484
481
|
}
|
|
@@ -487,31 +484,31 @@ export function PluginsScreen() {
|
|
|
487
484
|
await saveLocalInstalledPluginVersion(plugin.id, latestVersion, state.projectPath);
|
|
488
485
|
}
|
|
489
486
|
// On fresh install, prompt for MCP server env vars if needed
|
|
490
|
-
if (action ===
|
|
487
|
+
if (action === "install") {
|
|
491
488
|
modal.hideModal();
|
|
492
489
|
await collectPluginEnvVars(plugin.name, plugin.marketplace);
|
|
493
490
|
}
|
|
494
491
|
}
|
|
495
|
-
if (action !==
|
|
492
|
+
if (action !== "install") {
|
|
496
493
|
modal.hideModal();
|
|
497
494
|
}
|
|
498
495
|
fetchData();
|
|
499
496
|
}
|
|
500
497
|
catch (error) {
|
|
501
498
|
modal.hideModal();
|
|
502
|
-
await modal.message(
|
|
499
|
+
await modal.message("Error", `Failed: ${error}`, "error");
|
|
503
500
|
}
|
|
504
501
|
}
|
|
505
502
|
};
|
|
506
503
|
const handleUpdate = async () => {
|
|
507
504
|
const item = selectableItems[pluginsState.selectedIndex];
|
|
508
|
-
if (!item || item.type !==
|
|
505
|
+
if (!item || item.type !== "plugin" || !item.plugin?.hasUpdate)
|
|
509
506
|
return;
|
|
510
507
|
const plugin = item.plugin;
|
|
511
|
-
const isGlobal = pluginsState.scope ===
|
|
508
|
+
const isGlobal = pluginsState.scope === "global";
|
|
512
509
|
modal.loading(`Updating ${plugin.name}...`);
|
|
513
510
|
try {
|
|
514
|
-
const versionToSave = plugin.version ||
|
|
511
|
+
const versionToSave = plugin.version || "0.0.0";
|
|
515
512
|
if (isGlobal) {
|
|
516
513
|
await saveGlobalInstalledPluginVersion(plugin.id, versionToSave);
|
|
517
514
|
}
|
|
@@ -523,20 +520,20 @@ export function PluginsScreen() {
|
|
|
523
520
|
}
|
|
524
521
|
catch (error) {
|
|
525
522
|
modal.hideModal();
|
|
526
|
-
await modal.message(
|
|
523
|
+
await modal.message("Error", `Failed to update: ${error}`, "error");
|
|
527
524
|
}
|
|
528
525
|
};
|
|
529
526
|
const handleUpdateAll = async () => {
|
|
530
|
-
if (pluginsState.plugins.status !==
|
|
527
|
+
if (pluginsState.plugins.status !== "success")
|
|
531
528
|
return;
|
|
532
529
|
const updatable = pluginsState.plugins.data.filter((p) => p.hasUpdate);
|
|
533
530
|
if (updatable.length === 0)
|
|
534
531
|
return;
|
|
535
|
-
const isGlobal = pluginsState.scope ===
|
|
532
|
+
const isGlobal = pluginsState.scope === "global";
|
|
536
533
|
modal.loading(`Updating ${updatable.length} plugin(s)...`);
|
|
537
534
|
try {
|
|
538
535
|
for (const plugin of updatable) {
|
|
539
|
-
const versionToSave = plugin.version ||
|
|
536
|
+
const versionToSave = plugin.version || "0.0.0";
|
|
540
537
|
if (isGlobal) {
|
|
541
538
|
await saveGlobalInstalledPluginVersion(plugin.id, versionToSave);
|
|
542
539
|
}
|
|
@@ -549,50 +546,55 @@ export function PluginsScreen() {
|
|
|
549
546
|
}
|
|
550
547
|
catch (error) {
|
|
551
548
|
modal.hideModal();
|
|
552
|
-
await modal.message(
|
|
549
|
+
await modal.message("Error", `Failed to update: ${error}`, "error");
|
|
553
550
|
}
|
|
554
551
|
};
|
|
555
552
|
// Scope-specific toggle (install if not installed, uninstall if installed)
|
|
556
553
|
const handleScopeToggle = async (scope) => {
|
|
557
554
|
const item = selectableItems[pluginsState.selectedIndex];
|
|
558
|
-
if (!item || item.type !==
|
|
555
|
+
if (!item || item.type !== "plugin" || !item.plugin)
|
|
559
556
|
return;
|
|
560
557
|
const plugin = item.plugin;
|
|
561
|
-
const latestVersion = plugin.version ||
|
|
562
|
-
const scopeLabel = scope ===
|
|
558
|
+
const latestVersion = plugin.version || "0.0.0";
|
|
559
|
+
const scopeLabel = scope === "user" ? "User" : scope === "project" ? "Project" : "Local";
|
|
563
560
|
// Check if installed in this scope
|
|
564
|
-
const scopeData = scope ===
|
|
565
|
-
|
|
566
|
-
|
|
561
|
+
const scopeData = scope === "user"
|
|
562
|
+
? plugin.userScope
|
|
563
|
+
: scope === "project"
|
|
564
|
+
? plugin.projectScope
|
|
565
|
+
: plugin.localScope;
|
|
567
566
|
const isInstalledInScope = scopeData?.enabled;
|
|
568
567
|
const installedVersion = scopeData?.version;
|
|
569
568
|
// Check if this scope has an update available
|
|
570
|
-
const hasUpdateInScope = isInstalledInScope &&
|
|
571
|
-
|
|
569
|
+
const hasUpdateInScope = isInstalledInScope &&
|
|
570
|
+
installedVersion &&
|
|
571
|
+
latestVersion !== "0.0.0" &&
|
|
572
572
|
installedVersion !== latestVersion;
|
|
573
573
|
// Determine action: update if available, otherwise toggle install/uninstall
|
|
574
574
|
let action;
|
|
575
575
|
if (isInstalledInScope && hasUpdateInScope) {
|
|
576
|
-
action =
|
|
576
|
+
action = "update";
|
|
577
577
|
}
|
|
578
578
|
else if (isInstalledInScope) {
|
|
579
|
-
action =
|
|
579
|
+
action = "uninstall";
|
|
580
580
|
}
|
|
581
581
|
else {
|
|
582
|
-
action =
|
|
582
|
+
action = "install";
|
|
583
583
|
}
|
|
584
|
-
const actionLabel = action ===
|
|
585
|
-
|
|
586
|
-
|
|
584
|
+
const actionLabel = action === "update"
|
|
585
|
+
? `Updating ${scopeLabel}`
|
|
586
|
+
: action === "install"
|
|
587
|
+
? `Installing to ${scopeLabel}`
|
|
588
|
+
: `Uninstalling from ${scopeLabel}`;
|
|
587
589
|
modal.loading(`${actionLabel}...`);
|
|
588
590
|
try {
|
|
589
|
-
if (action ===
|
|
591
|
+
if (action === "uninstall") {
|
|
590
592
|
// Uninstall from this scope
|
|
591
|
-
if (scope ===
|
|
593
|
+
if (scope === "user") {
|
|
592
594
|
await enableGlobalPlugin(plugin.id, false);
|
|
593
595
|
await removeGlobalInstalledPluginVersion(plugin.id);
|
|
594
596
|
}
|
|
595
|
-
else if (scope ===
|
|
597
|
+
else if (scope === "project") {
|
|
596
598
|
await enablePlugin(plugin.id, false, state.projectPath);
|
|
597
599
|
await removeInstalledPluginVersion(plugin.id, state.projectPath);
|
|
598
600
|
}
|
|
@@ -603,11 +605,11 @@ export function PluginsScreen() {
|
|
|
603
605
|
}
|
|
604
606
|
else {
|
|
605
607
|
// Install or update to this scope (both save the latest version)
|
|
606
|
-
if (scope ===
|
|
608
|
+
if (scope === "user") {
|
|
607
609
|
await enableGlobalPlugin(plugin.id, true);
|
|
608
610
|
await saveGlobalInstalledPluginVersion(plugin.id, latestVersion);
|
|
609
611
|
}
|
|
610
|
-
else if (scope ===
|
|
612
|
+
else if (scope === "project") {
|
|
611
613
|
await enablePlugin(plugin.id, true, state.projectPath);
|
|
612
614
|
await saveInstalledPluginVersion(plugin.id, latestVersion, state.projectPath);
|
|
613
615
|
}
|
|
@@ -616,42 +618,48 @@ export function PluginsScreen() {
|
|
|
616
618
|
await saveLocalInstalledPluginVersion(plugin.id, latestVersion, state.projectPath);
|
|
617
619
|
}
|
|
618
620
|
// On fresh install, prompt for MCP server env vars if needed
|
|
619
|
-
if (action ===
|
|
621
|
+
if (action === "install") {
|
|
620
622
|
modal.hideModal();
|
|
621
623
|
await collectPluginEnvVars(plugin.name, plugin.marketplace);
|
|
622
624
|
}
|
|
623
625
|
}
|
|
624
|
-
if (action !==
|
|
626
|
+
if (action !== "install") {
|
|
625
627
|
modal.hideModal();
|
|
626
628
|
}
|
|
627
629
|
fetchData();
|
|
628
630
|
}
|
|
629
631
|
catch (error) {
|
|
630
632
|
modal.hideModal();
|
|
631
|
-
await modal.message(
|
|
633
|
+
await modal.message("Error", `Failed: ${error}`, "error");
|
|
632
634
|
}
|
|
633
635
|
};
|
|
634
636
|
const handleUninstall = async () => {
|
|
635
637
|
const item = selectableItems[pluginsState.selectedIndex];
|
|
636
|
-
if (!item || item.type !==
|
|
638
|
+
if (!item || item.type !== "plugin" || !item.plugin)
|
|
637
639
|
return;
|
|
638
640
|
const plugin = item.plugin;
|
|
639
641
|
// Build list of scopes where plugin is installed
|
|
640
642
|
const installedScopes = [];
|
|
641
643
|
if (plugin.userScope?.enabled) {
|
|
642
|
-
const ver = plugin.userScope.version
|
|
643
|
-
|
|
644
|
+
const ver = plugin.userScope.version
|
|
645
|
+
? ` v${plugin.userScope.version}`
|
|
646
|
+
: "";
|
|
647
|
+
installedScopes.push({ label: `User (global)${ver}`, value: "user" });
|
|
644
648
|
}
|
|
645
649
|
if (plugin.projectScope?.enabled) {
|
|
646
|
-
const ver = plugin.projectScope.version
|
|
647
|
-
|
|
650
|
+
const ver = plugin.projectScope.version
|
|
651
|
+
? ` v${plugin.projectScope.version}`
|
|
652
|
+
: "";
|
|
653
|
+
installedScopes.push({ label: `Project${ver}`, value: "project" });
|
|
648
654
|
}
|
|
649
655
|
if (plugin.localScope?.enabled) {
|
|
650
|
-
const ver = plugin.localScope.version
|
|
651
|
-
|
|
656
|
+
const ver = plugin.localScope.version
|
|
657
|
+
? ` v${plugin.localScope.version}`
|
|
658
|
+
: "";
|
|
659
|
+
installedScopes.push({ label: `Local${ver}`, value: "local" });
|
|
652
660
|
}
|
|
653
661
|
if (installedScopes.length === 0) {
|
|
654
|
-
await modal.message(
|
|
662
|
+
await modal.message("Not Installed", `${plugin.name} is not installed in any scope.`, "info");
|
|
655
663
|
return;
|
|
656
664
|
}
|
|
657
665
|
const scopeValue = await modal.select(`Uninstall ${plugin.name}`, `Installed in ${installedScopes.length} scope(s):`, installedScopes);
|
|
@@ -659,11 +667,11 @@ export function PluginsScreen() {
|
|
|
659
667
|
return; // Cancelled
|
|
660
668
|
modal.loading(`Uninstalling ${plugin.name}...`);
|
|
661
669
|
try {
|
|
662
|
-
if (scopeValue ===
|
|
670
|
+
if (scopeValue === "user") {
|
|
663
671
|
await enableGlobalPlugin(plugin.id, false);
|
|
664
672
|
await removeGlobalInstalledPluginVersion(plugin.id);
|
|
665
673
|
}
|
|
666
|
-
else if (scopeValue ===
|
|
674
|
+
else if (scopeValue === "project") {
|
|
667
675
|
await enablePlugin(plugin.id, false, state.projectPath);
|
|
668
676
|
await removeInstalledPluginVersion(plugin.id, state.projectPath);
|
|
669
677
|
}
|
|
@@ -677,66 +685,70 @@ export function PluginsScreen() {
|
|
|
677
685
|
}
|
|
678
686
|
catch (error) {
|
|
679
687
|
modal.hideModal();
|
|
680
|
-
await modal.message(
|
|
688
|
+
await modal.message("Error", `Failed to uninstall: ${error}`, "error");
|
|
681
689
|
}
|
|
682
690
|
};
|
|
683
691
|
// Render loading state
|
|
684
|
-
if (pluginsState.marketplaces.status ===
|
|
685
|
-
|
|
692
|
+
if (pluginsState.marketplaces.status === "loading" ||
|
|
693
|
+
pluginsState.plugins.status === "loading") {
|
|
694
|
+
return (_jsxs("box", { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: "#7e57c2", children: _jsx("strong", { children: "claudeup Plugins" }) }), _jsx("text", { fg: "gray", children: "Loading..." })] }));
|
|
686
695
|
}
|
|
687
696
|
// Render error state
|
|
688
|
-
if (pluginsState.marketplaces.status ===
|
|
689
|
-
|
|
697
|
+
if (pluginsState.marketplaces.status === "error" ||
|
|
698
|
+
pluginsState.plugins.status === "error") {
|
|
699
|
+
return (_jsxs("box", { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: "#7e57c2", children: _jsx("strong", { children: "claudeup Plugins" }) }), _jsx("text", { fg: "red", children: "Error loading data" })] }));
|
|
690
700
|
}
|
|
691
701
|
// Get selected item for detail panel
|
|
692
702
|
const selectedItem = selectableItems[pluginsState.selectedIndex];
|
|
693
703
|
// Render item with fuzzy highlight support
|
|
694
704
|
const renderListItem = (item, _idx, isSelected) => {
|
|
695
|
-
if (item.type ===
|
|
705
|
+
if (item.type === "category" && item.marketplace) {
|
|
696
706
|
const mp = item.marketplace;
|
|
697
707
|
// Differentiate marketplace types with appropriate badges
|
|
698
|
-
let statusText =
|
|
699
|
-
let statusColor =
|
|
708
|
+
let statusText = "";
|
|
709
|
+
let statusColor = "green";
|
|
700
710
|
if (item.marketplaceEnabled) {
|
|
701
|
-
if (mp.name ===
|
|
702
|
-
statusText =
|
|
703
|
-
statusColor =
|
|
711
|
+
if (mp.name === "claude-plugins-official") {
|
|
712
|
+
statusText = "★ Official";
|
|
713
|
+
statusColor = "yellow";
|
|
704
714
|
}
|
|
705
|
-
else if (mp.name ===
|
|
706
|
-
statusText =
|
|
707
|
-
statusColor =
|
|
715
|
+
else if (mp.name === "claude-code-plugins") {
|
|
716
|
+
statusText = "⚠ Deprecated";
|
|
717
|
+
statusColor = "gray";
|
|
708
718
|
}
|
|
709
719
|
else if (mp.official) {
|
|
710
|
-
statusText =
|
|
711
|
-
statusColor =
|
|
720
|
+
statusText = "★ Official";
|
|
721
|
+
statusColor = "yellow";
|
|
712
722
|
}
|
|
713
723
|
else {
|
|
714
|
-
statusText =
|
|
715
|
-
statusColor =
|
|
724
|
+
statusText = "✓ Added";
|
|
725
|
+
statusColor = "green";
|
|
716
726
|
}
|
|
717
727
|
}
|
|
718
728
|
if (isSelected) {
|
|
719
|
-
const arrow = item.isExpanded ?
|
|
720
|
-
const count = item.pluginCount !== undefined && item.pluginCount > 0
|
|
721
|
-
|
|
729
|
+
const arrow = item.isExpanded ? "▼" : "▶";
|
|
730
|
+
const count = item.pluginCount !== undefined && item.pluginCount > 0
|
|
731
|
+
? ` (${item.pluginCount})`
|
|
732
|
+
: "";
|
|
733
|
+
return (_jsx("text", { bg: "magenta", fg: "white", children: _jsxs("strong", { children: [" ", arrow, " ", mp.displayName, count, " "] }) }));
|
|
722
734
|
}
|
|
723
735
|
return (_jsx(CategoryHeader, { title: mp.displayName, expanded: item.isExpanded, count: item.pluginCount, status: statusText, statusColor: statusColor }));
|
|
724
736
|
}
|
|
725
|
-
if (item.type ===
|
|
737
|
+
if (item.type === "plugin" && item.plugin) {
|
|
726
738
|
const plugin = item.plugin;
|
|
727
|
-
let statusIcon =
|
|
728
|
-
let statusColor =
|
|
739
|
+
let statusIcon = "○";
|
|
740
|
+
let statusColor = "gray";
|
|
729
741
|
if (plugin.enabled) {
|
|
730
|
-
statusIcon =
|
|
731
|
-
statusColor =
|
|
742
|
+
statusIcon = "●";
|
|
743
|
+
statusColor = "green";
|
|
732
744
|
}
|
|
733
745
|
else if (plugin.installedVersion) {
|
|
734
|
-
statusIcon =
|
|
735
|
-
statusColor =
|
|
746
|
+
statusIcon = "●";
|
|
747
|
+
statusColor = "yellow";
|
|
736
748
|
}
|
|
737
749
|
// Build version string
|
|
738
|
-
let versionStr =
|
|
739
|
-
if (plugin.installedVersion && plugin.installedVersion !==
|
|
750
|
+
let versionStr = "";
|
|
751
|
+
if (plugin.installedVersion && plugin.installedVersion !== "0.0.0") {
|
|
740
752
|
versionStr = ` v${plugin.installedVersion}`;
|
|
741
753
|
if (plugin.hasUpdate && plugin.version) {
|
|
742
754
|
versionStr += ` → v${plugin.version}`;
|
|
@@ -747,52 +759,52 @@ export function PluginsScreen() {
|
|
|
747
759
|
const segments = matches ? highlightMatches(plugin.name, matches) : null;
|
|
748
760
|
if (isSelected) {
|
|
749
761
|
const displayText = ` ${statusIcon} ${plugin.name}${versionStr} `;
|
|
750
|
-
return (_jsx(
|
|
762
|
+
return (_jsx("text", { bg: "magenta", fg: "white", children: displayText }));
|
|
751
763
|
}
|
|
752
764
|
// For non-selected, render with colors
|
|
753
765
|
const displayName = segments
|
|
754
|
-
? segments.map(seg => seg.text).join(
|
|
766
|
+
? segments.map((seg) => seg.text).join("")
|
|
755
767
|
: plugin.name;
|
|
756
|
-
return (_jsxs(
|
|
768
|
+
return (_jsxs("text", { children: [_jsxs("span", { fg: statusColor, children: [" ", statusIcon, " "] }), _jsx("span", { children: displayName }), _jsx("span", { fg: plugin.hasUpdate ? "yellow" : "gray", children: versionStr })] }));
|
|
757
769
|
}
|
|
758
|
-
return _jsx(
|
|
770
|
+
return _jsx("text", { fg: "gray", children: item.label });
|
|
759
771
|
};
|
|
760
772
|
// Render detail content - compact to fit in available space
|
|
761
773
|
const renderDetail = () => {
|
|
762
774
|
if (!selectedItem) {
|
|
763
|
-
return _jsx(
|
|
775
|
+
return _jsx("text", { fg: "gray", children: "Select an item" });
|
|
764
776
|
}
|
|
765
|
-
if (selectedItem.type ===
|
|
777
|
+
if (selectedItem.type === "category" && selectedItem.marketplace) {
|
|
766
778
|
const mp = selectedItem.marketplace;
|
|
767
779
|
const isEnabled = selectedItem.marketplaceEnabled;
|
|
768
780
|
// Get appropriate badge for marketplace type
|
|
769
781
|
const getBadge = () => {
|
|
770
|
-
if (mp.name ===
|
|
771
|
-
return
|
|
772
|
-
if (mp.name ===
|
|
773
|
-
return
|
|
782
|
+
if (mp.name === "claude-plugins-official")
|
|
783
|
+
return " ★";
|
|
784
|
+
if (mp.name === "claude-code-plugins")
|
|
785
|
+
return " ⚠";
|
|
774
786
|
if (mp.official)
|
|
775
|
-
return
|
|
776
|
-
return
|
|
787
|
+
return " ★";
|
|
788
|
+
return "";
|
|
777
789
|
};
|
|
778
790
|
// Determine action hint based on state
|
|
779
791
|
const isCollapsed = pluginsState.collapsedMarketplaces.has(mp.name);
|
|
780
792
|
const hasPlugins = (selectedItem.pluginCount || 0) > 0;
|
|
781
|
-
let actionHint =
|
|
793
|
+
let actionHint = "Add";
|
|
782
794
|
if (isEnabled) {
|
|
783
795
|
if (isCollapsed) {
|
|
784
|
-
actionHint =
|
|
796
|
+
actionHint = "Expand";
|
|
785
797
|
}
|
|
786
798
|
else if (hasPlugins) {
|
|
787
|
-
actionHint =
|
|
799
|
+
actionHint = "Collapse";
|
|
788
800
|
}
|
|
789
801
|
else {
|
|
790
|
-
actionHint =
|
|
802
|
+
actionHint = "Remove";
|
|
791
803
|
}
|
|
792
804
|
}
|
|
793
|
-
return (_jsxs(
|
|
805
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: "cyan", children: _jsxs("strong", { children: [mp.displayName, getBadge()] }) }), _jsx("text", { fg: "gray", children: mp.description || "No description" }), _jsx("text", { fg: isEnabled ? "green" : "gray", children: isEnabled ? "● Added" : "○ Not added" }), _jsxs("text", { fg: "blue", children: ["github.com/", mp.source.repo] }), _jsxs("text", { children: ["Plugins: ", selectedItem.pluginCount || 0] }), _jsxs("box", { marginTop: 1, children: [_jsx("text", { bg: isEnabled ? "cyan" : "green", fg: "black", children: " Enter " }), _jsxs("text", { fg: "gray", children: [" ", actionHint] })] }), isEnabled && (_jsx("box", { children: _jsx("text", { fg: "gray", children: "\u2190 \u2192 to expand/collapse" }) }))] }));
|
|
794
806
|
}
|
|
795
|
-
if (selectedItem.type ===
|
|
807
|
+
if (selectedItem.type === "plugin" && selectedItem.plugin) {
|
|
796
808
|
const plugin = selectedItem.plugin;
|
|
797
809
|
const isInstalled = plugin.enabled || plugin.installedVersion;
|
|
798
810
|
// Build component counts
|
|
@@ -809,23 +821,24 @@ export function PluginsScreen() {
|
|
|
809
821
|
components.push(`${Object.keys(plugin.lspServers).length} LSP`);
|
|
810
822
|
}
|
|
811
823
|
// Show version only if valid (not null, not 0.0.0)
|
|
812
|
-
const showVersion = plugin.version && plugin.version !==
|
|
813
|
-
const showInstalledVersion = plugin.installedVersion && plugin.installedVersion !==
|
|
814
|
-
return (_jsxs(
|
|
824
|
+
const showVersion = plugin.version && plugin.version !== "0.0.0";
|
|
825
|
+
const showInstalledVersion = plugin.installedVersion && plugin.installedVersion !== "0.0.0";
|
|
826
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { justifyContent: "center", children: _jsx("text", { bg: "magenta", fg: "white", children: _jsxs("strong", { children: [" ", plugin.name, plugin.hasUpdate ? " ⬆" : "", " "] }) }) }), _jsx("box", { marginTop: 1, children: isInstalled ? (_jsx("text", { fg: plugin.enabled ? "green" : "yellow", children: plugin.enabled ? "● Enabled" : "● Disabled" })) : (_jsx("text", { fg: "gray", children: "\u25CB Not installed" })) }), _jsx("box", { marginTop: 1, marginBottom: 1, children: _jsx("text", { fg: "white", children: plugin.description }) }), showVersion && (_jsxs("text", { children: [_jsx("span", { children: "Version " }), _jsxs("span", { fg: "blue", children: ["v", plugin.version] }), showInstalledVersion &&
|
|
827
|
+
plugin.installedVersion !== plugin.version && (_jsxs("span", { children: [" (v", plugin.installedVersion, " installed)"] }))] })), plugin.category && (_jsxs("text", { children: [_jsx("span", { children: "Category " }), _jsx("span", { fg: "magenta", children: plugin.category })] })), plugin.author && (_jsxs("text", { children: [_jsx("span", { children: "Author " }), _jsx("span", { children: plugin.author.name })] })), components.length > 0 && (_jsxs("text", { children: [_jsx("span", { children: "Contains " }), _jsx("span", { fg: "yellow", children: components.join(" · ") })] })), _jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsx("span", { bg: "cyan", fg: "black", children: " u " }), _jsx("span", { fg: plugin.userScope?.enabled ? "cyan" : "gray", children: plugin.userScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "cyan", children: "User" }), _jsx("span", { children: " global" }), plugin.userScope?.version && (_jsxs("span", { fg: "cyan", children: [" v", plugin.userScope.version] }))] }), _jsxs("text", { children: [_jsx("span", { bg: "green", fg: "black", children: " p " }), _jsx("span", { fg: plugin.projectScope?.enabled ? "green" : "gray", children: plugin.projectScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "green", children: "Project" }), _jsx("span", { children: " team" }), plugin.projectScope?.version && (_jsxs("span", { fg: "green", children: [" v", plugin.projectScope.version] }))] }), _jsxs("text", { children: [_jsx("span", { bg: "yellow", fg: "black", children: " l " }), _jsx("span", { fg: plugin.localScope?.enabled ? "yellow" : "gray", children: plugin.localScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "yellow", children: "Local" }), _jsx("span", { children: " private" }), plugin.localScope?.version && (_jsxs("span", { fg: "yellow", children: [" v", plugin.localScope.version] }))] })] })] }), isInstalled && (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [plugin.hasUpdate && (_jsxs("box", { children: [_jsx("text", { bg: "magenta", fg: "white", children: " U " }), _jsxs("text", { children: [" Update to v", plugin.version] })] })), _jsxs("box", { children: [_jsx("text", { bg: "red", fg: "white", children: " d " }), _jsx("text", { children: " Uninstall" })] })] }))] }));
|
|
815
828
|
}
|
|
816
829
|
return null;
|
|
817
830
|
};
|
|
818
831
|
const footerHints = isSearchActive
|
|
819
|
-
?
|
|
820
|
-
:
|
|
832
|
+
? "Type to search │ Enter Confirm │ Esc Cancel"
|
|
833
|
+
: "u/p/l:scope │ U:update │ a:all │ d:remove │ n:add │ t:team │ /:search";
|
|
821
834
|
// Calculate status for subtitle
|
|
822
|
-
const scopeLabel = pluginsState.scope ===
|
|
823
|
-
const plugins = pluginsState.plugins.status ===
|
|
824
|
-
const installedCount = plugins.filter(p => p.enabled).length;
|
|
825
|
-
const updateCount = plugins.filter(p => p.hasUpdate).length;
|
|
826
|
-
const subtitle = `${scopeLabel} │ ${installedCount} installed${updateCount > 0 ? ` │ ${updateCount} updates` :
|
|
835
|
+
const scopeLabel = pluginsState.scope === "global" ? "Global" : "Project";
|
|
836
|
+
const plugins = pluginsState.plugins.status === "success" ? pluginsState.plugins.data : [];
|
|
837
|
+
const installedCount = plugins.filter((p) => p.enabled).length;
|
|
838
|
+
const updateCount = plugins.filter((p) => p.hasUpdate).length;
|
|
839
|
+
const subtitle = `${scopeLabel} │ ${installedCount} installed${updateCount > 0 ? ` │ ${updateCount} updates` : ""}`;
|
|
827
840
|
// Search placeholder shows status when not searching
|
|
828
|
-
const searchPlaceholder = `${scopeLabel} │ ${installedCount} installed${updateCount > 0 ? ` │ ${updateCount} ⬆` :
|
|
841
|
+
const searchPlaceholder = `${scopeLabel} │ ${installedCount} installed${updateCount > 0 ? ` │ ${updateCount} ⬆` : ""} │ / to search`;
|
|
829
842
|
return (_jsx(ScreenLayout, { title: "claudeup Plugins", subtitle: subtitle, currentScreen: "plugins", search: {
|
|
830
843
|
isActive: isSearchActive,
|
|
831
844
|
query: pluginsState.searchQuery,
|
|
@@ -833,4 +846,3 @@ export function PluginsScreen() {
|
|
|
833
846
|
}, footerHints: footerHints, listPanel: _jsx(ScrollableList, { items: selectableItems, selectedIndex: pluginsState.selectedIndex, renderItem: renderListItem, maxHeight: dimensions.listPanelHeight }), detailPanel: renderDetail() }));
|
|
834
847
|
}
|
|
835
848
|
export default PluginsScreen;
|
|
836
|
-
//# sourceMappingURL=PluginsScreen.js.map
|