claudeup 4.35.1 → 4.36.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 +4 -4
- package/src/__tests__/scope-squares.test.tsx +165 -0
- package/src/__tests__/theme-adaptive-colors.test.ts +307 -0
- package/src/__tests__/uppercase-keybindings.test.ts +101 -0
- package/src/main.tsx +21 -5
- package/src/opentui.d.ts +21 -12
- package/src/ui/App.tsx +19 -12
- package/src/ui/adapters/pluginsAdapter.ts +174 -168
- package/src/ui/adapters/settingsAdapter.ts +119 -116
- package/src/ui/adapters/skillsAdapter.ts +203 -196
- package/src/ui/components/CategoryHeader.tsx +9 -8
- package/src/ui/components/EmptyFilterState.tsx +10 -5
- package/src/ui/components/FlagDetailEditor.tsx +0 -0
- package/src/ui/components/ScopeIndicator.tsx +10 -6
- package/src/ui/components/ScrollableList.tsx +3 -2
- package/src/ui/components/SearchInput.tsx +2 -1
- package/src/ui/components/StyledText.tsx +5 -4
- package/src/ui/components/TabBar.tsx +4 -3
- package/src/ui/components/layout/FooterHints.tsx +37 -30
- package/src/ui/components/layout/Panel.tsx +6 -5
- package/src/ui/components/layout/ProgressBar.tsx +7 -6
- package/src/ui/components/layout/ScopeTabs.tsx +6 -5
- package/src/ui/components/layout/ScreenLayout.tsx +27 -24
- package/src/ui/components/layout/index.ts +3 -3
- package/src/ui/components/modals/ConfirmModal.tsx +12 -11
- package/src/ui/components/modals/InputModal.tsx +14 -6
- package/src/ui/components/modals/LoadingModal.tsx +6 -5
- package/src/ui/components/modals/MessageModal.tsx +9 -8
- package/src/ui/components/modals/SelectModal.tsx +11 -7
- package/src/ui/components/modals/VersionMismatchModal.tsx +14 -16
- package/src/ui/components/primitives/ActionHints.tsx +26 -26
- package/src/ui/components/primitives/DetailSection.tsx +13 -12
- package/src/ui/components/primitives/KeyValueLine.tsx +9 -8
- package/src/ui/components/primitives/ListCategoryRow.tsx +25 -27
- package/src/ui/components/primitives/MetaText.tsx +3 -3
- package/src/ui/components/primitives/ScopeDetail.tsx +48 -48
- package/src/ui/components/primitives/ScopeSquares.tsx +47 -22
- package/src/ui/components/primitives/SelectableRow.tsx +22 -16
- package/src/ui/hooks/useGitignoreModal.ts +78 -74
- package/src/ui/registry.ts +11 -11
- package/src/ui/renderers/cliToolRenderers.tsx +260 -203
- package/src/ui/renderers/gitignoreRenderers.tsx +43 -42
- package/src/ui/renderers/mcpRenderers.tsx +121 -117
- package/src/ui/renderers/pluginRenderers.tsx +528 -471
- package/src/ui/renderers/profileRenderers.tsx +346 -300
- package/src/ui/renderers/settingsRenderers.tsx +183 -176
- package/src/ui/renderers/skillRenderers.tsx +410 -326
- package/src/ui/screens/AliasScreen.tsx +1336 -1309
- package/src/ui/screens/CliToolsScreen.tsx +92 -40
- package/src/ui/screens/EnvVarsScreen.tsx +19 -13
- package/src/ui/screens/GitignoreScreen.tsx +510 -493
- package/src/ui/screens/McpRegistryScreen.tsx +28 -21
- package/src/ui/screens/McpScreen.tsx +12 -3
- package/src/ui/screens/PluginsScreen.tsx +17 -7
- package/src/ui/screens/ProfilesScreen.tsx +39 -23
- package/src/ui/screens/SkillsScreen.tsx +832 -688
- package/src/ui/theme-mode.ts +73 -0
- package/src/ui/theme.ts +147 -53
package/src/opentui.d.ts
CHANGED
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ReactNode } from "react";
|
|
11
|
+
import type { RGBA } from "@opentui/core";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* What OpenTUI actually accepts for a colour: a CSS string OR an RGBA, which is
|
|
15
|
+
* how adaptive colours are expressed (RGBA.defaultForeground(), RGBA.fromIndex()).
|
|
16
|
+
* These declarations previously said `string`, which made the terminal-resolved
|
|
17
|
+
* forms a type error and quietly pushed every call site towards absolute hex.
|
|
18
|
+
*/
|
|
19
|
+
type ColorProp = string | RGBA;
|
|
11
20
|
|
|
12
21
|
declare global {
|
|
13
22
|
namespace JSX {
|
|
@@ -28,7 +37,7 @@ declare global {
|
|
|
28
37
|
u: { children?: ReactNode };
|
|
29
38
|
dim: { children?: ReactNode };
|
|
30
39
|
a: { href?: string; children?: ReactNode };
|
|
31
|
-
span: { fg?:
|
|
40
|
+
span: { fg?: ColorProp; bg?: ColorProp; children?: ReactNode };
|
|
32
41
|
}
|
|
33
42
|
}
|
|
34
43
|
}
|
|
@@ -37,12 +46,12 @@ interface BaseBoxProps {
|
|
|
37
46
|
// Borders
|
|
38
47
|
border?: boolean;
|
|
39
48
|
borderStyle?: "single" | "double" | "rounded" | "bold";
|
|
40
|
-
borderColor?:
|
|
49
|
+
borderColor?: ColorProp;
|
|
41
50
|
title?: string;
|
|
42
51
|
titleAlignment?: "left" | "center" | "right";
|
|
43
52
|
|
|
44
53
|
// Colors
|
|
45
|
-
backgroundColor?:
|
|
54
|
+
backgroundColor?: ColorProp;
|
|
46
55
|
|
|
47
56
|
// Layout (Flexbox)
|
|
48
57
|
flexDirection?: "row" | "column";
|
|
@@ -94,8 +103,8 @@ interface BoxProps extends BaseBoxProps {
|
|
|
94
103
|
|
|
95
104
|
interface TextProps {
|
|
96
105
|
content?: string;
|
|
97
|
-
fg?:
|
|
98
|
-
bg?:
|
|
106
|
+
fg?: ColorProp;
|
|
107
|
+
bg?: ColorProp;
|
|
99
108
|
selectable?: boolean;
|
|
100
109
|
children?: ReactNode;
|
|
101
110
|
}
|
|
@@ -108,10 +117,10 @@ interface InputProps {
|
|
|
108
117
|
placeholder?: string;
|
|
109
118
|
focused?: boolean;
|
|
110
119
|
width?: number;
|
|
111
|
-
backgroundColor?:
|
|
112
|
-
textColor?:
|
|
113
|
-
cursorColor?:
|
|
114
|
-
focusedBackgroundColor?:
|
|
120
|
+
backgroundColor?: ColorProp;
|
|
121
|
+
textColor?: ColorProp;
|
|
122
|
+
cursorColor?: ColorProp;
|
|
123
|
+
focusedBackgroundColor?: ColorProp;
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
interface SelectOption {
|
|
@@ -150,8 +159,8 @@ interface ScrollboxProps {
|
|
|
150
159
|
scrollbarOptions?: {
|
|
151
160
|
showArrows?: boolean;
|
|
152
161
|
trackOptions?: {
|
|
153
|
-
foregroundColor?:
|
|
154
|
-
backgroundColor?:
|
|
162
|
+
foregroundColor?: ColorProp;
|
|
163
|
+
backgroundColor?: ColorProp;
|
|
155
164
|
};
|
|
156
165
|
};
|
|
157
166
|
};
|
|
@@ -161,7 +170,7 @@ interface ScrollboxProps {
|
|
|
161
170
|
interface AsciiFontProps {
|
|
162
171
|
text: string;
|
|
163
172
|
font?: "tiny" | "block" | "slick" | "shade";
|
|
164
|
-
color?:
|
|
173
|
+
color?: ColorProp;
|
|
165
174
|
}
|
|
166
175
|
|
|
167
176
|
interface CodeProps {
|
package/src/ui/App.tsx
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
} from "../services/version-check.js";
|
|
50
50
|
import { useKeyboardHandler } from "./hooks/useKeyboardHandler.js";
|
|
51
51
|
import { ProgressBar } from "./components/layout/ProgressBar.js";
|
|
52
|
+
import { theme } from "./theme.js";
|
|
52
53
|
|
|
53
54
|
export const VERSION = getCurrentVersion();
|
|
54
55
|
|
|
@@ -238,15 +239,15 @@ function UpdateBanner({ result }: { result: VersionCheckResult }) {
|
|
|
238
239
|
|
|
239
240
|
return (
|
|
240
241
|
<box paddingLeft={1} paddingRight={1}>
|
|
241
|
-
<text bg=
|
|
242
|
+
<text bg={theme.colors.warning} fg={theme.hints.fg}>
|
|
242
243
|
<strong> UPDATE </strong>
|
|
243
244
|
</text>
|
|
244
|
-
<text fg=
|
|
245
|
+
<text fg={theme.colors.warning}>
|
|
245
246
|
{" "}
|
|
246
247
|
v{result.currentVersion} → v{result.latestVersion}
|
|
247
248
|
</text>
|
|
248
|
-
<text fg=
|
|
249
|
-
<text fg=
|
|
249
|
+
<text fg={theme.colors.muted}> Run: </text>
|
|
250
|
+
<text fg={theme.colors.info}>claudeup update</text>
|
|
250
251
|
</box>
|
|
251
252
|
);
|
|
252
253
|
}
|
|
@@ -299,12 +300,12 @@ function AppContentInner({
|
|
|
299
300
|
{updateInfo?.updateAvailable && <UpdateBanner result={updateInfo} />}
|
|
300
301
|
{recoveryReport && (
|
|
301
302
|
<box paddingLeft={1} paddingRight={1}>
|
|
302
|
-
<text fg=
|
|
303
|
+
<text fg={theme.colors.success}>✓ Fixed: {recoveryReport}</text>
|
|
303
304
|
</box>
|
|
304
305
|
)}
|
|
305
306
|
{showDebug && (
|
|
306
307
|
<box paddingLeft={1} paddingRight={1}>
|
|
307
|
-
<text fg=
|
|
308
|
+
<text fg={theme.colors.muted}>
|
|
308
309
|
DEBUG: {dimensions.terminalWidth}x{dimensions.terminalHeight} |
|
|
309
310
|
content={dimensions.contentHeight} | screen=
|
|
310
311
|
{state.currentRoute.screen}
|
|
@@ -340,7 +341,9 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
340
341
|
const [showDebug, setShowDebug] = useState(false);
|
|
341
342
|
const [updateInfo, setUpdateInfo] = useState<VersionCheckResult | null>(null);
|
|
342
343
|
const [recoveryReport, setRecoveryReport] = useState<string | null>(null);
|
|
343
|
-
const [mismatchData, setMismatchData] = useState<
|
|
344
|
+
const [mismatchData, setMismatchData] = useState<
|
|
345
|
+
VersionMismatchInfo[] | null
|
|
346
|
+
>(null);
|
|
344
347
|
const mismatchModal = useMismatchModal();
|
|
345
348
|
const [gitignoreData, setGitignoreData] = useState<{
|
|
346
349
|
violationCount: number;
|
|
@@ -472,8 +475,13 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
472
475
|
const result = await checkGitignore(process.cwd());
|
|
473
476
|
if (result.violationCount > 0) {
|
|
474
477
|
const s = await loadGitignoreState(process.cwd());
|
|
475
|
-
const safeCount = s.violations.filter(
|
|
476
|
-
|
|
478
|
+
const safeCount = s.violations.filter(
|
|
479
|
+
(v) => v.severity === "safe",
|
|
480
|
+
).length;
|
|
481
|
+
setGitignoreData({
|
|
482
|
+
violationCount: result.violationCount,
|
|
483
|
+
safeCount,
|
|
484
|
+
});
|
|
477
485
|
}
|
|
478
486
|
} catch {
|
|
479
487
|
// non-fatal
|
|
@@ -491,8 +499,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
491
499
|
}, [dispatch]);
|
|
492
500
|
|
|
493
501
|
// Count transient banners for dimension calculation
|
|
494
|
-
const transientBannerCount =
|
|
495
|
-
recoveryReport ? 1 : 0;
|
|
502
|
+
const transientBannerCount = recoveryReport ? 1 : 0;
|
|
496
503
|
|
|
497
504
|
return (
|
|
498
505
|
<DimensionsProvider
|
|
@@ -507,7 +514,7 @@ function AppContent({ onExit }: AppContentProps) {
|
|
|
507
514
|
updateInfo={updateInfo}
|
|
508
515
|
onExit={onExit}
|
|
509
516
|
recoveryReport={recoveryReport}
|
|
510
|
-
|
|
517
|
+
/>
|
|
511
518
|
</DimensionsProvider>
|
|
512
519
|
);
|
|
513
520
|
}
|
|
@@ -2,34 +2,35 @@ import type { Marketplace } from "../../types/index.js";
|
|
|
2
2
|
import type { PluginInfo } from "../../services/plugin-manager.js";
|
|
3
3
|
|
|
4
4
|
// Virtual marketplace name for the community sub-section of claude-plugins-official
|
|
5
|
-
export const COMMUNITY_VIRTUAL_MARKETPLACE =
|
|
5
|
+
export const COMMUNITY_VIRTUAL_MARKETPLACE =
|
|
6
|
+
"claude-plugins-official:community";
|
|
6
7
|
// The marketplace that gets split into Anthropic Official + Community sections
|
|
7
8
|
export const SPLIT_MARKETPLACE = "claude-plugins-official";
|
|
8
9
|
|
|
9
10
|
// ─── Item types ───────────────────────────────────────────────────────────────
|
|
10
11
|
|
|
11
12
|
export interface PluginCategoryItem {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
id: string;
|
|
14
|
+
kind: "category";
|
|
15
|
+
label: string;
|
|
16
|
+
marketplace: Marketplace;
|
|
17
|
+
marketplaceEnabled: boolean;
|
|
18
|
+
pluginCount: number;
|
|
19
|
+
isExpanded: boolean;
|
|
20
|
+
isCommunitySection?: boolean;
|
|
21
|
+
/** Visual tone for the category row */
|
|
22
|
+
tone: "yellow" | "gray" | "green" | "red" | "purple" | "teal" | "byline";
|
|
23
|
+
/** Badge text shown on category row (e.g. "★ Official") */
|
|
24
|
+
badge?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export interface PluginPluginItem {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
id: string;
|
|
29
|
+
kind: "plugin";
|
|
30
|
+
label: string;
|
|
31
|
+
plugin: PluginInfo;
|
|
32
|
+
/** Fuzzy match highlight indices, if search is active */
|
|
33
|
+
matches?: number[];
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export type PluginBrowserItem = PluginCategoryItem | PluginPluginItem;
|
|
@@ -37,38 +38,38 @@ export type PluginBrowserItem = PluginCategoryItem | PluginPluginItem;
|
|
|
37
38
|
// ─── Adapter ─────────────────────────────────────────────────────────────────
|
|
38
39
|
|
|
39
40
|
export interface BuildPluginBrowserItemsArgs {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
marketplaces: Marketplace[];
|
|
42
|
+
plugins: PluginInfo[];
|
|
43
|
+
collapsedMarketplaces: Set<string>;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Derives tone and badge for a category item based on marketplace identity.
|
|
47
48
|
*/
|
|
48
49
|
function categoryStyling(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
mp: Marketplace,
|
|
51
|
+
isCommunitySection: boolean,
|
|
52
|
+
marketplaceEnabled: boolean,
|
|
52
53
|
): { tone: PluginCategoryItem["tone"]; badge?: string } {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
if (!marketplaceEnabled) {
|
|
55
|
+
return { tone: "gray" };
|
|
56
|
+
}
|
|
57
|
+
if (isCommunitySection) {
|
|
58
|
+
return { tone: "gray", badge: "3rd Party" };
|
|
59
|
+
}
|
|
60
|
+
if (mp.name === "claude-plugins-official") {
|
|
61
|
+
return { tone: "yellow", badge: "★ Official" };
|
|
62
|
+
}
|
|
63
|
+
if (mp.name === "claude-code-plugins") {
|
|
64
|
+
return { tone: "red", badge: "⚠ Deprecated" };
|
|
65
|
+
}
|
|
66
|
+
if (mp.official) {
|
|
67
|
+
return { tone: "yellow", badge: "★ Official" };
|
|
68
|
+
}
|
|
69
|
+
if (isMadAppGang(mp)) {
|
|
70
|
+
return { tone: "byline", badge: "by MadAppGang" };
|
|
71
|
+
}
|
|
72
|
+
return { tone: "green", badge: "✓ Added" };
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
/**
|
|
@@ -78,7 +79,7 @@ function categoryStyling(
|
|
|
78
79
|
* marketplace sort uses to float MadAppGang entries to the top.
|
|
79
80
|
*/
|
|
80
81
|
function isMadAppGang(mp: Marketplace): boolean {
|
|
81
|
-
|
|
82
|
+
return (mp.source.repo ?? "").toLowerCase().startsWith("madappgang/");
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/**
|
|
@@ -86,128 +87,133 @@ function isMadAppGang(mp: Marketplace): boolean {
|
|
|
86
87
|
* Extracted from PluginsScreen so it can be tested independently.
|
|
87
88
|
*/
|
|
88
89
|
export function buildPluginBrowserItems({
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
marketplaces,
|
|
91
|
+
plugins,
|
|
92
|
+
collapsedMarketplaces,
|
|
92
93
|
}: BuildPluginBrowserItemsArgs): PluginBrowserItem[] {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
94
|
+
const pluginsByMarketplace = new Map<string, PluginInfo[]>();
|
|
95
|
+
for (const plugin of plugins) {
|
|
96
|
+
const existing = pluginsByMarketplace.get(plugin.marketplace) || [];
|
|
97
|
+
existing.push(plugin);
|
|
98
|
+
pluginsByMarketplace.set(plugin.marketplace, existing);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Sort marketplaces: our own (magus*) first, deprecated last, others between.
|
|
102
|
+
const rank = (m: Marketplace) =>
|
|
103
|
+
m.owned ? 0 : m.deprecated || m.name === "claude-code-plugins" ? 2 : 1;
|
|
104
|
+
const sortedMarketplaces = [...marketplaces].sort(
|
|
105
|
+
(a, b) => rank(a) - rank(b),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const items: PluginBrowserItem[] = [];
|
|
109
|
+
|
|
110
|
+
for (const marketplace of sortedMarketplaces) {
|
|
111
|
+
const marketplacePlugins = pluginsByMarketplace.get(marketplace.name) || [];
|
|
112
|
+
const isCollapsed = collapsedMarketplaces.has(marketplace.name);
|
|
113
|
+
const isEnabled = marketplacePlugins.length > 0 || !!marketplace.official;
|
|
114
|
+
const hasPlugins = marketplacePlugins.length > 0;
|
|
115
|
+
|
|
116
|
+
// Special handling: split claude-plugins-official into two sub-sections
|
|
117
|
+
if (marketplace.name === SPLIT_MARKETPLACE && hasPlugins) {
|
|
118
|
+
const anthropicPlugins = marketplacePlugins.filter(
|
|
119
|
+
(p) => p.author?.name?.toLowerCase() === "anthropic",
|
|
120
|
+
);
|
|
121
|
+
const communityPlugins = marketplacePlugins.filter(
|
|
122
|
+
(p) => p.author?.name?.toLowerCase() !== "anthropic",
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Sub-section 1: Anthropic Official (plugins by Anthropic)
|
|
126
|
+
const anthropicCollapsed = collapsedMarketplaces.has(marketplace.name);
|
|
127
|
+
const anthropicHasPlugins = anthropicPlugins.length > 0;
|
|
128
|
+
const anthropicStyle = categoryStyling(marketplace, false, isEnabled);
|
|
129
|
+
items.push({
|
|
130
|
+
id: `mp:${marketplace.name}`,
|
|
131
|
+
kind: "category",
|
|
132
|
+
label: marketplace.displayName,
|
|
133
|
+
marketplace,
|
|
134
|
+
marketplaceEnabled: isEnabled,
|
|
135
|
+
pluginCount: anthropicPlugins.length,
|
|
136
|
+
isExpanded: !anthropicCollapsed && anthropicHasPlugins,
|
|
137
|
+
tone: anthropicStyle.tone,
|
|
138
|
+
badge: anthropicStyle.badge,
|
|
139
|
+
});
|
|
140
|
+
if (isEnabled && anthropicHasPlugins && !anthropicCollapsed) {
|
|
141
|
+
for (const plugin of anthropicPlugins) {
|
|
142
|
+
items.push({
|
|
143
|
+
id: `pl:${plugin.id}`,
|
|
144
|
+
kind: "plugin",
|
|
145
|
+
label: plugin.name,
|
|
146
|
+
plugin,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Sub-section 2: Community (third-party plugins in same marketplace)
|
|
152
|
+
if (communityPlugins.length > 0) {
|
|
153
|
+
const communityVirtualMp: Marketplace = {
|
|
154
|
+
name: COMMUNITY_VIRTUAL_MARKETPLACE,
|
|
155
|
+
displayName: "Anthropic Official — 3rd Party",
|
|
156
|
+
source: marketplace.source,
|
|
157
|
+
description:
|
|
158
|
+
"Third-party plugins in the Anthropic Official marketplace",
|
|
159
|
+
};
|
|
160
|
+
const communityCollapsed = collapsedMarketplaces.has(
|
|
161
|
+
COMMUNITY_VIRTUAL_MARKETPLACE,
|
|
162
|
+
);
|
|
163
|
+
const communityStyle = categoryStyling(communityVirtualMp, true, true);
|
|
164
|
+
items.push({
|
|
165
|
+
id: `mp:${COMMUNITY_VIRTUAL_MARKETPLACE}`,
|
|
166
|
+
kind: "category",
|
|
167
|
+
label: "Anthropic Official — 3rd Party",
|
|
168
|
+
marketplace: communityVirtualMp,
|
|
169
|
+
marketplaceEnabled: true,
|
|
170
|
+
pluginCount: communityPlugins.length,
|
|
171
|
+
isExpanded: !communityCollapsed,
|
|
172
|
+
isCommunitySection: true,
|
|
173
|
+
tone: communityStyle.tone,
|
|
174
|
+
badge: communityStyle.badge,
|
|
175
|
+
});
|
|
176
|
+
if (!communityCollapsed) {
|
|
177
|
+
for (const plugin of communityPlugins) {
|
|
178
|
+
items.push({
|
|
179
|
+
id: `pl:${plugin.id}`,
|
|
180
|
+
kind: "plugin",
|
|
181
|
+
label: plugin.name,
|
|
182
|
+
plugin,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Category header (marketplace)
|
|
192
|
+
const style = categoryStyling(marketplace, false, isEnabled);
|
|
193
|
+
items.push({
|
|
194
|
+
id: `mp:${marketplace.name}`,
|
|
195
|
+
kind: "category",
|
|
196
|
+
label: marketplace.displayName,
|
|
197
|
+
marketplace,
|
|
198
|
+
marketplaceEnabled: isEnabled,
|
|
199
|
+
pluginCount: marketplacePlugins.length,
|
|
200
|
+
isExpanded: !isCollapsed && hasPlugins,
|
|
201
|
+
tone: style.tone,
|
|
202
|
+
badge: style.badge,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Plugins under this marketplace (if expanded)
|
|
206
|
+
if (isEnabled && hasPlugins && !isCollapsed) {
|
|
207
|
+
for (const plugin of marketplacePlugins) {
|
|
208
|
+
items.push({
|
|
209
|
+
id: `pl:${plugin.id}`,
|
|
210
|
+
kind: "plugin",
|
|
211
|
+
label: plugin.name,
|
|
212
|
+
plugin,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return items;
|
|
213
219
|
}
|