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
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import React, { useEffect, useCallback, useState, useRef } from "react";
|
|
2
|
+
import { useApp, useModal, useNavigation } from "../state/AppContext.js";
|
|
3
|
+
import { useDimensions } from "../state/DimensionsContext.js";
|
|
4
|
+
import { useKeyboard } from "../hooks/useKeyboard.js";
|
|
5
|
+
import { ScreenLayout } from "../components/layout/index.js";
|
|
6
|
+
import { ScrollableList } from "../components/ScrollableList.js";
|
|
7
|
+
import { searchMcpServers, formatDate } from "../../services/mcp-registry.js";
|
|
8
|
+
import { addMcpServer, setAllowMcp } from "../../services/claude-settings.js";
|
|
9
|
+
import type { McpRegistryServer, McpServerConfig } from "../../types/index.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Deduplicate servers by name, keeping only the latest version.
|
|
13
|
+
* Uses version string comparison, falling back to published_at date.
|
|
14
|
+
*/
|
|
15
|
+
function deduplicateServers(servers: McpRegistryServer[]): McpRegistryServer[] {
|
|
16
|
+
const serverMap = new Map<string, McpRegistryServer>();
|
|
17
|
+
|
|
18
|
+
for (const server of servers) {
|
|
19
|
+
const existing = serverMap.get(server.name);
|
|
20
|
+
if (!existing) {
|
|
21
|
+
serverMap.set(server.name, server);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Compare versions - keep the newer one
|
|
26
|
+
const isNewer = compareVersions(server, existing) > 0;
|
|
27
|
+
if (isNewer) {
|
|
28
|
+
serverMap.set(server.name, server);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return Array.from(serverMap.values());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Compare two servers by version. Returns:
|
|
37
|
+
* > 0 if a is newer
|
|
38
|
+
* < 0 if b is newer
|
|
39
|
+
* 0 if equal or cannot determine
|
|
40
|
+
*/
|
|
41
|
+
function compareVersions(a: McpRegistryServer, b: McpRegistryServer): number {
|
|
42
|
+
// Try semver comparison first
|
|
43
|
+
if (a.version && b.version) {
|
|
44
|
+
const aParts = a.version.split(".").map((n) => parseInt(n, 10) || 0);
|
|
45
|
+
const bParts = b.version.split(".").map((n) => parseInt(n, 10) || 0);
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
48
|
+
const aVal = aParts[i] || 0;
|
|
49
|
+
const bVal = bParts[i] || 0;
|
|
50
|
+
if (aVal !== bVal) {
|
|
51
|
+
return aVal - bVal;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Fall back to published_at date
|
|
57
|
+
if (a.published_at && b.published_at) {
|
|
58
|
+
return (
|
|
59
|
+
new Date(a.published_at).getTime() - new Date(b.published_at).getTime()
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// If one has a date and other doesn't, prefer the one with date
|
|
64
|
+
if (a.published_at && !b.published_at) return 1;
|
|
65
|
+
if (!a.published_at && b.published_at) return -1;
|
|
66
|
+
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function McpRegistryScreen() {
|
|
71
|
+
const { state, dispatch } = useApp();
|
|
72
|
+
const { mcpRegistry } = state;
|
|
73
|
+
const modal = useModal();
|
|
74
|
+
const { navigateToScreen } = useNavigation();
|
|
75
|
+
const dimensions = useDimensions();
|
|
76
|
+
|
|
77
|
+
const [servers, setServers] = useState<McpRegistryServer[]>([]);
|
|
78
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
79
|
+
const [error, setError] = useState<string | null>(null);
|
|
80
|
+
const [searchQuery, setSearchQuery] = useState(mcpRegistry.searchQuery || "");
|
|
81
|
+
|
|
82
|
+
const isSearchActive =
|
|
83
|
+
state.isSearching &&
|
|
84
|
+
state.currentRoute.screen === "mcp-registry" &&
|
|
85
|
+
!state.modal;
|
|
86
|
+
|
|
87
|
+
const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
88
|
+
|
|
89
|
+
// Load servers
|
|
90
|
+
const loadServers = useCallback(async (query: string) => {
|
|
91
|
+
setIsLoading(true);
|
|
92
|
+
setError(null);
|
|
93
|
+
try {
|
|
94
|
+
const response = await searchMcpServers({ query, limit: 50 });
|
|
95
|
+
if (!response || !Array.isArray(response.servers)) {
|
|
96
|
+
throw new Error("Invalid response from MCP Registry API");
|
|
97
|
+
}
|
|
98
|
+
// Deduplicate to show only latest version of each server
|
|
99
|
+
const deduplicated = deduplicateServers(response.servers);
|
|
100
|
+
setServers(deduplicated);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
setError(err instanceof Error ? err.message : "Failed to load servers");
|
|
103
|
+
setServers([]);
|
|
104
|
+
}
|
|
105
|
+
setIsLoading(false);
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
// Debounced search
|
|
109
|
+
const debouncedSearch = useCallback(
|
|
110
|
+
(query: string) => {
|
|
111
|
+
if (searchTimeoutRef.current) {
|
|
112
|
+
clearTimeout(searchTimeoutRef.current);
|
|
113
|
+
}
|
|
114
|
+
searchTimeoutRef.current = setTimeout(() => {
|
|
115
|
+
loadServers(query);
|
|
116
|
+
}, 300);
|
|
117
|
+
},
|
|
118
|
+
[loadServers],
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
loadServers(searchQuery);
|
|
123
|
+
return () => {
|
|
124
|
+
if (searchTimeoutRef.current) {
|
|
125
|
+
clearTimeout(searchTimeoutRef.current);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
130
|
+
// Keyboard handling
|
|
131
|
+
useKeyboard((event) => {
|
|
132
|
+
// Handle search mode
|
|
133
|
+
if (isSearchActive) {
|
|
134
|
+
if (event.name === "escape") {
|
|
135
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
136
|
+
} else if (event.name === "enter") {
|
|
137
|
+
// Exit search mode and stay on list for navigation
|
|
138
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
139
|
+
} else if (event.name === "up") {
|
|
140
|
+
// Allow navigation while searching
|
|
141
|
+
const newIndex = Math.max(0, mcpRegistry.selectedIndex - 1);
|
|
142
|
+
dispatch({ type: "MCPREGISTRY_SELECT", index: newIndex });
|
|
143
|
+
} else if (event.name === "down") {
|
|
144
|
+
// Allow navigation while searching
|
|
145
|
+
const newIndex = Math.min(
|
|
146
|
+
Math.max(0, servers.length - 1),
|
|
147
|
+
mcpRegistry.selectedIndex + 1,
|
|
148
|
+
);
|
|
149
|
+
dispatch({ type: "MCPREGISTRY_SELECT", index: newIndex });
|
|
150
|
+
} else if (event.name === "backspace" || event.name === "delete") {
|
|
151
|
+
const newQuery = searchQuery.slice(0, -1);
|
|
152
|
+
setSearchQuery(newQuery);
|
|
153
|
+
dispatch({ type: "MCPREGISTRY_SEARCH", query: newQuery });
|
|
154
|
+
debouncedSearch(newQuery);
|
|
155
|
+
} else if (event.name.length === 1 && !event.ctrl && !event.meta) {
|
|
156
|
+
const newQuery = searchQuery + event.name;
|
|
157
|
+
setSearchQuery(newQuery);
|
|
158
|
+
dispatch({ type: "MCPREGISTRY_SEARCH", query: newQuery });
|
|
159
|
+
debouncedSearch(newQuery);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (state.modal) return;
|
|
165
|
+
|
|
166
|
+
// Start search with /
|
|
167
|
+
if (event.name === "/") {
|
|
168
|
+
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Navigation
|
|
173
|
+
if (event.name === "up" || event.name === "k") {
|
|
174
|
+
const newIndex = Math.max(0, mcpRegistry.selectedIndex - 1);
|
|
175
|
+
dispatch({ type: "MCPREGISTRY_SELECT", index: newIndex });
|
|
176
|
+
} else if (event.name === "down" || event.name === "j") {
|
|
177
|
+
const newIndex = Math.min(
|
|
178
|
+
Math.max(0, servers.length - 1),
|
|
179
|
+
mcpRegistry.selectedIndex + 1,
|
|
180
|
+
);
|
|
181
|
+
dispatch({ type: "MCPREGISTRY_SELECT", index: newIndex });
|
|
182
|
+
} else if (event.name === "l") {
|
|
183
|
+
navigateToScreen("mcp");
|
|
184
|
+
} else if (event.name === "R") {
|
|
185
|
+
loadServers(searchQuery);
|
|
186
|
+
} else if (event.name === "enter") {
|
|
187
|
+
handleInstall();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const handleInstall = async () => {
|
|
192
|
+
const server = servers[mcpRegistry.selectedIndex];
|
|
193
|
+
if (!server) return;
|
|
194
|
+
|
|
195
|
+
const config: McpServerConfig = {
|
|
196
|
+
type: "http",
|
|
197
|
+
url: server.url,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
modal.loading(`Installing ${server.name}...`);
|
|
201
|
+
try {
|
|
202
|
+
await setAllowMcp(true, state.projectPath);
|
|
203
|
+
await addMcpServer(server.name, config, state.projectPath);
|
|
204
|
+
modal.hideModal();
|
|
205
|
+
await modal.message(
|
|
206
|
+
"Installed",
|
|
207
|
+
`${server.name} has been configured.\n\nRestart Claude Code to activate.`,
|
|
208
|
+
"success",
|
|
209
|
+
);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
modal.hideModal();
|
|
212
|
+
await modal.message("Error", `Failed to install: ${error}`, "error");
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Get selected server
|
|
217
|
+
const selectedServer = servers[mcpRegistry.selectedIndex];
|
|
218
|
+
|
|
219
|
+
const renderDetail = () => {
|
|
220
|
+
if (isLoading) {
|
|
221
|
+
return <text fg="gray">Loading...</text>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (error) {
|
|
225
|
+
return <text fg="red">Error: {error}</text>;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!selectedServer) {
|
|
229
|
+
return <text fg="gray">Select a server to see details</text>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const dateDisplay = selectedServer.published_at
|
|
233
|
+
? formatDate(selectedServer.published_at)
|
|
234
|
+
: "unknown";
|
|
235
|
+
|
|
236
|
+
const versionDisplay = selectedServer.version
|
|
237
|
+
? `v${selectedServer.version}`
|
|
238
|
+
: "unknown";
|
|
239
|
+
|
|
240
|
+
return (
|
|
241
|
+
<box flexDirection="column">
|
|
242
|
+
<text fg="magenta"><strong>{selectedServer.name}</strong></text>
|
|
243
|
+
<box marginTop={1}>
|
|
244
|
+
<text>{selectedServer.short_description}</text>
|
|
245
|
+
</box>
|
|
246
|
+
<box marginTop={1}>
|
|
247
|
+
<text><strong>Version: </strong></text>
|
|
248
|
+
<text fg="green">{versionDisplay}</text>
|
|
249
|
+
</box>
|
|
250
|
+
<box>
|
|
251
|
+
<text><strong>Published: </strong></text>
|
|
252
|
+
<text fg="cyan">{dateDisplay}</text>
|
|
253
|
+
</box>
|
|
254
|
+
<box marginTop={1} flexDirection="column">
|
|
255
|
+
<text><strong>URL:</strong></text>
|
|
256
|
+
<text fg="cyan">{selectedServer.url}</text>
|
|
257
|
+
</box>
|
|
258
|
+
{selectedServer.source_code_url && (
|
|
259
|
+
<box marginTop={1} flexDirection="column">
|
|
260
|
+
<text><strong>Source:</strong></text>
|
|
261
|
+
<text fg="gray">{selectedServer.source_code_url}</text>
|
|
262
|
+
</box>
|
|
263
|
+
)}
|
|
264
|
+
<box marginTop={1}>
|
|
265
|
+
<text fg="green">Press Enter to install</text>
|
|
266
|
+
</box>
|
|
267
|
+
</box>
|
|
268
|
+
);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const renderListItem = (
|
|
272
|
+
server: McpRegistryServer,
|
|
273
|
+
_idx: number,
|
|
274
|
+
isSelected: boolean,
|
|
275
|
+
) => {
|
|
276
|
+
const version = server.version ? ` v${server.version}` : "";
|
|
277
|
+
return isSelected ? (
|
|
278
|
+
<text bg="magenta" fg="white">
|
|
279
|
+
{" "}
|
|
280
|
+
{server.name}
|
|
281
|
+
{version}{" "}
|
|
282
|
+
</text>
|
|
283
|
+
) : (
|
|
284
|
+
<text>
|
|
285
|
+
<span><strong>{server.name}</strong></span>
|
|
286
|
+
<span fg="green">{version}</span>
|
|
287
|
+
</text>
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Footer hints
|
|
292
|
+
const footerHints = isSearchActive
|
|
293
|
+
? "Type to search │ ↑↓:nav │ Enter:done │ Esc:cancel"
|
|
294
|
+
: "↑↓:nav │ Enter:install │ /:search │ R:refresh │ l:local";
|
|
295
|
+
|
|
296
|
+
// Status for search placeholder
|
|
297
|
+
const searchPlaceholder = `${servers.length} servers │ / to search`;
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<ScreenLayout
|
|
301
|
+
title="claudeup MCP Registry"
|
|
302
|
+
subtitle="Powered by MCP Registry"
|
|
303
|
+
currentScreen="mcp-registry"
|
|
304
|
+
search={{
|
|
305
|
+
isActive: isSearchActive,
|
|
306
|
+
query: searchQuery,
|
|
307
|
+
placeholder: searchPlaceholder,
|
|
308
|
+
}}
|
|
309
|
+
footerHints={footerHints}
|
|
310
|
+
listPanel={
|
|
311
|
+
isLoading ? (
|
|
312
|
+
<text fg="gray">Loading...</text>
|
|
313
|
+
) : error ? (
|
|
314
|
+
<text fg="red">Error: {error}</text>
|
|
315
|
+
) : servers.length === 0 ? (
|
|
316
|
+
<text fg="gray">No servers found</text>
|
|
317
|
+
) : (
|
|
318
|
+
<ScrollableList
|
|
319
|
+
items={servers}
|
|
320
|
+
selectedIndex={mcpRegistry.selectedIndex}
|
|
321
|
+
renderItem={renderListItem}
|
|
322
|
+
maxHeight={dimensions.listPanelHeight}
|
|
323
|
+
/>
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
detailPanel={renderDetail()}
|
|
327
|
+
/>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export default McpRegistryScreen;
|
|
@@ -1,12 +1,12 @@
|
|
|
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 { ScrollableList } from
|
|
8
|
-
import { getMcpServersByCategory, getCategoryDisplayName, categoryOrder, } from
|
|
9
|
-
import { addMcpServer, removeMcpServer, getInstalledMcpServers, getEnabledMcpServers, } from
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { useEffect, useCallback, useMemo } from "react";
|
|
3
|
+
import { useApp, useModal, useNavigation } 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 { ScrollableList } from "../components/ScrollableList.js";
|
|
8
|
+
import { getMcpServersByCategory, getCategoryDisplayName, categoryOrder, } from "../../data/mcp-servers.js";
|
|
9
|
+
import { addMcpServer, removeMcpServer, getInstalledMcpServers, getEnabledMcpServers, } from "../../services/claude-settings.js";
|
|
10
10
|
export function McpScreen() {
|
|
11
11
|
const { state, dispatch } = useApp();
|
|
12
12
|
const { mcp } = state;
|
|
@@ -15,7 +15,7 @@ export function McpScreen() {
|
|
|
15
15
|
const dimensions = useDimensions();
|
|
16
16
|
// Fetch data
|
|
17
17
|
const fetchData = useCallback(async () => {
|
|
18
|
-
dispatch({ type:
|
|
18
|
+
dispatch({ type: "MCP_DATA_LOADING" });
|
|
19
19
|
try {
|
|
20
20
|
const serversByCategory = getMcpServersByCategory();
|
|
21
21
|
const installedServers = await getInstalledMcpServers(state.projectPath);
|
|
@@ -34,14 +34,14 @@ export function McpScreen() {
|
|
|
34
34
|
installedAsBooleans[name] = true;
|
|
35
35
|
}
|
|
36
36
|
dispatch({
|
|
37
|
-
type:
|
|
37
|
+
type: "MCP_DATA_SUCCESS",
|
|
38
38
|
servers,
|
|
39
39
|
installedServers: { ...installedAsBooleans, ...enabledServers },
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
catch (error) {
|
|
43
43
|
dispatch({
|
|
44
|
-
type:
|
|
44
|
+
type: "MCP_DATA_ERROR",
|
|
45
45
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
46
46
|
});
|
|
47
47
|
}
|
|
@@ -51,7 +51,7 @@ export function McpScreen() {
|
|
|
51
51
|
}, [fetchData]);
|
|
52
52
|
// Build list items with categories
|
|
53
53
|
const allListItems = useMemo(() => {
|
|
54
|
-
if (mcp.servers.status !==
|
|
54
|
+
if (mcp.servers.status !== "success")
|
|
55
55
|
return [];
|
|
56
56
|
const serversByCategory = getMcpServersByCategory();
|
|
57
57
|
const items = [];
|
|
@@ -66,14 +66,14 @@ export function McpScreen() {
|
|
|
66
66
|
for (const server of servers) {
|
|
67
67
|
const isInstalled = mcp.installedServers[server.name] !== undefined;
|
|
68
68
|
const isEnabled = mcp.installedServers[server.name] === true;
|
|
69
|
-
let status =
|
|
69
|
+
let status = "○";
|
|
70
70
|
if (isInstalled && isEnabled) {
|
|
71
|
-
status =
|
|
71
|
+
status = "●";
|
|
72
72
|
}
|
|
73
73
|
else if (isInstalled) {
|
|
74
|
-
status =
|
|
74
|
+
status = "●";
|
|
75
75
|
}
|
|
76
|
-
const configTag = server.requiresConfig ?
|
|
76
|
+
const configTag = server.requiresConfig ? " *" : "";
|
|
77
77
|
items.push({
|
|
78
78
|
label: ` ${status} ${server.name}${configTag}`,
|
|
79
79
|
server,
|
|
@@ -85,27 +85,27 @@ export function McpScreen() {
|
|
|
85
85
|
// Use all items - search goes to global registry, not local filter
|
|
86
86
|
const listItems = allListItems;
|
|
87
87
|
// Keyboard handling
|
|
88
|
-
|
|
88
|
+
useKeyboard((event) => {
|
|
89
89
|
if (state.isSearching || state.modal)
|
|
90
90
|
return;
|
|
91
91
|
// Start search - navigate to registry with search mode active
|
|
92
|
-
if (
|
|
93
|
-
dispatch({ type:
|
|
94
|
-
navigateToScreen(
|
|
92
|
+
if (event.name === "/") {
|
|
93
|
+
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
94
|
+
navigateToScreen("mcp-registry");
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
-
if (
|
|
97
|
+
if (event.name === "up" || event.name === "k") {
|
|
98
98
|
const newIndex = Math.max(0, mcp.selectedIndex - 1);
|
|
99
|
-
dispatch({ type:
|
|
99
|
+
dispatch({ type: "MCP_SELECT", index: newIndex });
|
|
100
100
|
}
|
|
101
|
-
else if (
|
|
101
|
+
else if (event.name === "down" || event.name === "j") {
|
|
102
102
|
const newIndex = Math.min(listItems.length - 1, mcp.selectedIndex + 1);
|
|
103
|
-
dispatch({ type:
|
|
103
|
+
dispatch({ type: "MCP_SELECT", index: newIndex });
|
|
104
104
|
}
|
|
105
|
-
else if (
|
|
106
|
-
navigateToScreen(
|
|
105
|
+
else if (event.name === "r") {
|
|
106
|
+
navigateToScreen("mcp-registry");
|
|
107
107
|
}
|
|
108
|
-
else if (
|
|
108
|
+
else if (event.name === "enter") {
|
|
109
109
|
handleSelect();
|
|
110
110
|
}
|
|
111
111
|
});
|
|
@@ -116,18 +116,18 @@ export function McpScreen() {
|
|
|
116
116
|
const server = item.server;
|
|
117
117
|
const isInstalled = mcp.installedServers[server.name] !== undefined;
|
|
118
118
|
if (isInstalled) {
|
|
119
|
-
const confirmed = await modal.confirm(`Remove ${server.name}?`,
|
|
119
|
+
const confirmed = await modal.confirm(`Remove ${server.name}?`, "This will remove the MCP server configuration.");
|
|
120
120
|
if (confirmed) {
|
|
121
121
|
modal.loading(`Removing ${server.name}...`);
|
|
122
122
|
try {
|
|
123
123
|
await removeMcpServer(server.name, state.projectPath);
|
|
124
124
|
modal.hideModal();
|
|
125
|
-
await modal.message(
|
|
125
|
+
await modal.message("Removed", `${server.name} has been removed.`, "success");
|
|
126
126
|
fetchData();
|
|
127
127
|
}
|
|
128
128
|
catch (error) {
|
|
129
129
|
modal.hideModal();
|
|
130
|
-
await modal.message(
|
|
130
|
+
await modal.message("Error", `Failed to remove: ${error}`, "error");
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -138,8 +138,8 @@ export function McpScreen() {
|
|
|
138
138
|
};
|
|
139
139
|
const installMcpServer = async (server) => {
|
|
140
140
|
let config;
|
|
141
|
-
if (server.type ===
|
|
142
|
-
config = { type:
|
|
141
|
+
if (server.type === "http") {
|
|
142
|
+
config = { type: "http", url: server.url };
|
|
143
143
|
}
|
|
144
144
|
else {
|
|
145
145
|
config = {
|
|
@@ -161,11 +161,11 @@ export function McpScreen() {
|
|
|
161
161
|
continue;
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
const value = await modal.input(`Configure ${server.name}`, `${field.label}${field.required ?
|
|
164
|
+
const value = await modal.input(`Configure ${server.name}`, `${field.label}${field.required ? " (required)" : ""}:`, field.default);
|
|
165
165
|
if (value === null)
|
|
166
166
|
return; // User cancelled
|
|
167
167
|
if (field.required && !value) {
|
|
168
|
-
await modal.message(
|
|
168
|
+
await modal.message("Required Field", `${field.label} is required.`, "error");
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
171
|
if (value) {
|
|
@@ -178,45 +178,44 @@ export function McpScreen() {
|
|
|
178
178
|
try {
|
|
179
179
|
await addMcpServer(server.name, config, state.projectPath);
|
|
180
180
|
modal.hideModal();
|
|
181
|
-
await modal.message(
|
|
181
|
+
await modal.message("Installed", `${server.name} has been configured.\n\nRestart Claude Code to activate.`, "success");
|
|
182
182
|
fetchData();
|
|
183
183
|
}
|
|
184
184
|
catch (error) {
|
|
185
185
|
modal.hideModal();
|
|
186
|
-
await modal.message(
|
|
186
|
+
await modal.message("Error", `Failed to install: ${error}`, "error");
|
|
187
187
|
}
|
|
188
188
|
};
|
|
189
189
|
// Get selected item
|
|
190
190
|
const selectedItem = listItems[mcp.selectedIndex];
|
|
191
191
|
const renderDetail = () => {
|
|
192
|
-
if (mcp.servers.status ===
|
|
193
|
-
return _jsx(
|
|
192
|
+
if (mcp.servers.status === "loading") {
|
|
193
|
+
return _jsx("text", { fg: "gray", children: "Loading MCP servers..." });
|
|
194
194
|
}
|
|
195
195
|
if (!selectedItem || selectedItem.isCategory || !selectedItem.server) {
|
|
196
|
-
return (_jsx(
|
|
196
|
+
return (_jsx("box", { flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: _jsx("text", { fg: "gray", children: "Select a server to see details" }) }));
|
|
197
197
|
}
|
|
198
198
|
const server = selectedItem.server;
|
|
199
199
|
const isInstalled = mcp.installedServers[server.name] !== undefined;
|
|
200
200
|
const isEnabled = mcp.installedServers[server.name] === true;
|
|
201
|
-
return (_jsxs(
|
|
201
|
+
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("box", { marginBottom: 1, children: [_jsx("text", { fg: "cyan", children: _jsxs("strong", { children: ["\u26A1 ", server.name] }) }), server.requiresConfig && _jsx("text", { fg: "yellow", children: " \u2699" })] }), _jsx("text", { fg: "gray", children: server.description }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("box", { children: [_jsx("text", { fg: "gray", children: "Status " }), isInstalled && isEnabled ? (_jsx("text", { fg: "green", children: "\u25CF Installed" })) : isInstalled ? (_jsx("text", { fg: "yellow", children: "\u25CF Disabled" })) : (_jsx("text", { fg: "gray", children: "\u25CB Not installed" }))] }), _jsxs("box", { children: [_jsx("text", { fg: "gray", children: "Type " }), _jsx("text", { fg: "white", children: server.type === "http" ? "HTTP" : "Command" })] }), server.type === "http" ? (_jsxs("box", { children: [_jsx("text", { fg: "gray", children: "URL " }), _jsx("text", { fg: "blue", children: server.url })] })) : (_jsxs("box", { children: [_jsx("text", { fg: "gray", children: "Command " }), _jsx("text", { fg: "cyan", children: server.command })] })), server.requiresConfig && (_jsxs("box", { children: [_jsx("text", { fg: "gray", children: "Config " }), _jsxs("text", { fg: "yellow", children: [server.configFields?.length || 0, " fields required"] })] }))] }), _jsx("box", { marginTop: 2, children: isInstalled ? (_jsxs("box", { children: [_jsx("text", { bg: "red", fg: "white", children: " Enter " }), _jsx("text", { fg: "gray", children: " Remove server" })] })) : (_jsxs("box", { children: [_jsx("text", { bg: "green", fg: "black", children: " Enter " }), _jsx("text", { fg: "gray", children: " Install server" })] })) })] }));
|
|
202
202
|
};
|
|
203
203
|
const renderListItem = (item, _idx, isSelected) => {
|
|
204
204
|
// Category header
|
|
205
205
|
if (item.isCategory) {
|
|
206
|
-
return (
|
|
206
|
+
return (_jsx("text", { fg: "magenta", children: _jsxs("strong", { children: ["\u25B8 ", item.label] }) }));
|
|
207
207
|
}
|
|
208
208
|
// Server item
|
|
209
209
|
const server = item.server;
|
|
210
210
|
const isInstalled = server && mcp.installedServers[server.name] !== undefined;
|
|
211
|
-
const icon = isInstalled ?
|
|
212
|
-
const iconColor = isInstalled ?
|
|
213
|
-
return isSelected ? (_jsxs(
|
|
211
|
+
const icon = isInstalled ? "●" : "○";
|
|
212
|
+
const iconColor = isInstalled ? "green" : "gray";
|
|
213
|
+
return isSelected ? (_jsxs("text", { bg: "magenta", fg: "white", children: [" ", icon, " ", server?.name || "", " "] })) : (_jsxs("text", { children: [_jsx("span", { fg: iconColor, children: icon }), _jsxs("span", { fg: "white", children: [" ", server?.name || ""] }), server?.requiresConfig && _jsx("span", { fg: "yellow", children: " \u2699" })] }));
|
|
214
214
|
};
|
|
215
215
|
// Calculate status counts
|
|
216
216
|
const installedCount = Object.keys(mcp.installedServers).length;
|
|
217
|
-
const enabledCount = Object.values(mcp.installedServers).filter(v => v === true).length;
|
|
217
|
+
const enabledCount = Object.values(mcp.installedServers).filter((v) => v === true).length;
|
|
218
218
|
const subtitle = `${enabledCount} enabled │ ${installedCount} configured │ / to search`;
|
|
219
219
|
return (_jsx(ScreenLayout, { title: "claudeup MCP Servers", subtitle: subtitle, currentScreen: "mcp", footerHints: "\u2191\u2193:nav \u2502 Enter:toggle \u2502 /:search \u2502 r:registry", listPanel: _jsx(ScrollableList, { items: listItems, selectedIndex: mcp.selectedIndex, renderItem: renderListItem, maxHeight: dimensions.listPanelHeight }), detailPanel: renderDetail() }));
|
|
220
220
|
}
|
|
221
221
|
export default McpScreen;
|
|
222
|
-
//# sourceMappingURL=McpScreen.js.map
|