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
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { ItemRenderer } from "../registry.js";
|
|
3
3
|
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
SettingsBrowserItem,
|
|
5
|
+
SettingsCategoryItem,
|
|
6
|
+
SettingsSettingItem,
|
|
7
7
|
} from "../adapters/settingsAdapter.js";
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
CATEGORY_LABELS,
|
|
10
|
+
CATEGORY_BG,
|
|
11
|
+
CATEGORY_COLOR,
|
|
12
|
+
CATEGORY_DESCRIPTIONS,
|
|
13
|
+
formatValue,
|
|
14
14
|
} from "../adapters/settingsAdapter.js";
|
|
15
15
|
import { SelectableRow, MetaText } from "../components/primitives/index.js";
|
|
16
16
|
import { theme } from "../theme.js";
|
|
@@ -18,193 +18,200 @@ import { theme } from "../theme.js";
|
|
|
18
18
|
// ─── Category renderer ─────────────────────────────────────────────────────────
|
|
19
19
|
|
|
20
20
|
const categoryRenderer: ItemRenderer<SettingsCategoryItem> = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
21
|
+
renderRow: ({ item, isSelected }) => {
|
|
22
|
+
const star = item.category === "recommended" ? "★ " : "";
|
|
23
|
+
const label = `${star}${CATEGORY_LABELS[item.category]}`;
|
|
24
|
+
const bg = isSelected ? theme.selection.bg : CATEGORY_BG[item.category];
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<box width="100%">
|
|
28
|
+
<text bg={bg} fg={theme.hints.fg}>
|
|
29
|
+
<strong> {label} </strong>
|
|
30
|
+
</text>
|
|
31
|
+
</box>
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
renderDetail: ({ item }) => {
|
|
36
|
+
const cat = item.category;
|
|
37
|
+
return (
|
|
38
|
+
<box flexDirection="column">
|
|
39
|
+
<text fg={CATEGORY_COLOR[cat]}>
|
|
40
|
+
<strong>{CATEGORY_LABELS[cat]}</strong>
|
|
41
|
+
</text>
|
|
42
|
+
<box marginTop={1}>
|
|
43
|
+
<text fg={theme.colors.muted}>{CATEGORY_DESCRIPTIONS[cat]}</text>
|
|
44
|
+
</box>
|
|
45
|
+
</box>
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
// ─── Setting renderer ──────────────────────────────────────────────────────────
|
|
51
51
|
|
|
52
52
|
const settingRenderer: ItemRenderer<SettingsSettingItem> = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
53
|
+
renderRow: ({ item, isSelected }) => {
|
|
54
|
+
const { setting } = item;
|
|
55
|
+
const indicator = item.isDefault ? "○" : "●";
|
|
56
|
+
const displayValue = formatValue(setting, item.effectiveValue);
|
|
57
|
+
|
|
58
|
+
if (isSelected) {
|
|
59
|
+
return (
|
|
60
|
+
<text bg={theme.selection.bg} fg={theme.selection.fg}>
|
|
61
|
+
{" "}
|
|
62
|
+
{indicator} {setting.name.padEnd(28)}
|
|
63
|
+
{displayValue}{" "}
|
|
64
|
+
</text>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const indicatorColor = item.isDefault
|
|
69
|
+
? theme.colors.muted
|
|
70
|
+
: theme.colors.info;
|
|
71
|
+
const valueColor = item.isDefault
|
|
72
|
+
? theme.colors.muted
|
|
73
|
+
: theme.colors.success;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<text fg={theme.colors.text}>
|
|
77
|
+
<span fg={indicatorColor}> {indicator} </span>
|
|
78
|
+
<span>{setting.name.padEnd(28)}</span>
|
|
79
|
+
<span fg={valueColor}>{displayValue}</span>
|
|
80
|
+
</text>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
renderDetail: ({ item }) => {
|
|
85
|
+
const { setting } = item;
|
|
86
|
+
const scoped = item.scopedValues;
|
|
87
|
+
const storageDesc =
|
|
88
|
+
setting.storage.type === "attribution"
|
|
89
|
+
? "settings.json: attribution"
|
|
90
|
+
: setting.storage.type === "attribution-text"
|
|
91
|
+
? "settings.json: attribution"
|
|
92
|
+
: setting.storage.type === "env"
|
|
93
|
+
? `env: ${setting.storage.key}`
|
|
94
|
+
: `settings.json: ${setting.storage.key}`;
|
|
95
|
+
|
|
96
|
+
const userValue = formatValue(setting, scoped.user);
|
|
97
|
+
const projectValue = formatValue(setting, scoped.project);
|
|
98
|
+
const userIsSet = scoped.user !== undefined && scoped.user !== "";
|
|
99
|
+
const projectIsSet = scoped.project !== undefined && scoped.project !== "";
|
|
100
|
+
|
|
101
|
+
const actionLabel =
|
|
102
|
+
setting.type === "boolean"
|
|
103
|
+
? "toggle"
|
|
104
|
+
: setting.type === "select"
|
|
105
|
+
? "choose"
|
|
106
|
+
: "edit";
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<box flexDirection="column">
|
|
110
|
+
<text fg={theme.colors.info}>
|
|
111
|
+
<strong>{setting.name}</strong>
|
|
112
|
+
</text>
|
|
113
|
+
<box marginTop={1}>
|
|
114
|
+
<text fg={theme.colors.text}>{setting.description}</text>
|
|
115
|
+
</box>
|
|
116
|
+
|
|
117
|
+
<box marginTop={1}>
|
|
118
|
+
<text fg={theme.colors.text}>
|
|
119
|
+
<span fg={theme.colors.muted}>Stored </span>
|
|
120
|
+
<span fg={theme.colors.link}>{storageDesc}</span>
|
|
121
|
+
</text>
|
|
122
|
+
</box>
|
|
123
|
+
{setting.defaultValue !== undefined && (
|
|
124
|
+
<box>
|
|
125
|
+
<text fg={theme.colors.text}>
|
|
126
|
+
<span fg={theme.colors.muted}>Default </span>
|
|
127
|
+
<span>{setting.defaultValue}</span>
|
|
128
|
+
</text>
|
|
129
|
+
</box>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
<box flexDirection="column" marginTop={1}>
|
|
133
|
+
<text fg={theme.colors.text}>{"────────────────────────"}</text>
|
|
134
|
+
<text fg={theme.colors.text}>
|
|
135
|
+
<strong>Scopes:</strong>
|
|
136
|
+
</text>
|
|
137
|
+
<box marginTop={1} flexDirection="column">
|
|
138
|
+
<text fg={theme.colors.text}>
|
|
139
|
+
<span bg={theme.scopes.user} fg={theme.hints.fg}>
|
|
140
|
+
{" "}
|
|
141
|
+
u{" "}
|
|
142
|
+
</span>
|
|
143
|
+
<span fg={userIsSet ? theme.scopes.user : theme.colors.muted}>
|
|
144
|
+
{userIsSet ? " ● " : " ○ "}
|
|
145
|
+
</span>
|
|
146
|
+
<span fg={theme.scopes.user}>User</span>
|
|
147
|
+
<span> global</span>
|
|
148
|
+
<span fg={userIsSet ? theme.scopes.user : theme.colors.muted}>
|
|
149
|
+
{" "}
|
|
150
|
+
{userValue}
|
|
151
|
+
</span>
|
|
152
|
+
</text>
|
|
153
|
+
<text fg={theme.colors.text}>
|
|
154
|
+
<span bg={theme.scopes.project} fg={theme.hints.fg}>
|
|
155
|
+
{" "}
|
|
156
|
+
p{" "}
|
|
157
|
+
</span>
|
|
158
|
+
<span
|
|
159
|
+
fg={projectIsSet ? theme.scopes.project : theme.colors.muted}
|
|
160
|
+
>
|
|
161
|
+
{projectIsSet ? " ● " : " ○ "}
|
|
162
|
+
</span>
|
|
163
|
+
<span fg={theme.scopes.project}>Project</span>
|
|
164
|
+
<span> team</span>
|
|
165
|
+
<span
|
|
166
|
+
fg={projectIsSet ? theme.scopes.project : theme.colors.muted}
|
|
167
|
+
>
|
|
168
|
+
{" "}
|
|
169
|
+
{projectValue}
|
|
170
|
+
</span>
|
|
171
|
+
</text>
|
|
172
|
+
</box>
|
|
173
|
+
</box>
|
|
174
|
+
|
|
175
|
+
<box marginTop={1}>
|
|
176
|
+
<text fg={theme.colors.muted}>
|
|
177
|
+
Press u/p to {actionLabel} in scope
|
|
178
|
+
</text>
|
|
179
|
+
</box>
|
|
180
|
+
</box>
|
|
181
|
+
);
|
|
182
|
+
},
|
|
177
183
|
};
|
|
178
184
|
|
|
179
185
|
// ─── Dispatch helpers ──────────────────────────────────────────────────────────
|
|
180
186
|
|
|
181
187
|
export const settingsRenderers: {
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
category: ItemRenderer<SettingsCategoryItem>;
|
|
189
|
+
setting: ItemRenderer<SettingsSettingItem>;
|
|
184
190
|
} = {
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
category: categoryRenderer,
|
|
192
|
+
setting: settingRenderer,
|
|
187
193
|
};
|
|
188
194
|
|
|
189
195
|
export function renderSettingRow(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
item: SettingsBrowserItem,
|
|
197
|
+
_index: number,
|
|
198
|
+
isSelected: boolean,
|
|
193
199
|
): React.ReactNode {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
if (item.kind === "category") {
|
|
201
|
+
return settingsRenderers.category.renderRow({ item, isSelected });
|
|
202
|
+
}
|
|
203
|
+
return settingsRenderers.setting.renderRow({ item, isSelected });
|
|
198
204
|
}
|
|
199
205
|
|
|
200
206
|
export function renderSettingDetail(
|
|
201
|
-
|
|
207
|
+
item: SettingsBrowserItem | undefined,
|
|
202
208
|
): React.ReactNode {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
209
|
+
if (!item)
|
|
210
|
+
return <text fg={theme.colors.muted}>Select a setting to see details</text>;
|
|
211
|
+
if (item.kind === "category") {
|
|
212
|
+
return settingsRenderers.category.renderDetail({ item });
|
|
213
|
+
}
|
|
214
|
+
return settingsRenderers.setting.renderDetail({ item });
|
|
208
215
|
}
|
|
209
216
|
|
|
210
217
|
// Suppress unused import warning — MetaText may be used in future extensions
|