claudeup 3.9.0 → 3.10.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/package.json +1 -1
- package/src/data/skill-repos.js +15 -15
- package/src/data/skill-repos.ts +15 -15
- package/src/services/skills-manager.js +124 -56
- package/src/services/skills-manager.ts +131 -58
- package/src/types/index.ts +4 -0
- package/src/ui/App.js +9 -9
- package/src/ui/App.tsx +9 -9
- package/src/ui/components/EmptyFilterState.js +4 -0
- package/src/ui/components/EmptyFilterState.tsx +27 -0
- package/src/ui/components/TabBar.js +4 -4
- package/src/ui/components/TabBar.tsx +4 -4
- package/src/ui/screens/PluginsScreen.js +17 -35
- package/src/ui/screens/PluginsScreen.tsx +25 -43
- package/src/ui/screens/SkillsScreen.js +248 -143
- package/src/ui/screens/SkillsScreen.tsx +316 -163
package/src/ui/App.js
CHANGED
|
@@ -92,24 +92,24 @@ function GlobalKeyHandler({ onDebugToggle, onExit, }) {
|
|
|
92
92
|
if (input === "1")
|
|
93
93
|
navigateToScreen("plugins");
|
|
94
94
|
else if (input === "2")
|
|
95
|
-
navigateToScreen("
|
|
95
|
+
navigateToScreen("skills");
|
|
96
96
|
else if (input === "3")
|
|
97
|
-
navigateToScreen("
|
|
97
|
+
navigateToScreen("mcp");
|
|
98
98
|
else if (input === "4")
|
|
99
|
-
navigateToScreen("
|
|
99
|
+
navigateToScreen("settings");
|
|
100
100
|
else if (input === "5")
|
|
101
101
|
navigateToScreen("profiles");
|
|
102
102
|
else if (input === "6")
|
|
103
|
-
navigateToScreen("
|
|
103
|
+
navigateToScreen("cli-tools");
|
|
104
104
|
// Tab navigation cycling
|
|
105
105
|
if (key.tab) {
|
|
106
106
|
const screens = [
|
|
107
107
|
"plugins",
|
|
108
|
+
"skills",
|
|
108
109
|
"mcp",
|
|
109
110
|
"settings",
|
|
110
|
-
"cli-tools",
|
|
111
111
|
"profiles",
|
|
112
|
-
"
|
|
112
|
+
"cli-tools",
|
|
113
113
|
];
|
|
114
114
|
const currentIndex = screens.indexOf(state.currentRoute.screen);
|
|
115
115
|
if (currentIndex !== -1) {
|
|
@@ -144,9 +144,9 @@ function GlobalKeyHandler({ onDebugToggle, onExit, }) {
|
|
|
144
144
|
? This help
|
|
145
145
|
|
|
146
146
|
Quick Navigation
|
|
147
|
-
1 Plugins 4
|
|
148
|
-
2
|
|
149
|
-
3
|
|
147
|
+
1 Plugins 4 Settings
|
|
148
|
+
2 Skills 5 Profiles
|
|
149
|
+
3 MCP Servers 6 CLI Tools
|
|
150
150
|
|
|
151
151
|
Plugin Actions
|
|
152
152
|
u Update d Uninstall
|
package/src/ui/App.tsx
CHANGED
|
@@ -124,21 +124,21 @@ function GlobalKeyHandler({
|
|
|
124
124
|
|
|
125
125
|
if (isTopLevel) {
|
|
126
126
|
if (input === "1") navigateToScreen("plugins");
|
|
127
|
-
else if (input === "2") navigateToScreen("
|
|
128
|
-
else if (input === "3") navigateToScreen("
|
|
129
|
-
else if (input === "4") navigateToScreen("
|
|
127
|
+
else if (input === "2") navigateToScreen("skills");
|
|
128
|
+
else if (input === "3") navigateToScreen("mcp");
|
|
129
|
+
else if (input === "4") navigateToScreen("settings");
|
|
130
130
|
else if (input === "5") navigateToScreen("profiles");
|
|
131
|
-
else if (input === "6") navigateToScreen("
|
|
131
|
+
else if (input === "6") navigateToScreen("cli-tools");
|
|
132
132
|
|
|
133
133
|
// Tab navigation cycling
|
|
134
134
|
if (key.tab) {
|
|
135
135
|
const screens: Screen[] = [
|
|
136
136
|
"plugins",
|
|
137
|
+
"skills",
|
|
137
138
|
"mcp",
|
|
138
139
|
"settings",
|
|
139
|
-
"cli-tools",
|
|
140
140
|
"profiles",
|
|
141
|
-
"
|
|
141
|
+
"cli-tools",
|
|
142
142
|
];
|
|
143
143
|
const currentIndex = screens.indexOf(
|
|
144
144
|
state.currentRoute.screen as Screen,
|
|
@@ -177,9 +177,9 @@ function GlobalKeyHandler({
|
|
|
177
177
|
? This help
|
|
178
178
|
|
|
179
179
|
Quick Navigation
|
|
180
|
-
1 Plugins 4
|
|
181
|
-
2
|
|
182
|
-
3
|
|
180
|
+
1 Plugins 4 Settings
|
|
181
|
+
2 Skills 5 Profiles
|
|
182
|
+
3 MCP Servers 6 CLI Tools
|
|
183
183
|
|
|
184
184
|
Plugin Actions
|
|
185
185
|
u Update d Uninstall
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "@opentui/react/jsx-runtime";
|
|
2
|
+
export function EmptyFilterState({ query, entityName = "items", }) {
|
|
3
|
+
return (_jsxs("box", { flexDirection: "column", marginTop: 2, paddingLeft: 2, paddingRight: 2, children: [_jsxs("text", { fg: "yellow", children: ["No ", entityName, " found for \"", query, "\""] }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: "Try a different search term, or if you think" }) }), _jsx("text", { fg: "gray", children: "this is a bug, report it at:" }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "#5c9aff", children: "github.com/MadAppGang/magus/issues" }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: "Press Esc to clear the filter." }) })] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
interface EmptyFilterStateProps {
|
|
4
|
+
query: string;
|
|
5
|
+
entityName?: string; // "plugins", "skills", "MCP servers"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function EmptyFilterState({
|
|
9
|
+
query,
|
|
10
|
+
entityName = "items",
|
|
11
|
+
}: EmptyFilterStateProps) {
|
|
12
|
+
return (
|
|
13
|
+
<box flexDirection="column" marginTop={2} paddingLeft={2} paddingRight={2}>
|
|
14
|
+
<text fg="yellow">No {entityName} found for "{query}"</text>
|
|
15
|
+
<box marginTop={1}>
|
|
16
|
+
<text fg="gray">Try a different search term, or if you think</text>
|
|
17
|
+
</box>
|
|
18
|
+
<text fg="gray">this is a bug, report it at:</text>
|
|
19
|
+
<box marginTop={1}>
|
|
20
|
+
<text fg="#5c9aff">github.com/MadAppGang/magus/issues</text>
|
|
21
|
+
</box>
|
|
22
|
+
<box marginTop={1}>
|
|
23
|
+
<text fg="gray">Press Esc to clear the filter.</text>
|
|
24
|
+
</box>
|
|
25
|
+
</box>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -2,11 +2,11 @@ import { jsxs as _jsxs, jsx as _jsx } from "@opentui/react/jsx-runtime";
|
|
|
2
2
|
import { useKeyboardHandler } from "../hooks/useKeyboardHandler";
|
|
3
3
|
const TABS = [
|
|
4
4
|
{ key: "1", label: "Plugins", screen: "plugins" },
|
|
5
|
-
{ key: "2", label: "
|
|
6
|
-
{ key: "3", label: "
|
|
7
|
-
{ key: "4", label: "
|
|
5
|
+
{ key: "2", label: "Skills", screen: "skills" },
|
|
6
|
+
{ key: "3", label: "MCP", screen: "mcp" },
|
|
7
|
+
{ key: "4", label: "Settings", screen: "settings" },
|
|
8
8
|
{ key: "5", label: "Profiles", screen: "profiles" },
|
|
9
|
-
{ key: "6", label: "
|
|
9
|
+
{ key: "6", label: "CLI", screen: "cli-tools" },
|
|
10
10
|
];
|
|
11
11
|
export function TabBar({ currentScreen, onTabChange }) {
|
|
12
12
|
// Handle number key shortcuts (1-5)
|
|
@@ -10,11 +10,11 @@ interface Tab {
|
|
|
10
10
|
|
|
11
11
|
const TABS: Tab[] = [
|
|
12
12
|
{ key: "1", label: "Plugins", screen: "plugins" },
|
|
13
|
-
{ key: "2", label: "
|
|
14
|
-
{ key: "3", label: "
|
|
15
|
-
{ key: "4", label: "
|
|
13
|
+
{ key: "2", label: "Skills", screen: "skills" },
|
|
14
|
+
{ key: "3", label: "MCP", screen: "mcp" },
|
|
15
|
+
{ key: "4", label: "Settings", screen: "settings" },
|
|
16
16
|
{ key: "5", label: "Profiles", screen: "profiles" },
|
|
17
|
-
{ key: "6", label: "
|
|
17
|
+
{ key: "6", label: "CLI", screen: "cli-tools" },
|
|
18
18
|
];
|
|
19
19
|
|
|
20
20
|
interface TabBarProps {
|
|
@@ -6,6 +6,7 @@ import { useKeyboard } from "../hooks/useKeyboard.js";
|
|
|
6
6
|
import { ScreenLayout } from "../components/layout/index.js";
|
|
7
7
|
import { CategoryHeader } from "../components/CategoryHeader.js";
|
|
8
8
|
import { ScrollableList } from "../components/ScrollableList.js";
|
|
9
|
+
import { EmptyFilterState } from "../components/EmptyFilterState.js";
|
|
9
10
|
import { fuzzyFilter, highlightMatches } from "../../utils/fuzzy-search.js";
|
|
10
11
|
import { getAllMarketplaces } from "../../data/marketplaces.js";
|
|
11
12
|
import { getAvailablePlugins, refreshAllMarketplaces, clearMarketplaceCache, getLocalMarketplacesInfo, } from "../../services/plugin-manager.js";
|
|
@@ -175,31 +176,17 @@ export function PluginsScreen() {
|
|
|
175
176
|
}
|
|
176
177
|
return;
|
|
177
178
|
}
|
|
178
|
-
// Navigation — always works
|
|
179
|
+
// Navigation — always works; exits search mode on navigate
|
|
179
180
|
if (event.name === "up" || event.name === "k") {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
dispatch({
|
|
183
|
-
type: "PLUGINS_SET_SEARCH",
|
|
184
|
-
query: pluginsState.searchQuery + event.name,
|
|
185
|
-
});
|
|
186
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
181
|
+
if (isSearchActive)
|
|
182
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
189
183
|
const newIndex = Math.max(0, pluginsState.selectedIndex - 1);
|
|
190
184
|
dispatch({ type: "PLUGINS_SELECT", index: newIndex });
|
|
191
185
|
return;
|
|
192
186
|
}
|
|
193
187
|
if (event.name === "down" || event.name === "j") {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
dispatch({
|
|
197
|
-
type: "PLUGINS_SET_SEARCH",
|
|
198
|
-
query: pluginsState.searchQuery + event.name,
|
|
199
|
-
});
|
|
200
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
188
|
+
if (isSearchActive)
|
|
189
|
+
dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
203
190
|
const newIndex = Math.min(selectableItems.length - 1, pluginsState.selectedIndex + 1);
|
|
204
191
|
dispatch({ type: "PLUGINS_SELECT", index: newIndex });
|
|
205
192
|
return;
|
|
@@ -229,9 +216,9 @@ export function PluginsScreen() {
|
|
|
229
216
|
}
|
|
230
217
|
return;
|
|
231
218
|
}
|
|
232
|
-
// When
|
|
233
|
-
//
|
|
234
|
-
if (
|
|
219
|
+
// When actively typing in search, letters go to the query
|
|
220
|
+
// After Enter (isSearchActive=false, hasQuery=true), shortcuts resume
|
|
221
|
+
if (isSearchActive) {
|
|
235
222
|
if (event.name.length === 1 && !event.ctrl && !event.meta && !/[0-9]/.test(event.name)) {
|
|
236
223
|
dispatch({
|
|
237
224
|
type: "PLUGINS_SET_SEARCH",
|
|
@@ -241,7 +228,7 @@ export function PluginsScreen() {
|
|
|
241
228
|
}
|
|
242
229
|
return;
|
|
243
230
|
}
|
|
244
|
-
//
|
|
231
|
+
// Action shortcuts work when not actively typing (even with filter visible)
|
|
245
232
|
// Start explicit search mode with /
|
|
246
233
|
if (event.name === "/") {
|
|
247
234
|
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
@@ -268,14 +255,9 @@ export function PluginsScreen() {
|
|
|
268
255
|
handleUninstall();
|
|
269
256
|
else if (event.name === "s")
|
|
270
257
|
handleSaveAsProfile();
|
|
271
|
-
//
|
|
272
|
-
else if (event.name
|
|
258
|
+
// "/" to enter search mode
|
|
259
|
+
else if (event.name === "/") {
|
|
273
260
|
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
274
|
-
dispatch({
|
|
275
|
-
type: "PLUGINS_SET_SEARCH",
|
|
276
|
-
query: event.name,
|
|
277
|
-
});
|
|
278
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
279
261
|
}
|
|
280
262
|
});
|
|
281
263
|
// Handle actions
|
|
@@ -920,14 +902,14 @@ export function PluginsScreen() {
|
|
|
920
902
|
// Show version only if valid (not null, not 0.0.0)
|
|
921
903
|
const showVersion = plugin.version && plugin.version !== "0.0.0";
|
|
922
904
|
const showInstalledVersion = plugin.installedVersion && plugin.installedVersion !== "0.0.0";
|
|
923
|
-
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:
|
|
905
|
+
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: "green", children: "\u25CF Installed" })) : (_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: "#5c9aff", children: ["v", plugin.version] }), showInstalledVersion &&
|
|
924
906
|
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: [_jsxs("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: [_jsxs("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: [_jsxs("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: [_jsxs("text", { bg: "magenta", fg: "white", children: [" ", "U", " "] }), _jsxs("text", { children: [" Update to v", plugin.version] })] })), _jsxs("box", { children: [_jsxs("text", { bg: "red", fg: "white", children: [" ", "d", " "] }), _jsx("text", { children: " Uninstall" })] })] }))] }));
|
|
925
907
|
}
|
|
926
908
|
return null;
|
|
927
909
|
};
|
|
928
|
-
const footerHints = isSearchActive
|
|
929
|
-
? "
|
|
930
|
-
: "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │
|
|
910
|
+
const footerHints = isSearchActive
|
|
911
|
+
? "type to filter │ Enter:done │ Esc:clear"
|
|
912
|
+
: "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │ /:search";
|
|
931
913
|
// Calculate status for subtitle
|
|
932
914
|
const scopeLabel = pluginsState.scope === "global" ? "Global" : "Project";
|
|
933
915
|
const plugins = pluginsState.plugins.status === "success" ? pluginsState.plugins.data : [];
|
|
@@ -940,6 +922,6 @@ export function PluginsScreen() {
|
|
|
940
922
|
isActive: isSearchActive,
|
|
941
923
|
query: pluginsState.searchQuery,
|
|
942
924
|
placeholder: searchPlaceholder,
|
|
943
|
-
}, footerHints: footerHints, listPanel: _jsx(ScrollableList, { items: selectableItems, selectedIndex: pluginsState.selectedIndex, renderItem: renderListItem, maxHeight: dimensions.listPanelHeight }), detailPanel: renderDetail() }));
|
|
925
|
+
}, footerHints: footerHints, listPanel: _jsxs("box", { flexDirection: "column", children: [_jsx(ScrollableList, { items: selectableItems, selectedIndex: pluginsState.selectedIndex, renderItem: renderListItem, maxHeight: dimensions.listPanelHeight }), pluginsState.searchQuery && selectableItems.length === 0 && (_jsx(EmptyFilterState, { query: pluginsState.searchQuery, entityName: "plugins" }))] }), detailPanel: renderDetail() }));
|
|
944
926
|
}
|
|
945
927
|
export default PluginsScreen;
|
|
@@ -5,6 +5,7 @@ import { useKeyboard } from "../hooks/useKeyboard.js";
|
|
|
5
5
|
import { ScreenLayout } from "../components/layout/index.js";
|
|
6
6
|
import { CategoryHeader } from "../components/CategoryHeader.js";
|
|
7
7
|
import { ScrollableList } from "../components/ScrollableList.js";
|
|
8
|
+
import { EmptyFilterState } from "../components/EmptyFilterState.js";
|
|
8
9
|
import { fuzzyFilter, highlightMatches } from "../../utils/fuzzy-search.js";
|
|
9
10
|
import { getAllMarketplaces } from "../../data/marketplaces.js";
|
|
10
11
|
import {
|
|
@@ -240,31 +241,15 @@ export function PluginsScreen() {
|
|
|
240
241
|
return;
|
|
241
242
|
}
|
|
242
243
|
|
|
243
|
-
// Navigation — always works
|
|
244
|
+
// Navigation — always works; exits search mode on navigate
|
|
244
245
|
if (event.name === "up" || event.name === "k") {
|
|
245
|
-
|
|
246
|
-
if (event.name === "k" && (hasQuery || isSearchActive)) {
|
|
247
|
-
dispatch({
|
|
248
|
-
type: "PLUGINS_SET_SEARCH",
|
|
249
|
-
query: pluginsState.searchQuery + event.name,
|
|
250
|
-
});
|
|
251
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
246
|
+
if (isSearchActive) dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
254
247
|
const newIndex = Math.max(0, pluginsState.selectedIndex - 1);
|
|
255
248
|
dispatch({ type: "PLUGINS_SELECT", index: newIndex });
|
|
256
249
|
return;
|
|
257
250
|
}
|
|
258
251
|
if (event.name === "down" || event.name === "j") {
|
|
259
|
-
|
|
260
|
-
if (event.name === "j" && (hasQuery || isSearchActive)) {
|
|
261
|
-
dispatch({
|
|
262
|
-
type: "PLUGINS_SET_SEARCH",
|
|
263
|
-
query: pluginsState.searchQuery + event.name,
|
|
264
|
-
});
|
|
265
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
252
|
+
if (isSearchActive) dispatch({ type: "SET_SEARCHING", isSearching: false });
|
|
268
253
|
const newIndex = Math.min(
|
|
269
254
|
selectableItems.length - 1,
|
|
270
255
|
pluginsState.selectedIndex + 1,
|
|
@@ -302,9 +287,9 @@ export function PluginsScreen() {
|
|
|
302
287
|
return;
|
|
303
288
|
}
|
|
304
289
|
|
|
305
|
-
// When
|
|
306
|
-
//
|
|
307
|
-
if (
|
|
290
|
+
// When actively typing in search, letters go to the query
|
|
291
|
+
// After Enter (isSearchActive=false, hasQuery=true), shortcuts resume
|
|
292
|
+
if (isSearchActive) {
|
|
308
293
|
if (event.name.length === 1 && !event.ctrl && !event.meta && !/[0-9]/.test(event.name)) {
|
|
309
294
|
dispatch({
|
|
310
295
|
type: "PLUGINS_SET_SEARCH",
|
|
@@ -315,7 +300,7 @@ export function PluginsScreen() {
|
|
|
315
300
|
return;
|
|
316
301
|
}
|
|
317
302
|
|
|
318
|
-
//
|
|
303
|
+
// Action shortcuts work when not actively typing (even with filter visible)
|
|
319
304
|
|
|
320
305
|
// Start explicit search mode with /
|
|
321
306
|
if (event.name === "/") {
|
|
@@ -334,14 +319,9 @@ export function PluginsScreen() {
|
|
|
334
319
|
else if (event.name === "a") handleUpdateAll();
|
|
335
320
|
else if (event.name === "d") handleUninstall();
|
|
336
321
|
else if (event.name === "s") handleSaveAsProfile();
|
|
337
|
-
//
|
|
338
|
-
else if (event.name
|
|
322
|
+
// "/" to enter search mode
|
|
323
|
+
else if (event.name === "/") {
|
|
339
324
|
dispatch({ type: "SET_SEARCHING", isSearching: true });
|
|
340
|
-
dispatch({
|
|
341
|
-
type: "PLUGINS_SET_SEARCH",
|
|
342
|
-
query: event.name,
|
|
343
|
-
});
|
|
344
|
-
dispatch({ type: "PLUGINS_SELECT", index: 0 });
|
|
345
325
|
}
|
|
346
326
|
});
|
|
347
327
|
|
|
@@ -1260,9 +1240,7 @@ export function PluginsScreen() {
|
|
|
1260
1240
|
{/* Status line */}
|
|
1261
1241
|
<box marginTop={1}>
|
|
1262
1242
|
{isInstalled ? (
|
|
1263
|
-
<text fg=
|
|
1264
|
-
{plugin.enabled ? "● Enabled" : "● Disabled"}
|
|
1265
|
-
</text>
|
|
1243
|
+
<text fg="green">● Installed</text>
|
|
1266
1244
|
) : (
|
|
1267
1245
|
<text fg="gray">○ Not installed</text>
|
|
1268
1246
|
)}
|
|
@@ -1383,10 +1361,9 @@ export function PluginsScreen() {
|
|
|
1383
1361
|
return null;
|
|
1384
1362
|
};
|
|
1385
1363
|
|
|
1386
|
-
const footerHints =
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
: "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │ type to search";
|
|
1364
|
+
const footerHints = isSearchActive
|
|
1365
|
+
? "type to filter │ Enter:done │ Esc:clear"
|
|
1366
|
+
: "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │ /:search";
|
|
1390
1367
|
|
|
1391
1368
|
// Calculate status for subtitle
|
|
1392
1369
|
const scopeLabel = pluginsState.scope === "global" ? "Global" : "Project";
|
|
@@ -1411,12 +1388,17 @@ export function PluginsScreen() {
|
|
|
1411
1388
|
}}
|
|
1412
1389
|
footerHints={footerHints}
|
|
1413
1390
|
listPanel={
|
|
1414
|
-
<
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1391
|
+
<box flexDirection="column">
|
|
1392
|
+
<ScrollableList
|
|
1393
|
+
items={selectableItems}
|
|
1394
|
+
selectedIndex={pluginsState.selectedIndex}
|
|
1395
|
+
renderItem={renderListItem}
|
|
1396
|
+
maxHeight={dimensions.listPanelHeight}
|
|
1397
|
+
/>
|
|
1398
|
+
{pluginsState.searchQuery && selectableItems.length === 0 && (
|
|
1399
|
+
<EmptyFilterState query={pluginsState.searchQuery} entityName="plugins" />
|
|
1400
|
+
)}
|
|
1401
|
+
</box>
|
|
1420
1402
|
}
|
|
1421
1403
|
detailPanel={renderDetail()}
|
|
1422
1404
|
/>
|