@laststance/claude-plugin-dashboard 0.1.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/LICENSE +21 -0
- package/README.md +235 -0
- package/dist/app.d.ts +8 -0
- package/dist/app.js +481 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +316 -0
- package/dist/components/ConfirmDialog.d.ts +14 -0
- package/dist/components/ConfirmDialog.js +14 -0
- package/dist/components/KeyHints.d.ts +19 -0
- package/dist/components/KeyHints.js +23 -0
- package/dist/components/MarketplaceDetail.d.ts +15 -0
- package/dist/components/MarketplaceDetail.js +39 -0
- package/dist/components/MarketplaceList.d.ts +16 -0
- package/dist/components/MarketplaceList.js +32 -0
- package/dist/components/PluginDetail.d.ts +15 -0
- package/dist/components/PluginDetail.js +52 -0
- package/dist/components/PluginList.d.ts +19 -0
- package/dist/components/PluginList.js +54 -0
- package/dist/components/SearchInput.d.ts +16 -0
- package/dist/components/SearchInput.js +14 -0
- package/dist/components/SortDropdown.d.ts +21 -0
- package/dist/components/SortDropdown.js +29 -0
- package/dist/components/StatusIcon.d.ts +20 -0
- package/dist/components/StatusIcon.js +25 -0
- package/dist/components/TabBar.d.ts +24 -0
- package/dist/components/TabBar.js +38 -0
- package/dist/services/fileService.d.ts +41 -0
- package/dist/services/fileService.js +104 -0
- package/dist/services/pluginActionsService.d.ts +21 -0
- package/dist/services/pluginActionsService.js +65 -0
- package/dist/services/pluginService.d.ts +66 -0
- package/dist/services/pluginService.js +188 -0
- package/dist/services/settingsService.d.ts +82 -0
- package/dist/services/settingsService.js +117 -0
- package/dist/tabs/DiscoverTab.d.ts +26 -0
- package/dist/tabs/DiscoverTab.js +25 -0
- package/dist/tabs/ErrorsTab.d.ts +16 -0
- package/dist/tabs/ErrorsTab.js +39 -0
- package/dist/tabs/InstalledTab.d.ts +16 -0
- package/dist/tabs/InstalledTab.js +24 -0
- package/dist/tabs/MarketplacesTab.d.ts +16 -0
- package/dist/tabs/MarketplacesTab.js +21 -0
- package/dist/types/index.d.ts +250 -0
- package/dist/types/index.js +5 -0
- package/dist/utils/paths.d.ts +40 -0
- package/dist/utils/paths.js +50 -0
- package/package.json +60 -0
package/dist/app.js
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Main App component for Claude Code Plugin Dashboard
|
|
4
|
+
* Interactive TUI to browse and manage Claude Code plugins
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect, useReducer } from 'react';
|
|
7
|
+
import { Box, Text, useInput, useApp } from 'ink';
|
|
8
|
+
import TabBar, { getNextTab } from './components/TabBar.js';
|
|
9
|
+
import KeyHints from './components/KeyHints.js';
|
|
10
|
+
import DiscoverTab from './tabs/DiscoverTab.js';
|
|
11
|
+
import InstalledTab from './tabs/InstalledTab.js';
|
|
12
|
+
import MarketplacesTab from './tabs/MarketplacesTab.js';
|
|
13
|
+
import ErrorsTab from './tabs/ErrorsTab.js';
|
|
14
|
+
import { loadAllPlugins, loadMarketplaces, searchPlugins, sortPlugins, } from './services/pluginService.js';
|
|
15
|
+
import { togglePlugin } from './services/settingsService.js';
|
|
16
|
+
import { installPlugin, uninstallPlugin, } from './services/pluginActionsService.js';
|
|
17
|
+
import ConfirmDialog from './components/ConfirmDialog.js';
|
|
18
|
+
/**
|
|
19
|
+
* Initial application state
|
|
20
|
+
*/
|
|
21
|
+
const initialState = {
|
|
22
|
+
activeTab: 'discover',
|
|
23
|
+
plugins: [],
|
|
24
|
+
marketplaces: [],
|
|
25
|
+
errors: [],
|
|
26
|
+
selectedIndex: 0,
|
|
27
|
+
searchQuery: '',
|
|
28
|
+
sortBy: 'installs',
|
|
29
|
+
sortOrder: 'desc',
|
|
30
|
+
loading: true,
|
|
31
|
+
error: null,
|
|
32
|
+
message: null,
|
|
33
|
+
operation: 'idle',
|
|
34
|
+
operationPluginId: null,
|
|
35
|
+
confirmUninstall: false,
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* State reducer for application state management
|
|
39
|
+
*/
|
|
40
|
+
function appReducer(state, action) {
|
|
41
|
+
switch (action.type) {
|
|
42
|
+
case 'SET_TAB':
|
|
43
|
+
return {
|
|
44
|
+
...state,
|
|
45
|
+
activeTab: action.payload,
|
|
46
|
+
selectedIndex: 0,
|
|
47
|
+
searchQuery: '',
|
|
48
|
+
message: null,
|
|
49
|
+
};
|
|
50
|
+
case 'NEXT_TAB':
|
|
51
|
+
return {
|
|
52
|
+
...state,
|
|
53
|
+
activeTab: getNextTab(state.activeTab, 'next'),
|
|
54
|
+
selectedIndex: 0,
|
|
55
|
+
searchQuery: '',
|
|
56
|
+
message: null,
|
|
57
|
+
};
|
|
58
|
+
case 'PREV_TAB':
|
|
59
|
+
return {
|
|
60
|
+
...state,
|
|
61
|
+
activeTab: getNextTab(state.activeTab, 'prev'),
|
|
62
|
+
selectedIndex: 0,
|
|
63
|
+
searchQuery: '',
|
|
64
|
+
message: null,
|
|
65
|
+
};
|
|
66
|
+
case 'SET_PLUGINS':
|
|
67
|
+
return {
|
|
68
|
+
...state,
|
|
69
|
+
plugins: action.payload,
|
|
70
|
+
loading: false,
|
|
71
|
+
};
|
|
72
|
+
case 'SET_MARKETPLACES':
|
|
73
|
+
return {
|
|
74
|
+
...state,
|
|
75
|
+
marketplaces: action.payload,
|
|
76
|
+
};
|
|
77
|
+
case 'SET_ERRORS':
|
|
78
|
+
return {
|
|
79
|
+
...state,
|
|
80
|
+
errors: action.payload,
|
|
81
|
+
};
|
|
82
|
+
case 'SET_SELECTED_INDEX':
|
|
83
|
+
return {
|
|
84
|
+
...state,
|
|
85
|
+
selectedIndex: action.payload,
|
|
86
|
+
message: null,
|
|
87
|
+
};
|
|
88
|
+
case 'MOVE_SELECTION': {
|
|
89
|
+
const items = getItemsForTab(state);
|
|
90
|
+
const maxIndex = Math.max(0, items.length - 1);
|
|
91
|
+
if (items.length === 0)
|
|
92
|
+
return state;
|
|
93
|
+
const newIndex = action.payload === 'up'
|
|
94
|
+
? Math.max(0, state.selectedIndex - 1)
|
|
95
|
+
: Math.min(maxIndex, state.selectedIndex + 1);
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
selectedIndex: newIndex,
|
|
99
|
+
message: null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
case 'SET_SEARCH_QUERY':
|
|
103
|
+
return {
|
|
104
|
+
...state,
|
|
105
|
+
searchQuery: action.payload,
|
|
106
|
+
selectedIndex: 0,
|
|
107
|
+
};
|
|
108
|
+
case 'SET_SORT':
|
|
109
|
+
return {
|
|
110
|
+
...state,
|
|
111
|
+
sortBy: action.payload.by,
|
|
112
|
+
sortOrder: action.payload.order,
|
|
113
|
+
selectedIndex: 0,
|
|
114
|
+
};
|
|
115
|
+
case 'TOGGLE_PLUGIN_ENABLED': {
|
|
116
|
+
const pluginId = action.payload;
|
|
117
|
+
const updatedPlugins = state.plugins.map((p) => {
|
|
118
|
+
if (p.id === pluginId) {
|
|
119
|
+
return { ...p, isEnabled: !p.isEnabled };
|
|
120
|
+
}
|
|
121
|
+
return p;
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
...state,
|
|
125
|
+
plugins: updatedPlugins,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
case 'UPDATE_PLUGIN': {
|
|
129
|
+
const updatedPlugins = state.plugins.map((p) => {
|
|
130
|
+
if (p.id === action.payload.id) {
|
|
131
|
+
return action.payload;
|
|
132
|
+
}
|
|
133
|
+
return p;
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
...state,
|
|
137
|
+
plugins: updatedPlugins,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
case 'SET_LOADING':
|
|
141
|
+
return {
|
|
142
|
+
...state,
|
|
143
|
+
loading: action.payload,
|
|
144
|
+
};
|
|
145
|
+
case 'SET_ERROR':
|
|
146
|
+
return {
|
|
147
|
+
...state,
|
|
148
|
+
error: action.payload,
|
|
149
|
+
loading: false,
|
|
150
|
+
};
|
|
151
|
+
case 'SET_MESSAGE':
|
|
152
|
+
return {
|
|
153
|
+
...state,
|
|
154
|
+
message: action.payload,
|
|
155
|
+
};
|
|
156
|
+
case 'START_OPERATION':
|
|
157
|
+
return {
|
|
158
|
+
...state,
|
|
159
|
+
operation: action.payload.operation,
|
|
160
|
+
operationPluginId: action.payload.pluginId,
|
|
161
|
+
message: action.payload.operation === 'installing'
|
|
162
|
+
? `Installing ${action.payload.pluginId}...`
|
|
163
|
+
: `Uninstalling ${action.payload.pluginId}...`,
|
|
164
|
+
};
|
|
165
|
+
case 'END_OPERATION':
|
|
166
|
+
return {
|
|
167
|
+
...state,
|
|
168
|
+
operation: 'idle',
|
|
169
|
+
operationPluginId: null,
|
|
170
|
+
};
|
|
171
|
+
case 'SHOW_CONFIRM_UNINSTALL':
|
|
172
|
+
return {
|
|
173
|
+
...state,
|
|
174
|
+
confirmUninstall: true,
|
|
175
|
+
operationPluginId: action.payload,
|
|
176
|
+
};
|
|
177
|
+
case 'HIDE_CONFIRM_UNINSTALL':
|
|
178
|
+
return {
|
|
179
|
+
...state,
|
|
180
|
+
confirmUninstall: false,
|
|
181
|
+
operationPluginId: null,
|
|
182
|
+
};
|
|
183
|
+
default:
|
|
184
|
+
return state;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get items array for current tab
|
|
189
|
+
*/
|
|
190
|
+
function getItemsForTab(state) {
|
|
191
|
+
switch (state.activeTab) {
|
|
192
|
+
case 'discover':
|
|
193
|
+
return getFilteredPlugins(state);
|
|
194
|
+
case 'installed':
|
|
195
|
+
return state.plugins.filter((p) => p.isInstalled);
|
|
196
|
+
case 'marketplaces':
|
|
197
|
+
return state.marketplaces;
|
|
198
|
+
case 'errors':
|
|
199
|
+
return state.errors;
|
|
200
|
+
default:
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get filtered and sorted plugins for discover tab
|
|
206
|
+
*/
|
|
207
|
+
function getFilteredPlugins(state) {
|
|
208
|
+
let plugins = state.plugins;
|
|
209
|
+
// Apply search filter
|
|
210
|
+
if (state.searchQuery) {
|
|
211
|
+
plugins = searchPlugins(state.searchQuery, plugins);
|
|
212
|
+
}
|
|
213
|
+
// Apply sort
|
|
214
|
+
plugins = sortPlugins(plugins, state.sortBy, state.sortOrder);
|
|
215
|
+
return plugins;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Main App component
|
|
219
|
+
*/
|
|
220
|
+
export default function App() {
|
|
221
|
+
const { exit } = useApp();
|
|
222
|
+
const [state, dispatch] = useReducer(appReducer, initialState);
|
|
223
|
+
const [isSearchMode, setIsSearchMode] = useState(false);
|
|
224
|
+
// Load data on mount
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
try {
|
|
227
|
+
const plugins = loadAllPlugins();
|
|
228
|
+
const marketplaces = loadMarketplaces();
|
|
229
|
+
dispatch({ type: 'SET_PLUGINS', payload: plugins });
|
|
230
|
+
dispatch({ type: 'SET_MARKETPLACES', payload: marketplaces });
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
dispatch({
|
|
234
|
+
type: 'SET_ERROR',
|
|
235
|
+
payload: error instanceof Error ? error.message : 'Failed to load data',
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}, []);
|
|
239
|
+
/**
|
|
240
|
+
* Handle plugin installation
|
|
241
|
+
*/
|
|
242
|
+
async function handleInstall(pluginId) {
|
|
243
|
+
dispatch({
|
|
244
|
+
type: 'START_OPERATION',
|
|
245
|
+
payload: { operation: 'installing', pluginId },
|
|
246
|
+
});
|
|
247
|
+
const result = await installPlugin(pluginId);
|
|
248
|
+
dispatch({ type: 'END_OPERATION' });
|
|
249
|
+
if (result.success) {
|
|
250
|
+
// Reload plugins to get fresh state
|
|
251
|
+
const plugins = loadAllPlugins();
|
|
252
|
+
dispatch({ type: 'SET_PLUGINS', payload: plugins });
|
|
253
|
+
dispatch({ type: 'SET_MESSAGE', payload: `✅ ${result.message}` });
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
dispatch({
|
|
257
|
+
type: 'SET_MESSAGE',
|
|
258
|
+
payload: `❌ ${result.message}${result.error ? `: ${result.error}` : ''}`,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Handle plugin uninstallation
|
|
264
|
+
*/
|
|
265
|
+
async function handleUninstall(pluginId) {
|
|
266
|
+
dispatch({
|
|
267
|
+
type: 'START_OPERATION',
|
|
268
|
+
payload: { operation: 'uninstalling', pluginId },
|
|
269
|
+
});
|
|
270
|
+
const result = await uninstallPlugin(pluginId);
|
|
271
|
+
dispatch({ type: 'END_OPERATION' });
|
|
272
|
+
if (result.success) {
|
|
273
|
+
// Reload plugins to get fresh state
|
|
274
|
+
const plugins = loadAllPlugins();
|
|
275
|
+
dispatch({ type: 'SET_PLUGINS', payload: plugins });
|
|
276
|
+
dispatch({ type: 'SET_MESSAGE', payload: `✅ ${result.message}` });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
dispatch({
|
|
280
|
+
type: 'SET_MESSAGE',
|
|
281
|
+
payload: `❌ ${result.message}${result.error ? `: ${result.error}` : ''}`,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Keyboard input handling
|
|
286
|
+
useInput((input, key) => {
|
|
287
|
+
// Block all input during operations
|
|
288
|
+
if (state.operation !== 'idle') {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// Handle confirmation dialog
|
|
292
|
+
if (state.confirmUninstall && state.operationPluginId) {
|
|
293
|
+
if (input === 'y' || input === 'Y') {
|
|
294
|
+
dispatch({ type: 'HIDE_CONFIRM_UNINSTALL' });
|
|
295
|
+
handleUninstall(state.operationPluginId);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (input === 'n' || input === 'N' || key.escape) {
|
|
299
|
+
dispatch({ type: 'HIDE_CONFIRM_UNINSTALL' });
|
|
300
|
+
dispatch({ type: 'SET_MESSAGE', payload: 'Uninstall cancelled' });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// Search mode input
|
|
306
|
+
if (isSearchMode) {
|
|
307
|
+
if (key.escape || key.return) {
|
|
308
|
+
setIsSearchMode(false);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (key.backspace || key.delete) {
|
|
312
|
+
dispatch({
|
|
313
|
+
type: 'SET_SEARCH_QUERY',
|
|
314
|
+
payload: state.searchQuery.slice(0, -1),
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
319
|
+
dispatch({
|
|
320
|
+
type: 'SET_SEARCH_QUERY',
|
|
321
|
+
payload: state.searchQuery + input,
|
|
322
|
+
});
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
// Emacs-style navigation (Ctrl+P / Ctrl+N)
|
|
328
|
+
if (key.ctrl && input === 'p') {
|
|
329
|
+
dispatch({ type: 'MOVE_SELECTION', payload: 'up' });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (key.ctrl && input === 'n') {
|
|
333
|
+
dispatch({ type: 'MOVE_SELECTION', payload: 'down' });
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
// Tab navigation
|
|
337
|
+
if (key.leftArrow) {
|
|
338
|
+
dispatch({ type: 'PREV_TAB' });
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (key.rightArrow) {
|
|
342
|
+
dispatch({ type: 'NEXT_TAB' });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (key.tab) {
|
|
346
|
+
dispatch({ type: 'NEXT_TAB' });
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// List navigation
|
|
350
|
+
if (key.upArrow) {
|
|
351
|
+
dispatch({ type: 'MOVE_SELECTION', payload: 'up' });
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (key.downArrow) {
|
|
355
|
+
dispatch({ type: 'MOVE_SELECTION', payload: 'down' });
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// Enter search mode
|
|
359
|
+
if (input === '/' && state.activeTab === 'discover') {
|
|
360
|
+
setIsSearchMode(true);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
// Toggle plugin (Space or Enter)
|
|
364
|
+
if ((input === ' ' || key.return) &&
|
|
365
|
+
(state.activeTab === 'discover' || state.activeTab === 'installed')) {
|
|
366
|
+
const items = state.activeTab === 'installed'
|
|
367
|
+
? state.plugins.filter((p) => p.isInstalled)
|
|
368
|
+
: getFilteredPlugins(state);
|
|
369
|
+
const selectedPlugin = items[state.selectedIndex];
|
|
370
|
+
if (selectedPlugin && selectedPlugin.isInstalled) {
|
|
371
|
+
try {
|
|
372
|
+
const newState = togglePlugin(selectedPlugin.id);
|
|
373
|
+
dispatch({
|
|
374
|
+
type: 'TOGGLE_PLUGIN_ENABLED',
|
|
375
|
+
payload: selectedPlugin.id,
|
|
376
|
+
});
|
|
377
|
+
dispatch({
|
|
378
|
+
type: 'SET_MESSAGE',
|
|
379
|
+
payload: newState
|
|
380
|
+
? `✅ ${selectedPlugin.name} enabled`
|
|
381
|
+
: `❌ ${selectedPlugin.name} disabled`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
dispatch({
|
|
386
|
+
type: 'SET_MESSAGE',
|
|
387
|
+
payload: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
// Cycle sort (s key)
|
|
394
|
+
if (input === 's' && state.activeTab === 'discover') {
|
|
395
|
+
const nextSort = {
|
|
396
|
+
installs: 'name',
|
|
397
|
+
name: 'date',
|
|
398
|
+
date: 'installs',
|
|
399
|
+
};
|
|
400
|
+
dispatch({
|
|
401
|
+
type: 'SET_SORT',
|
|
402
|
+
payload: { by: nextSort[state.sortBy], order: state.sortOrder },
|
|
403
|
+
});
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
// Toggle sort order (S key)
|
|
407
|
+
if (input === 'S' && state.activeTab === 'discover') {
|
|
408
|
+
dispatch({
|
|
409
|
+
type: 'SET_SORT',
|
|
410
|
+
payload: {
|
|
411
|
+
by: state.sortBy,
|
|
412
|
+
order: state.sortOrder === 'asc' ? 'desc' : 'asc',
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
// Clear search (Escape)
|
|
418
|
+
if (key.escape && state.searchQuery) {
|
|
419
|
+
dispatch({ type: 'SET_SEARCH_QUERY', payload: '' });
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// Install (i key) - only on discover/installed tabs
|
|
423
|
+
if (input === 'i' &&
|
|
424
|
+
(state.activeTab === 'discover' || state.activeTab === 'installed')) {
|
|
425
|
+
const items = state.activeTab === 'installed'
|
|
426
|
+
? state.plugins.filter((p) => p.isInstalled)
|
|
427
|
+
: getFilteredPlugins(state);
|
|
428
|
+
const selectedPlugin = items[state.selectedIndex];
|
|
429
|
+
if (selectedPlugin && !selectedPlugin.isInstalled) {
|
|
430
|
+
handleInstall(selectedPlugin.id);
|
|
431
|
+
}
|
|
432
|
+
else if (selectedPlugin?.isInstalled) {
|
|
433
|
+
dispatch({
|
|
434
|
+
type: 'SET_MESSAGE',
|
|
435
|
+
payload: '⚠️ Plugin is already installed',
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
// Uninstall (u key) - only on discover/installed tabs
|
|
441
|
+
if (input === 'u' &&
|
|
442
|
+
(state.activeTab === 'discover' || state.activeTab === 'installed')) {
|
|
443
|
+
const items = state.activeTab === 'installed'
|
|
444
|
+
? state.plugins.filter((p) => p.isInstalled)
|
|
445
|
+
: getFilteredPlugins(state);
|
|
446
|
+
const selectedPlugin = items[state.selectedIndex];
|
|
447
|
+
if (selectedPlugin && selectedPlugin.isInstalled) {
|
|
448
|
+
dispatch({ type: 'SHOW_CONFIRM_UNINSTALL', payload: selectedPlugin.id });
|
|
449
|
+
}
|
|
450
|
+
else if (selectedPlugin && !selectedPlugin.isInstalled) {
|
|
451
|
+
dispatch({ type: 'SET_MESSAGE', payload: '⚠️ Plugin is not installed' });
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
// Exit (q or Ctrl+C)
|
|
456
|
+
if (input === 'q' || (key.ctrl && input === 'c')) {
|
|
457
|
+
exit();
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
// Loading state
|
|
462
|
+
if (state.loading) {
|
|
463
|
+
return (_jsx(Box, { flexDirection: "column", padding: 1, children: _jsx(Text, { children: "Loading plugins..." }) }));
|
|
464
|
+
}
|
|
465
|
+
// Error state
|
|
466
|
+
if (state.error) {
|
|
467
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Text, { color: "red", children: ["Error: ", state.error] }), _jsx(Text, { dimColor: true, children: "Press q to exit" })] }));
|
|
468
|
+
}
|
|
469
|
+
// Get filtered data for current tab
|
|
470
|
+
const filteredPlugins = getFilteredPlugins(state);
|
|
471
|
+
const installedPlugins = state.plugins.filter((p) => p.isInstalled);
|
|
472
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsx(Text, { bold: true, color: "magenta", children: "\u26A1 Claude Code Plugin Dashboard" }), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: "v0.1.0" })] }), _jsx(TabBar, { activeTab: state.activeTab }), _jsxs(Box, { flexGrow: 1, flexDirection: "column", children: [state.activeTab === 'discover' && (_jsx(DiscoverTab, { plugins: filteredPlugins, selectedIndex: state.selectedIndex, searchQuery: state.searchQuery, sortBy: state.sortBy, sortOrder: state.sortOrder, isSearchMode: isSearchMode })), state.activeTab === 'installed' && (_jsx(InstalledTab, { plugins: installedPlugins, selectedIndex: state.selectedIndex })), state.activeTab === 'marketplaces' && (_jsx(MarketplacesTab, { marketplaces: state.marketplaces, selectedIndex: state.selectedIndex })), state.activeTab === 'errors' && (_jsx(ErrorsTab, { errors: state.errors, selectedIndex: state.selectedIndex }))] }), state.confirmUninstall && state.operationPluginId && (_jsx(ConfirmDialog, { message: `Uninstall ${state.operationPluginId}?` })), state.message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: state.message }) })), _jsx(KeyHints, { extraHints: state.activeTab === 'discover' || state.activeTab === 'installed'
|
|
473
|
+
? [
|
|
474
|
+
{ key: 'i', action: 'install' },
|
|
475
|
+
{ key: 'u', action: 'uninstall' },
|
|
476
|
+
...(state.activeTab === 'discover'
|
|
477
|
+
? [{ key: 's', action: 'sort' }]
|
|
478
|
+
: []),
|
|
479
|
+
]
|
|
480
|
+
: undefined })] }));
|
|
481
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for Claude Code Plugin Dashboard
|
|
4
|
+
* Supports both interactive (TUI) and non-interactive (command) modes
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* claude-plugin-dashboard # Interactive mode
|
|
8
|
+
* claude-plugin-dashboard status # Show summary
|
|
9
|
+
* claude-plugin-dashboard list # List all plugins
|
|
10
|
+
* claude-plugin-dashboard list --installed # List installed plugins
|
|
11
|
+
* claude-plugin-dashboard enable <plugin-id> # Enable plugin
|
|
12
|
+
* claude-plugin-dashboard disable <plugin-id># Disable plugin
|
|
13
|
+
* claude-plugin-dashboard toggle <plugin-id> # Toggle plugin
|
|
14
|
+
* claude-plugin-dashboard help # Show help
|
|
15
|
+
*/
|
|
16
|
+
export {};
|