claudeup 1.7.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.
Files changed (302) hide show
  1. package/bin/claudeup.js +20 -2
  2. package/package.json +10 -19
  3. package/src/data/cli-tools.js +123 -0
  4. package/src/data/cli-tools.ts +140 -0
  5. package/{dist → src}/data/marketplaces.js +23 -24
  6. package/src/data/marketplaces.ts +95 -0
  7. package/src/data/mcp-servers.js +509 -0
  8. package/src/data/mcp-servers.ts +526 -0
  9. package/src/data/statuslines.js +159 -0
  10. package/src/data/statuslines.ts +188 -0
  11. package/src/index.js +4 -0
  12. package/src/index.ts +5 -0
  13. package/{dist → src}/main.js +46 -47
  14. package/src/main.tsx +145 -0
  15. package/src/opentui.d.ts +191 -0
  16. package/src/prerunner/index.js +87 -0
  17. package/src/prerunner/index.ts +124 -0
  18. package/{dist → src}/services/claude-runner.js +9 -10
  19. package/src/services/claude-runner.ts +31 -0
  20. package/{dist → src}/services/claude-settings.js +72 -33
  21. package/src/services/claude-settings.ts +934 -0
  22. package/src/services/local-marketplace.js +339 -0
  23. package/src/services/local-marketplace.ts +489 -0
  24. package/{dist → src}/services/mcp-registry.js +13 -14
  25. package/src/services/mcp-registry.ts +105 -0
  26. package/{dist → src}/services/plugin-manager.js +61 -13
  27. package/src/services/plugin-manager.ts +693 -0
  28. package/{dist → src}/services/plugin-mcp-config.js +19 -18
  29. package/src/services/plugin-mcp-config.ts +242 -0
  30. package/{dist → src}/services/update-cache.js +7 -8
  31. package/src/services/update-cache.ts +78 -0
  32. package/{dist → src}/services/version-check.js +15 -14
  33. package/src/services/version-check.ts +122 -0
  34. package/src/types/index.js +1 -0
  35. package/src/types/index.ts +141 -0
  36. package/src/ui/App.js +213 -0
  37. package/src/ui/App.tsx +359 -0
  38. package/src/ui/components/CategoryHeader.js +9 -0
  39. package/src/ui/components/CategoryHeader.tsx +41 -0
  40. package/{dist → src}/ui/components/ScrollableList.js +19 -6
  41. package/src/ui/components/ScrollableList.tsx +98 -0
  42. package/src/ui/components/SearchInput.js +19 -0
  43. package/src/ui/components/SearchInput.tsx +56 -0
  44. package/src/ui/components/StyledText.js +39 -0
  45. package/src/ui/components/StyledText.tsx +70 -0
  46. package/src/ui/components/TabBar.js +38 -0
  47. package/src/ui/components/TabBar.tsx +88 -0
  48. package/src/ui/components/layout/Panel.js +6 -0
  49. package/src/ui/components/layout/Panel.tsx +62 -0
  50. package/src/ui/components/layout/ProgressBar.js +14 -0
  51. package/src/ui/components/layout/ProgressBar.tsx +47 -0
  52. package/src/ui/components/layout/ScopeTabs.js +6 -0
  53. package/src/ui/components/layout/ScopeTabs.tsx +53 -0
  54. package/src/ui/components/layout/ScreenLayout.js +21 -0
  55. package/src/ui/components/layout/ScreenLayout.tsx +147 -0
  56. package/src/ui/components/layout/index.js +4 -0
  57. package/src/ui/components/layout/index.ts +4 -0
  58. package/src/ui/components/modals/ConfirmModal.js +14 -0
  59. package/src/ui/components/modals/ConfirmModal.tsx +59 -0
  60. package/src/ui/components/modals/InputModal.js +16 -0
  61. package/src/ui/components/modals/InputModal.tsx +68 -0
  62. package/src/ui/components/modals/LoadingModal.js +14 -0
  63. package/src/ui/components/modals/LoadingModal.tsx +40 -0
  64. package/src/ui/components/modals/MessageModal.js +16 -0
  65. package/src/ui/components/modals/MessageModal.tsx +64 -0
  66. package/src/ui/components/modals/ModalContainer.js +56 -0
  67. package/src/ui/components/modals/ModalContainer.tsx +104 -0
  68. package/src/ui/components/modals/SelectModal.js +26 -0
  69. package/src/ui/components/modals/SelectModal.tsx +82 -0
  70. package/src/ui/components/modals/index.js +6 -0
  71. package/src/ui/components/modals/index.ts +6 -0
  72. package/src/ui/hooks/index.js +3 -0
  73. package/src/ui/hooks/index.ts +3 -0
  74. package/{dist → src}/ui/hooks/useAsyncData.js +21 -22
  75. package/src/ui/hooks/useAsyncData.ts +127 -0
  76. package/src/ui/hooks/useKeyboard.js +13 -0
  77. package/src/ui/hooks/useKeyboard.ts +26 -0
  78. package/src/ui/hooks/useKeyboardHandler.js +39 -0
  79. package/src/ui/hooks/useKeyboardHandler.ts +63 -0
  80. package/{dist → src}/ui/screens/CliToolsScreen.js +60 -54
  81. package/src/ui/screens/CliToolsScreen.tsx +468 -0
  82. package/src/ui/screens/EnvVarsScreen.js +154 -0
  83. package/src/ui/screens/EnvVarsScreen.tsx +269 -0
  84. package/{dist → src}/ui/screens/McpRegistryScreen.js +56 -55
  85. package/src/ui/screens/McpRegistryScreen.tsx +331 -0
  86. package/{dist → src}/ui/screens/McpScreen.js +46 -47
  87. package/src/ui/screens/McpScreen.tsx +392 -0
  88. package/src/ui/screens/ModelSelectorScreen.js +292 -0
  89. package/src/ui/screens/ModelSelectorScreen.tsx +441 -0
  90. package/{dist → src}/ui/screens/PluginsScreen.js +305 -293
  91. package/src/ui/screens/PluginsScreen.tsx +1231 -0
  92. package/src/ui/screens/StatusLineScreen.js +200 -0
  93. package/src/ui/screens/StatusLineScreen.tsx +411 -0
  94. package/src/ui/screens/index.js +7 -0
  95. package/src/ui/screens/index.ts +7 -0
  96. package/src/ui/state/AnimationContext.js +34 -0
  97. package/src/ui/state/AnimationContext.tsx +76 -0
  98. package/{dist → src}/ui/state/AppContext.js +31 -32
  99. package/src/ui/state/AppContext.tsx +235 -0
  100. package/{dist → src}/ui/state/DimensionsContext.js +16 -17
  101. package/src/ui/state/DimensionsContext.tsx +144 -0
  102. package/{dist → src}/ui/state/reducer.js +89 -90
  103. package/src/ui/state/reducer.ts +467 -0
  104. package/src/ui/state/types.js +1 -0
  105. package/src/ui/state/types.ts +273 -0
  106. package/{dist → src}/utils/command-utils.js +3 -4
  107. package/src/utils/command-utils.ts +20 -0
  108. package/{dist → src}/utils/fuzzy-search.js +2 -3
  109. package/src/utils/fuzzy-search.ts +138 -0
  110. package/{dist → src}/utils/string-utils.js +6 -6
  111. package/src/utils/string-utils.ts +88 -0
  112. package/dist/data/cli-tools.d.ts +0 -13
  113. package/dist/data/cli-tools.d.ts.map +0 -1
  114. package/dist/data/cli-tools.js +0 -124
  115. package/dist/data/cli-tools.js.map +0 -1
  116. package/dist/data/marketplaces.d.ts +0 -6
  117. package/dist/data/marketplaces.d.ts.map +0 -1
  118. package/dist/data/marketplaces.js.map +0 -1
  119. package/dist/data/mcp-servers.d.ts +0 -8
  120. package/dist/data/mcp-servers.d.ts.map +0 -1
  121. package/dist/data/mcp-servers.js +0 -503
  122. package/dist/data/mcp-servers.js.map +0 -1
  123. package/dist/data/statuslines.d.ts +0 -10
  124. package/dist/data/statuslines.d.ts.map +0 -1
  125. package/dist/data/statuslines.js +0 -160
  126. package/dist/data/statuslines.js.map +0 -1
  127. package/dist/index.d.ts +0 -3
  128. package/dist/index.d.ts.map +0 -1
  129. package/dist/index.js +0 -90
  130. package/dist/index.js.map +0 -1
  131. package/dist/main.d.ts +0 -3
  132. package/dist/main.d.ts.map +0 -1
  133. package/dist/main.js.map +0 -1
  134. package/dist/prerunner/index.d.ts +0 -7
  135. package/dist/prerunner/index.d.ts.map +0 -1
  136. package/dist/prerunner/index.js +0 -64
  137. package/dist/prerunner/index.js.map +0 -1
  138. package/dist/services/claude-runner.d.ts +0 -7
  139. package/dist/services/claude-runner.d.ts.map +0 -1
  140. package/dist/services/claude-runner.js.map +0 -1
  141. package/dist/services/claude-settings.d.ts +0 -73
  142. package/dist/services/claude-settings.d.ts.map +0 -1
  143. package/dist/services/claude-settings.js.map +0 -1
  144. package/dist/services/local-marketplace.d.ts +0 -111
  145. package/dist/services/local-marketplace.d.ts.map +0 -1
  146. package/dist/services/local-marketplace.js +0 -599
  147. package/dist/services/local-marketplace.js.map +0 -1
  148. package/dist/services/mcp-registry.d.ts +0 -10
  149. package/dist/services/mcp-registry.d.ts.map +0 -1
  150. package/dist/services/mcp-registry.js.map +0 -1
  151. package/dist/services/plugin-manager.d.ts +0 -65
  152. package/dist/services/plugin-manager.d.ts.map +0 -1
  153. package/dist/services/plugin-manager.js.map +0 -1
  154. package/dist/services/plugin-mcp-config.d.ts +0 -52
  155. package/dist/services/plugin-mcp-config.d.ts.map +0 -1
  156. package/dist/services/plugin-mcp-config.js.map +0 -1
  157. package/dist/services/update-cache.d.ts +0 -16
  158. package/dist/services/update-cache.d.ts.map +0 -1
  159. package/dist/services/update-cache.js.map +0 -1
  160. package/dist/services/version-check.d.ts +0 -20
  161. package/dist/services/version-check.d.ts.map +0 -1
  162. package/dist/services/version-check.js.map +0 -1
  163. package/dist/types/index.d.ts +0 -105
  164. package/dist/types/index.d.ts.map +0 -1
  165. package/dist/types/index.js +0 -2
  166. package/dist/types/index.js.map +0 -1
  167. package/dist/ui/InkApp.d.ts +0 -5
  168. package/dist/ui/InkApp.d.ts.map +0 -1
  169. package/dist/ui/InkApp.js +0 -188
  170. package/dist/ui/InkApp.js.map +0 -1
  171. package/dist/ui/components/CategoryHeader.d.ts +0 -16
  172. package/dist/ui/components/CategoryHeader.d.ts.map +0 -1
  173. package/dist/ui/components/CategoryHeader.js +0 -11
  174. package/dist/ui/components/CategoryHeader.js.map +0 -1
  175. package/dist/ui/components/ScrollableList.d.ts +0 -16
  176. package/dist/ui/components/ScrollableList.d.ts.map +0 -1
  177. package/dist/ui/components/ScrollableList.js.map +0 -1
  178. package/dist/ui/components/SearchInput.d.ts +0 -18
  179. package/dist/ui/components/SearchInput.d.ts.map +0 -1
  180. package/dist/ui/components/SearchInput.js +0 -30
  181. package/dist/ui/components/SearchInput.js.map +0 -1
  182. package/dist/ui/components/TabBar.d.ts +0 -8
  183. package/dist/ui/components/TabBar.d.ts.map +0 -1
  184. package/dist/ui/components/TabBar.js +0 -18
  185. package/dist/ui/components/TabBar.js.map +0 -1
  186. package/dist/ui/components/layout/Footer.d.ts +0 -14
  187. package/dist/ui/components/layout/Footer.d.ts.map +0 -1
  188. package/dist/ui/components/layout/Footer.js +0 -23
  189. package/dist/ui/components/layout/Footer.js.map +0 -1
  190. package/dist/ui/components/layout/Header.d.ts +0 -4
  191. package/dist/ui/components/layout/Header.d.ts.map +0 -1
  192. package/dist/ui/components/layout/Header.js +0 -25
  193. package/dist/ui/components/layout/Header.js.map +0 -1
  194. package/dist/ui/components/layout/Panel.d.ts +0 -22
  195. package/dist/ui/components/layout/Panel.d.ts.map +0 -1
  196. package/dist/ui/components/layout/Panel.js +0 -8
  197. package/dist/ui/components/layout/Panel.js.map +0 -1
  198. package/dist/ui/components/layout/ProgressBar.d.ts +0 -12
  199. package/dist/ui/components/layout/ProgressBar.d.ts.map +0 -1
  200. package/dist/ui/components/layout/ProgressBar.js +0 -16
  201. package/dist/ui/components/layout/ProgressBar.js.map +0 -1
  202. package/dist/ui/components/layout/ScopeTabs.d.ts +0 -12
  203. package/dist/ui/components/layout/ScopeTabs.d.ts.map +0 -1
  204. package/dist/ui/components/layout/ScopeTabs.js +0 -8
  205. package/dist/ui/components/layout/ScopeTabs.js.map +0 -1
  206. package/dist/ui/components/layout/ScreenLayout.d.ts +0 -30
  207. package/dist/ui/components/layout/ScreenLayout.d.ts.map +0 -1
  208. package/dist/ui/components/layout/ScreenLayout.js +0 -23
  209. package/dist/ui/components/layout/ScreenLayout.js.map +0 -1
  210. package/dist/ui/components/layout/index.d.ts +0 -7
  211. package/dist/ui/components/layout/index.d.ts.map +0 -1
  212. package/dist/ui/components/layout/index.js +0 -7
  213. package/dist/ui/components/layout/index.js.map +0 -1
  214. package/dist/ui/components/modals/ConfirmModal.d.ts +0 -14
  215. package/dist/ui/components/modals/ConfirmModal.d.ts.map +0 -1
  216. package/dist/ui/components/modals/ConfirmModal.js +0 -15
  217. package/dist/ui/components/modals/ConfirmModal.js.map +0 -1
  218. package/dist/ui/components/modals/InputModal.d.ts +0 -16
  219. package/dist/ui/components/modals/InputModal.d.ts.map +0 -1
  220. package/dist/ui/components/modals/InputModal.js +0 -23
  221. package/dist/ui/components/modals/InputModal.js.map +0 -1
  222. package/dist/ui/components/modals/LoadingModal.d.ts +0 -8
  223. package/dist/ui/components/modals/LoadingModal.d.ts.map +0 -1
  224. package/dist/ui/components/modals/LoadingModal.js +0 -8
  225. package/dist/ui/components/modals/LoadingModal.js.map +0 -1
  226. package/dist/ui/components/modals/MessageModal.d.ts +0 -14
  227. package/dist/ui/components/modals/MessageModal.d.ts.map +0 -1
  228. package/dist/ui/components/modals/MessageModal.js +0 -17
  229. package/dist/ui/components/modals/MessageModal.js.map +0 -1
  230. package/dist/ui/components/modals/ModalContainer.d.ts +0 -7
  231. package/dist/ui/components/modals/ModalContainer.d.ts.map +0 -1
  232. package/dist/ui/components/modals/ModalContainer.js +0 -38
  233. package/dist/ui/components/modals/ModalContainer.js.map +0 -1
  234. package/dist/ui/components/modals/SelectModal.d.ts +0 -17
  235. package/dist/ui/components/modals/SelectModal.d.ts.map +0 -1
  236. package/dist/ui/components/modals/SelectModal.js +0 -33
  237. package/dist/ui/components/modals/SelectModal.js.map +0 -1
  238. package/dist/ui/components/modals/index.d.ts +0 -7
  239. package/dist/ui/components/modals/index.d.ts.map +0 -1
  240. package/dist/ui/components/modals/index.js +0 -7
  241. package/dist/ui/components/modals/index.js.map +0 -1
  242. package/dist/ui/hooks/index.d.ts +0 -3
  243. package/dist/ui/hooks/index.d.ts.map +0 -1
  244. package/dist/ui/hooks/index.js +0 -3
  245. package/dist/ui/hooks/index.js.map +0 -1
  246. package/dist/ui/hooks/useAsyncData.d.ts +0 -40
  247. package/dist/ui/hooks/useAsyncData.d.ts.map +0 -1
  248. package/dist/ui/hooks/useAsyncData.js.map +0 -1
  249. package/dist/ui/hooks/useKeyboardNavigation.d.ts +0 -27
  250. package/dist/ui/hooks/useKeyboardNavigation.d.ts.map +0 -1
  251. package/dist/ui/hooks/useKeyboardNavigation.js +0 -82
  252. package/dist/ui/hooks/useKeyboardNavigation.js.map +0 -1
  253. package/dist/ui/screens/CliToolsScreen.d.ts +0 -4
  254. package/dist/ui/screens/CliToolsScreen.d.ts.map +0 -1
  255. package/dist/ui/screens/CliToolsScreen.js.map +0 -1
  256. package/dist/ui/screens/EnvVarsScreen.d.ts +0 -4
  257. package/dist/ui/screens/EnvVarsScreen.d.ts.map +0 -1
  258. package/dist/ui/screens/EnvVarsScreen.js +0 -145
  259. package/dist/ui/screens/EnvVarsScreen.js.map +0 -1
  260. package/dist/ui/screens/McpRegistryScreen.d.ts +0 -4
  261. package/dist/ui/screens/McpRegistryScreen.d.ts.map +0 -1
  262. package/dist/ui/screens/McpRegistryScreen.js.map +0 -1
  263. package/dist/ui/screens/McpScreen.d.ts +0 -4
  264. package/dist/ui/screens/McpScreen.d.ts.map +0 -1
  265. package/dist/ui/screens/McpScreen.js.map +0 -1
  266. package/dist/ui/screens/ModelSelectorScreen.d.ts +0 -4
  267. package/dist/ui/screens/ModelSelectorScreen.d.ts.map +0 -1
  268. package/dist/ui/screens/ModelSelectorScreen.js +0 -143
  269. package/dist/ui/screens/ModelSelectorScreen.js.map +0 -1
  270. package/dist/ui/screens/PluginsScreen.d.ts +0 -4
  271. package/dist/ui/screens/PluginsScreen.d.ts.map +0 -1
  272. package/dist/ui/screens/PluginsScreen.js.map +0 -1
  273. package/dist/ui/screens/StatusLineScreen.d.ts +0 -4
  274. package/dist/ui/screens/StatusLineScreen.d.ts.map +0 -1
  275. package/dist/ui/screens/StatusLineScreen.js +0 -197
  276. package/dist/ui/screens/StatusLineScreen.js.map +0 -1
  277. package/dist/ui/screens/index.d.ts +0 -8
  278. package/dist/ui/screens/index.d.ts.map +0 -1
  279. package/dist/ui/screens/index.js +0 -8
  280. package/dist/ui/screens/index.js.map +0 -1
  281. package/dist/ui/state/AppContext.d.ts +0 -40
  282. package/dist/ui/state/AppContext.d.ts.map +0 -1
  283. package/dist/ui/state/AppContext.js.map +0 -1
  284. package/dist/ui/state/DimensionsContext.d.ts +0 -27
  285. package/dist/ui/state/DimensionsContext.d.ts.map +0 -1
  286. package/dist/ui/state/DimensionsContext.js.map +0 -1
  287. package/dist/ui/state/reducer.d.ts +0 -4
  288. package/dist/ui/state/reducer.d.ts.map +0 -1
  289. package/dist/ui/state/reducer.js.map +0 -1
  290. package/dist/ui/state/types.d.ts +0 -266
  291. package/dist/ui/state/types.d.ts.map +0 -1
  292. package/dist/ui/state/types.js +0 -2
  293. package/dist/ui/state/types.js.map +0 -1
  294. package/dist/utils/command-utils.d.ts +0 -8
  295. package/dist/utils/command-utils.d.ts.map +0 -1
  296. package/dist/utils/command-utils.js.map +0 -1
  297. package/dist/utils/fuzzy-search.d.ts +0 -33
  298. package/dist/utils/fuzzy-search.d.ts.map +0 -1
  299. package/dist/utils/fuzzy-search.js.map +0 -1
  300. package/dist/utils/string-utils.d.ts +0 -24
  301. package/dist/utils/string-utils.d.ts.map +0 -1
  302. 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 'react';
3
- import { Box, Text, useInput } from 'ink';
4
- import { useApp, useModal, useProgress } from '../state/AppContext.js';
5
- import { useDimensions } from '../state/DimensionsContext.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 { addMarketplace, removeMarketplace, addGlobalMarketplace, removeGlobalMarketplace, enablePlugin, enableGlobalPlugin, enableLocalPlugin, saveGlobalInstalledPluginVersion, removeGlobalInstalledPluginVersion, saveLocalInstalledPluginVersion, removeLocalInstalledPluginVersion, setMcpEnvVar, getMcpEnvVars, } from '../../services/claude-settings.js';
13
- import { getPluginEnvRequirements, getPluginSourcePath, } from '../../services/plugin-mcp-config.js';
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 && state.currentRoute.screen === 'plugins' && !state.modal;
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: 'PLUGINS_DATA_LOADING' });
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: 'PLUGINS_DATA_SUCCESS',
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: 'PLUGINS_DATA_ERROR',
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 !== 'success' || pluginsState.plugins.status !== 'success') {
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 === 'claude-code-plugins' ? 1 : 0;
64
- const bDeprecated = b.name === 'claude-code-plugins' ? 1 : 0;
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: 'category',
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: 'plugin',
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
- }, [pluginsState.marketplaces, pluginsState.plugins, pluginsState.collapsedMarketplaces]);
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 === 'plugin');
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 === 'category' && item.marketplace) {
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 === 'plugin' && item.plugin) {
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 === 'plugin' || item.type === 'category');
144
+ return filteredItems.filter((item) => item.type === "plugin" || item.type === "category");
139
145
  }, [filteredItems]);
140
146
  // Keyboard handling
141
- useInput((input, key) => {
147
+ useKeyboard((event) => {
142
148
  // Handle search mode
143
149
  if (isSearchActive) {
144
- if (key.escape) {
145
- dispatch({ type: 'SET_SEARCHING', isSearching: false });
146
- dispatch({ type: 'PLUGINS_SET_SEARCH', query: '' });
150
+ if (event.name === "escape") {
151
+ dispatch({ type: "SET_SEARCHING", isSearching: false });
152
+ dispatch({ type: "PLUGINS_SET_SEARCH", query: "" });
147
153
  }
148
- else if (key.return) {
149
- dispatch({ type: 'SET_SEARCHING', isSearching: false });
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 (key.backspace || key.delete) {
153
- dispatch({ type: 'PLUGINS_SET_SEARCH', query: pluginsState.searchQuery.slice(0, -1) });
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 (input && !key.ctrl && !key.meta) {
156
- dispatch({ type: 'PLUGINS_SET_SEARCH', query: pluginsState.searchQuery + input });
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 (input === '/') {
164
- dispatch({ type: 'SET_SEARCHING', isSearching: true });
175
+ if (event.name === "/") {
176
+ dispatch({ type: "SET_SEARCHING", isSearching: true });
165
177
  return;
166
178
  }
167
179
  // Navigation
168
- if (key.upArrow || input === 'k') {
180
+ if (event.name === "up" || event.name === "k") {
169
181
  const newIndex = Math.max(0, pluginsState.selectedIndex - 1);
170
- dispatch({ type: 'PLUGINS_SELECT', index: newIndex });
182
+ dispatch({ type: "PLUGINS_SELECT", index: newIndex });
171
183
  }
172
- else if (key.downArrow || input === 'j') {
184
+ else if (event.name === "down" || event.name === "j") {
173
185
  const newIndex = Math.min(selectableItems.length - 1, pluginsState.selectedIndex + 1);
174
- dispatch({ type: 'PLUGINS_SELECT', index: newIndex });
186
+ dispatch({ type: "PLUGINS_SELECT", index: newIndex });
175
187
  }
176
188
  // Collapse/expand marketplace
177
- else if ((key.leftArrow || key.rightArrow || input === '<' || input === '>') && selectableItems[pluginsState.selectedIndex]?.marketplace) {
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({ type: 'PLUGINS_TOGGLE_MARKETPLACE', name: item.marketplace.name });
193
+ dispatch({
194
+ type: "PLUGINS_TOGGLE_MARKETPLACE",
195
+ name: item.marketplace.name,
196
+ });
181
197
  }
182
198
  }
183
199
  // Refresh
184
- else if (input === 'r') {
200
+ else if (event.name === "r") {
185
201
  handleRefresh();
186
202
  }
187
- // New marketplace
188
- else if (input === 'n') {
189
- handleAddMarketplace();
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 (input === 'u') {
193
- handleScopeToggle('user');
212
+ else if (event.name === "u") {
213
+ handleScopeToggle("user");
194
214
  }
195
- else if (input === 'p') {
196
- handleScopeToggle('project');
215
+ else if (event.name === "p") {
216
+ handleScopeToggle("project");
197
217
  }
198
- else if (input === 'l') {
199
- handleScopeToggle('local');
218
+ else if (event.name === "l") {
219
+ handleScopeToggle("local");
200
220
  }
201
221
  // Update plugin (Shift+U)
202
- else if (input === 'U') {
222
+ else if (event.name === "U") {
203
223
  handleUpdate();
204
224
  }
205
225
  // Update all
206
- else if (input === 'a') {
226
+ else if (event.name === "a") {
207
227
  handleUpdateAll();
208
228
  }
209
229
  // Delete/uninstall
210
- else if (input === 'd') {
230
+ else if (event.name === "d") {
211
231
  handleUninstall();
212
232
  }
213
233
  // Enter for selection
214
- else if (key.return) {
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('Refreshing marketplaces...');
240
+ progress.show("Refreshing cache...");
221
241
  try {
222
242
  const result = await refreshAllMarketplaces((p) => {
223
- progress.show(`Refreshing ${p.name}...`, p.current, p.total);
243
+ progress.show(`${p.name}`, p.current, p.total);
224
244
  });
225
245
  clearMarketplaceCache();
226
246
  progress.hide();
227
- // Build success message with repair info
228
- let message = 'Marketplaces refreshed successfully.';
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('Refreshed', message, 'success');
256
+ await modal.message("Refreshed", message, "success");
246
257
  fetchData();
247
258
  }
248
259
  catch (error) {
249
260
  progress.hide();
250
- await modal.message('Error', `Refresh failed: ${error}`, 'error');
261
+ await modal.message("Error", `Refresh failed: ${error}`, "error");
251
262
  }
252
263
  };
253
- const handleAddMarketplace = async () => {
254
- const repo = await modal.input('Add Marketplace', 'GitHub repo (owner/repo):');
255
- if (!repo || !repo.trim())
256
- return;
257
- progress.show('Cloning marketplace...');
258
- try {
259
- const result = await cloneMarketplace(repo.trim());
260
- if (result.success) {
261
- const normalizedRepo = repo.trim().replace(/^https:\/\/github\.com\//, '').replace(/\.git$/, '');
262
- const marketplace = {
263
- name: result.name,
264
- displayName: result.name,
265
- source: { source: 'github', repo: normalizedRepo },
266
- description: '',
267
- official: false,
268
- };
269
- if (pluginsState.scope === 'global') {
270
- await addGlobalMarketplace(marketplace);
271
- }
272
- else {
273
- await addMarketplace(marketplace, state.projectPath);
274
- }
275
- await addToKnownMarketplaces(result.name, normalizedRepo);
276
- clearMarketplaceCache();
277
- progress.hide();
278
- await modal.message('Added', `${result.name} marketplace added.`, 'success');
279
- fetchData();
280
- }
281
- else {
282
- progress.hide();
283
- await modal.message('Failed', result.error || 'Clone failed', 'error');
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('Configure MCP Servers?', `This plugin includes MCP servers (${serverNames.join(', ')}) that need ${missingVars.length} environment variable(s).\n\nConfigure now?`);
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('Skipped Configuration', 'You can configure these variables later in the Environment Variables screen (press 4).', 'info');
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('Configuration Incomplete', `Skipped remaining configuration.\nYou can configure these later in Environment Variables (press 4).`, 'info');
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('Error collecting plugin env vars:', 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 === 'category' && item.marketplace) {
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: 'PLUGINS_TOGGLE_MARKETPLACE', name: mp.name });
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: 'PLUGINS_TOGGLE_MARKETPLACE', name: mp.name });
368
+ dispatch({ type: "PLUGINS_TOGGLE_MARKETPLACE", name: mp.name });
363
369
  }
364
370
  else {
365
- // If expanded with no plugins, offer to remove
366
- const confirmed = await modal.confirm(`Remove ${mp.displayName}?`, 'Plugins from this marketplace will no longer be available.');
367
- if (confirmed) {
368
- modal.loading(`Removing ${mp.displayName}...`);
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
- // Add marketplace
392
- modal.loading(`Adding ${mp.displayName}...`);
393
- try {
394
- if (isGlobal) {
395
- await addGlobalMarketplace(mp);
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 === 'plugin' && item.plugin) {
385
+ else if (item.type === "plugin" && item.plugin) {
410
386
  const plugin = item.plugin;
411
- const latestVersion = plugin.version || '0.0.0';
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 && latestVersion && ver !== latestVersion && latestVersion !== '0.0.0';
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
- { label: buildScopeLabel('User', plugin.userScope, 'global'), value: 'user' },
427
- { label: buildScopeLabel('Project', plugin.projectScope, 'team'), value: 'project' },
428
- { label: buildScopeLabel('Local', plugin.localScope, 'private'), value: 'local' },
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 === 'user' ? plugin.userScope :
435
- scopeValue === 'project' ? plugin.projectScope :
436
- plugin.localScope;
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 === 'user' ? 'User' : scopeValue === 'project' ? 'Project' : 'Local';
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 && installedVersion &&
442
- latestVersion !== '0.0.0' &&
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 = 'update';
442
+ action = "update";
448
443
  }
449
444
  else if (isInstalledInScope) {
450
- action = 'uninstall';
445
+ action = "uninstall";
451
446
  }
452
447
  else {
453
- action = 'install';
448
+ action = "install";
454
449
  }
455
- const actionLabel = action === 'update' ? `Updating ${scopeLabel}` :
456
- action === 'install' ? `Installing to ${scopeLabel}` :
457
- `Uninstalling from ${scopeLabel}`;
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 === 'uninstall') {
457
+ if (action === "uninstall") {
461
458
  // Uninstall from this scope
462
- if (scopeValue === 'user') {
459
+ if (scopeValue === "user") {
463
460
  await enableGlobalPlugin(plugin.id, false);
464
461
  await removeGlobalInstalledPluginVersion(plugin.id);
465
462
  }
466
- else if (scopeValue === 'project') {
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 === 'user') {
474
+ if (scopeValue === "user") {
478
475
  await enableGlobalPlugin(plugin.id, true);
479
476
  await saveGlobalInstalledPluginVersion(plugin.id, latestVersion);
480
477
  }
481
- else if (scopeValue === 'project') {
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 === 'install') {
487
+ if (action === "install") {
491
488
  modal.hideModal();
492
489
  await collectPluginEnvVars(plugin.name, plugin.marketplace);
493
490
  }
494
491
  }
495
- if (action !== 'install') {
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('Error', `Failed: ${error}`, 'error');
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 !== 'plugin' || !item.plugin?.hasUpdate)
505
+ if (!item || item.type !== "plugin" || !item.plugin?.hasUpdate)
509
506
  return;
510
507
  const plugin = item.plugin;
511
- const isGlobal = pluginsState.scope === 'global';
508
+ const isGlobal = pluginsState.scope === "global";
512
509
  modal.loading(`Updating ${plugin.name}...`);
513
510
  try {
514
- const versionToSave = plugin.version || '0.0.0';
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('Error', `Failed to update: ${error}`, 'error');
523
+ await modal.message("Error", `Failed to update: ${error}`, "error");
527
524
  }
528
525
  };
529
526
  const handleUpdateAll = async () => {
530
- if (pluginsState.plugins.status !== 'success')
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 === 'global';
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 || '0.0.0';
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('Error', `Failed to update: ${error}`, 'error');
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 !== 'plugin' || !item.plugin)
555
+ if (!item || item.type !== "plugin" || !item.plugin)
559
556
  return;
560
557
  const plugin = item.plugin;
561
- const latestVersion = plugin.version || '0.0.0';
562
- const scopeLabel = scope === 'user' ? 'User' : scope === 'project' ? 'Project' : 'Local';
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 === 'user' ? plugin.userScope :
565
- scope === 'project' ? plugin.projectScope :
566
- plugin.localScope;
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 && installedVersion &&
571
- latestVersion !== '0.0.0' &&
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 = 'update';
576
+ action = "update";
577
577
  }
578
578
  else if (isInstalledInScope) {
579
- action = 'uninstall';
579
+ action = "uninstall";
580
580
  }
581
581
  else {
582
- action = 'install';
582
+ action = "install";
583
583
  }
584
- const actionLabel = action === 'update' ? `Updating ${scopeLabel}` :
585
- action === 'install' ? `Installing to ${scopeLabel}` :
586
- `Uninstalling from ${scopeLabel}`;
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 === 'uninstall') {
591
+ if (action === "uninstall") {
590
592
  // Uninstall from this scope
591
- if (scope === 'user') {
593
+ if (scope === "user") {
592
594
  await enableGlobalPlugin(plugin.id, false);
593
595
  await removeGlobalInstalledPluginVersion(plugin.id);
594
596
  }
595
- else if (scope === 'project') {
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 === 'user') {
608
+ if (scope === "user") {
607
609
  await enableGlobalPlugin(plugin.id, true);
608
610
  await saveGlobalInstalledPluginVersion(plugin.id, latestVersion);
609
611
  }
610
- else if (scope === 'project') {
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 === 'install') {
621
+ if (action === "install") {
620
622
  modal.hideModal();
621
623
  await collectPluginEnvVars(plugin.name, plugin.marketplace);
622
624
  }
623
625
  }
624
- if (action !== 'install') {
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('Error', `Failed: ${error}`, 'error');
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 !== 'plugin' || !item.plugin)
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 ? ` v${plugin.userScope.version}` : '';
643
- installedScopes.push({ label: `User (global)${ver}`, value: 'user' });
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 ? ` v${plugin.projectScope.version}` : '';
647
- installedScopes.push({ label: `Project${ver}`, value: 'project' });
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 ? ` v${plugin.localScope.version}` : '';
651
- installedScopes.push({ label: `Local${ver}`, value: 'local' });
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('Not Installed', `${plugin.name} is not installed in any scope.`, 'info');
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 === 'user') {
670
+ if (scopeValue === "user") {
663
671
  await enableGlobalPlugin(plugin.id, false);
664
672
  await removeGlobalInstalledPluginVersion(plugin.id);
665
673
  }
666
- else if (scopeValue === 'project') {
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('Error', `Failed to uninstall: ${error}`, 'error');
688
+ await modal.message("Error", `Failed to uninstall: ${error}`, "error");
681
689
  }
682
690
  };
683
691
  // Render loading state
684
- if (pluginsState.marketplaces.status === 'loading' || pluginsState.plugins.status === 'loading') {
685
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "#7e57c2", bold: true, children: "claudeup Plugins" }), _jsx(Text, { color: "gray", children: "Loading..." })] }));
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 === 'error' || pluginsState.plugins.status === 'error') {
689
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "#7e57c2", bold: true, children: "claudeup Plugins" }), _jsx(Text, { color: "red", children: "Error loading data" })] }));
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 === 'category' && item.marketplace) {
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 = 'green';
708
+ let statusText = "";
709
+ let statusColor = "green";
700
710
  if (item.marketplaceEnabled) {
701
- if (mp.name === 'claude-plugins-official') {
702
- statusText = '★ Official';
703
- statusColor = 'yellow';
711
+ if (mp.name === "claude-plugins-official") {
712
+ statusText = "★ Official";
713
+ statusColor = "yellow";
704
714
  }
705
- else if (mp.name === 'claude-code-plugins') {
706
- statusText = '⚠ Deprecated';
707
- statusColor = 'gray';
715
+ else if (mp.name === "claude-code-plugins") {
716
+ statusText = "⚠ Deprecated";
717
+ statusColor = "gray";
708
718
  }
709
719
  else if (mp.official) {
710
- statusText = '★ Official';
711
- statusColor = 'yellow';
720
+ statusText = "★ Official";
721
+ statusColor = "yellow";
712
722
  }
713
723
  else {
714
- statusText = '✓ Added';
715
- statusColor = 'green';
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 ? ` (${item.pluginCount})` : '';
721
- return (_jsx(Text, { backgroundColor: "magenta", color: "white", bold: true, children: ` ${arrow} ${mp.displayName}${count} ` }));
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 === 'plugin' && item.plugin) {
737
+ if (item.type === "plugin" && item.plugin) {
726
738
  const plugin = item.plugin;
727
- let statusIcon = '';
728
- let statusColor = 'gray';
739
+ let statusIcon = "";
740
+ let statusColor = "gray";
729
741
  if (plugin.enabled) {
730
- statusIcon = '';
731
- statusColor = 'green';
742
+ statusIcon = "";
743
+ statusColor = "green";
732
744
  }
733
745
  else if (plugin.installedVersion) {
734
- statusIcon = '';
735
- statusColor = 'yellow';
746
+ statusIcon = "";
747
+ statusColor = "yellow";
736
748
  }
737
749
  // Build version string
738
- let versionStr = '';
739
- if (plugin.installedVersion && plugin.installedVersion !== '0.0.0') {
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(Text, { backgroundColor: "magenta", color: "white", wrap: "truncate", children: displayText }));
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(Text, { wrap: "truncate", children: [_jsxs(Text, { color: statusColor, children: [' ', statusIcon, " "] }), _jsx(Text, { children: displayName }), _jsx(Text, { color: plugin.hasUpdate ? 'yellow' : 'gray', children: versionStr })] }));
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(Text, { color: "gray", children: item.label });
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(Text, { color: "gray", children: "Select an item" });
775
+ return _jsx("text", { fg: "gray", children: "Select an item" });
764
776
  }
765
- if (selectedItem.type === 'category' && selectedItem.marketplace) {
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 === 'claude-plugins-official')
771
- return '';
772
- if (mp.name === 'claude-code-plugins')
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 = 'Add';
793
+ let actionHint = "Add";
782
794
  if (isEnabled) {
783
795
  if (isCollapsed) {
784
- actionHint = 'Expand';
796
+ actionHint = "Expand";
785
797
  }
786
798
  else if (hasPlugins) {
787
- actionHint = 'Collapse';
799
+ actionHint = "Collapse";
788
800
  }
789
801
  else {
790
- actionHint = 'Remove';
802
+ actionHint = "Remove";
791
803
  }
792
804
  }
793
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, color: "cyan", children: [mp.displayName, getBadge()] }), _jsx(Text, { color: "gray", wrap: "wrap", children: mp.description || 'No description' }), _jsx(Text, { color: isEnabled ? 'green' : 'gray', children: isEnabled ? '● Added' : '○ Not added' }), _jsxs(Text, { color: "blue", wrap: "wrap", children: ["github.com/", mp.source.repo] }), _jsxs(Text, { children: ["Plugins: ", selectedItem.pluginCount || 0] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { backgroundColor: isEnabled ? 'cyan' : 'green', color: "black", children: " Enter " }), _jsxs(Text, { color: "gray", children: [" ", actionHint] })] }), isEnabled && (_jsx(Box, { children: _jsx(Text, { color: "gray", children: "\u2190 \u2192 to expand/collapse" }) }))] }));
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 === 'plugin' && selectedItem.plugin) {
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 !== '0.0.0';
813
- const showInstalledVersion = plugin.installedVersion && plugin.installedVersion !== '0.0.0';
814
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { justifyContent: "center", children: _jsx(Text, { backgroundColor: "magenta", color: "white", bold: true, children: ` ${plugin.name}${plugin.hasUpdate ? ' ⬆' : ''} ` }) }), _jsx(Box, { marginTop: 1, children: isInstalled ? (_jsx(Text, { color: plugin.enabled ? 'green' : 'yellow', children: plugin.enabled ? '● Enabled' : '● Disabled' })) : (_jsx(Text, { color: "gray", children: "\u25CB Not installed" })) }), _jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { color: "white", wrap: "wrap", children: plugin.description }) }), showVersion && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Version " }), _jsxs(Text, { color: "blue", children: ["v", plugin.version] }), showInstalledVersion && plugin.installedVersion !== plugin.version && _jsxs(Text, { dimColor: true, children: [" (v", plugin.installedVersion, " installed)"] })] })), plugin.category && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Category " }), _jsx(Text, { color: "magenta", children: plugin.category })] })), plugin.author && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Author " }), _jsx(Text, { children: plugin.author.name })] })), components.length > 0 && (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Contains " }), _jsx(Text, { color: "yellow", children: components.join(' · ') })] })), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, 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, { bold: true, children: "Scopes:" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { backgroundColor: "cyan", color: "black", children: " u " }), _jsx(Text, { color: plugin.userScope?.enabled ? 'cyan' : 'gray', children: plugin.userScope?.enabled ? ' ● ' : ' ○ ' }), _jsx(Text, { color: "cyan", children: "User" }), _jsx(Text, { dimColor: true, children: " global" }), plugin.userScope?.version && _jsxs(Text, { color: "cyan", children: [" v", plugin.userScope.version] })] }), _jsxs(Box, { children: [_jsx(Text, { backgroundColor: "green", color: "black", children: " p " }), _jsx(Text, { color: plugin.projectScope?.enabled ? 'green' : 'gray', children: plugin.projectScope?.enabled ? ' ● ' : ' ○ ' }), _jsx(Text, { color: "green", children: "Project" }), _jsx(Text, { dimColor: true, children: " team" }), plugin.projectScope?.version && _jsxs(Text, { color: "green", children: [" v", plugin.projectScope.version] })] }), _jsxs(Box, { children: [_jsx(Text, { backgroundColor: "yellow", color: "black", children: " l " }), _jsx(Text, { color: plugin.localScope?.enabled ? 'yellow' : 'gray', children: plugin.localScope?.enabled ? ' ● ' : ' ○ ' }), _jsx(Text, { color: "yellow", children: "Local" }), _jsx(Text, { dimColor: true, children: " private" }), plugin.localScope?.version && _jsxs(Text, { color: "yellow", children: [" v", plugin.localScope.version] })] })] })] }), isInstalled && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [plugin.hasUpdate && (_jsxs(Box, { children: [_jsx(Text, { backgroundColor: "magenta", color: "white", children: " U " }), _jsxs(Text, { children: [" Update to v", plugin.version] })] })), _jsxs(Box, { children: [_jsx(Text, { backgroundColor: "red", color: "white", children: " d " }), _jsx(Text, { children: " Uninstall" })] })] }))] }));
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
- ? 'Type to search │ Enter Confirm │ Esc Cancel'
820
- : 'u/p/l:scope │ U:update │ a:all │ d:remove │ /:search';
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 === 'global' ? 'Global' : 'Project';
823
- const plugins = pluginsState.plugins.status === 'success' ? pluginsState.plugins.data : [];
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} ⬆` : ''} │ / to search`;
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