claudeup 4.35.0 → 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__/git-worktree.test.ts +108 -0
- 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/__tests__/worktree-registry-resolution.test.ts +107 -0
- package/src/main.tsx +21 -5
- package/src/opentui.d.ts +21 -12
- package/src/services/claude-settings.ts +37 -7
- package/src/services/git-worktree.ts +129 -0
- package/src/services/plugin-manager.ts +10 -1
- 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
|
@@ -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
|
}
|