claudeup 4.35.1 → 4.37.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__/catalog-cache-store.test.ts +271 -0
- package/src/__tests__/catalog-notice.test.ts +155 -0
- package/src/__tests__/github-budget.test.ts +200 -0
- package/src/__tests__/plugin-manager-fallback.test.ts +200 -8
- 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/services/catalog-cache-store.ts +218 -0
- package/src/services/github-budget.ts +274 -0
- package/src/services/marketplace-catalog-git.ts +170 -0
- package/src/services/marketplace-catalog.ts +95 -0
- package/src/services/marketplace-fetcher.ts +310 -87
- package/src/services/plugin-manager.ts +103 -92
- package/src/ui/App.tsx +19 -12
- package/src/ui/adapters/catalogNotice.ts +122 -0
- 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 +46 -26
- 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 +566 -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 +152 -33
- package/src/ui/screens/ProfilesScreen.tsx +39 -23
- package/src/ui/screens/SkillsScreen.tsx +832 -688
- package/src/ui/state/reducer.ts +11 -2
- package/src/ui/state/types.ts +16 -1
- package/src/ui/theme-mode.ts +73 -0
- package/src/ui/theme.ts +147 -53
- package/src/utils/config-dir.ts +47 -0
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type InstallMethod,
|
|
15
15
|
} from "../renderers/cliToolRenderers.js";
|
|
16
16
|
import { ScrollableList } from "../components/ScrollableList.js";
|
|
17
|
+
import { theme } from "../theme.js";
|
|
17
18
|
|
|
18
19
|
const execAsync = promisify(exec);
|
|
19
20
|
|
|
@@ -35,10 +36,17 @@ function parseVersion(versionOutput: string): string | undefined {
|
|
|
35
36
|
|
|
36
37
|
function methodFromPath(binPath: string): InstallMethod | null {
|
|
37
38
|
if (binPath.includes("/.bun/")) return "bun";
|
|
38
|
-
if (binPath.includes("/homebrew/") || binPath.includes("/Cellar/"))
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
39
|
+
if (binPath.includes("/homebrew/") || binPath.includes("/Cellar/"))
|
|
40
|
+
return "brew";
|
|
41
|
+
if (
|
|
42
|
+
binPath.includes("/.local/share/claude") ||
|
|
43
|
+
binPath.includes("/.local/bin/claude")
|
|
44
|
+
)
|
|
45
|
+
return "npm";
|
|
46
|
+
if (binPath.includes("/.nvm/") || binPath.includes("/node_modules/"))
|
|
47
|
+
return "npm";
|
|
48
|
+
if (binPath.includes("/.local/share/pnpm") || binPath.includes("/pnpm/"))
|
|
49
|
+
return "pnpm";
|
|
42
50
|
if (binPath.includes("/.yarn/")) return "yarn";
|
|
43
51
|
return null;
|
|
44
52
|
}
|
|
@@ -50,7 +58,10 @@ interface InstallInfo {
|
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
/** Extract brew formula name from a Cellar symlink target like ../Cellar/gemini-cli/0.35.2/bin/gemini */
|
|
53
|
-
function extractBrewFormula(
|
|
61
|
+
function extractBrewFormula(
|
|
62
|
+
binPath: string,
|
|
63
|
+
linkTarget: string,
|
|
64
|
+
): string | undefined {
|
|
54
65
|
// Try symlink target first: ../Cellar/{formula}/{version}/...
|
|
55
66
|
const cellarMatch = linkTarget.match(/Cellar\/([^/]+)\//);
|
|
56
67
|
if (cellarMatch) return cellarMatch[1];
|
|
@@ -70,8 +81,12 @@ async function detectInstallMethods(
|
|
|
70
81
|
timeout: 3000,
|
|
71
82
|
shell: "/bin/bash",
|
|
72
83
|
});
|
|
73
|
-
const paths = stdout
|
|
74
|
-
|
|
84
|
+
const paths = stdout
|
|
85
|
+
.trim()
|
|
86
|
+
.split("\n")
|
|
87
|
+
.filter((p) => p && !p.includes("aliased"));
|
|
88
|
+
if (paths.length === 0)
|
|
89
|
+
return { primary: fallback as InstallMethod, all: [] };
|
|
75
90
|
|
|
76
91
|
const methods: InstallMethod[] = [];
|
|
77
92
|
let brewFormula: string | undefined;
|
|
@@ -100,38 +115,60 @@ async function detectInstallMethods(
|
|
|
100
115
|
if (method && !methods.includes(method)) methods.push(method);
|
|
101
116
|
}
|
|
102
117
|
|
|
103
|
-
if (methods.length === 0)
|
|
118
|
+
if (methods.length === 0)
|
|
119
|
+
return { primary: fallback as InstallMethod, all: [] };
|
|
104
120
|
return { primary: methods[0]!, all: methods, brewFormula };
|
|
105
121
|
} catch {
|
|
106
122
|
return { primary: fallback as InstallMethod, all: [] };
|
|
107
123
|
}
|
|
108
124
|
}
|
|
109
125
|
|
|
110
|
-
function getUninstallCommand(
|
|
126
|
+
function getUninstallCommand(
|
|
127
|
+
tool: import("../../data/cli-tools.js").CliTool,
|
|
128
|
+
method: InstallMethod,
|
|
129
|
+
brewFormula?: string,
|
|
130
|
+
): string {
|
|
111
131
|
switch (method) {
|
|
112
|
-
case "bun":
|
|
113
|
-
|
|
114
|
-
case "
|
|
115
|
-
|
|
116
|
-
case "
|
|
117
|
-
|
|
118
|
-
|
|
132
|
+
case "bun":
|
|
133
|
+
return `bun remove -g ${tool.packageName}`;
|
|
134
|
+
case "npm":
|
|
135
|
+
return `npm uninstall -g ${tool.packageName}`;
|
|
136
|
+
case "pnpm":
|
|
137
|
+
return `pnpm remove -g ${tool.packageName}`;
|
|
138
|
+
case "yarn":
|
|
139
|
+
return `yarn global remove ${tool.packageName}`;
|
|
140
|
+
case "brew":
|
|
141
|
+
return `brew uninstall ${brewFormula || tool.name}`;
|
|
142
|
+
case "pip":
|
|
143
|
+
return `pip uninstall -y ${tool.packageName}`;
|
|
144
|
+
default:
|
|
145
|
+
return "";
|
|
119
146
|
}
|
|
120
147
|
}
|
|
121
148
|
|
|
122
|
-
function getUpdateCommand(
|
|
149
|
+
function getUpdateCommand(
|
|
150
|
+
tool: import("../../data/cli-tools.js").CliTool,
|
|
151
|
+
method: InstallMethod,
|
|
152
|
+
brewFormula?: string,
|
|
153
|
+
): string {
|
|
123
154
|
switch (method) {
|
|
124
|
-
case "bun":
|
|
125
|
-
|
|
126
|
-
case "
|
|
127
|
-
|
|
128
|
-
case "
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
case "bun":
|
|
156
|
+
return `bun install -g ${tool.packageName}`;
|
|
157
|
+
case "npm":
|
|
158
|
+
return `npm install -g ${tool.packageName}`;
|
|
159
|
+
case "pnpm":
|
|
160
|
+
return `pnpm install -g ${tool.packageName}`;
|
|
161
|
+
case "yarn":
|
|
162
|
+
return `yarn global add ${tool.packageName}`;
|
|
163
|
+
case "brew":
|
|
164
|
+
return `brew upgrade ${brewFormula || tool.name}`;
|
|
165
|
+
case "pip":
|
|
166
|
+
return tool.installCommand;
|
|
167
|
+
default:
|
|
168
|
+
return tool.installCommand;
|
|
131
169
|
}
|
|
132
170
|
}
|
|
133
171
|
|
|
134
|
-
|
|
135
172
|
async function getInstalledVersion(
|
|
136
173
|
tool: import("../../data/cli-tools.js").CliTool,
|
|
137
174
|
): Promise<string | undefined> {
|
|
@@ -143,7 +180,9 @@ async function getInstalledVersion(
|
|
|
143
180
|
}
|
|
144
181
|
}
|
|
145
182
|
|
|
146
|
-
async function getLatestNpmVersion(
|
|
183
|
+
async function getLatestNpmVersion(
|
|
184
|
+
packageName: string,
|
|
185
|
+
): Promise<string | undefined> {
|
|
147
186
|
try {
|
|
148
187
|
const { stdout } = await execAsync(
|
|
149
188
|
`npm view ${packageName} version 2>/dev/null`,
|
|
@@ -155,7 +194,9 @@ async function getLatestNpmVersion(packageName: string): Promise<string | undefi
|
|
|
155
194
|
}
|
|
156
195
|
}
|
|
157
196
|
|
|
158
|
-
async function getLatestPipVersion(
|
|
197
|
+
async function getLatestPipVersion(
|
|
198
|
+
packageName: string,
|
|
199
|
+
): Promise<string | undefined> {
|
|
159
200
|
try {
|
|
160
201
|
const { stdout } = await execAsync(
|
|
161
202
|
`pip index versions ${packageName} 2>/dev/null | head -1`,
|
|
@@ -247,12 +288,12 @@ export function CliToolsScreen() {
|
|
|
247
288
|
latestVersion: latest,
|
|
248
289
|
checking: false,
|
|
249
290
|
hasUpdate:
|
|
250
|
-
version && latest
|
|
251
|
-
? compareVersions(version, latest) < 0
|
|
252
|
-
: false,
|
|
291
|
+
version && latest ? compareVersions(version, latest) < 0 : false,
|
|
253
292
|
installMethod: version ? info.primary : undefined,
|
|
254
293
|
allMethods: version && info.all.length > 1 ? info.all : undefined,
|
|
255
|
-
updateCommand: version
|
|
294
|
+
updateCommand: version
|
|
295
|
+
? getUpdateCommand(tool, info.primary, info.brewFormula)
|
|
296
|
+
: undefined,
|
|
256
297
|
brewFormula: info.brewFormula,
|
|
257
298
|
});
|
|
258
299
|
});
|
|
@@ -304,7 +345,9 @@ export function CliToolsScreen() {
|
|
|
304
345
|
fetchVersionInfo();
|
|
305
346
|
};
|
|
306
347
|
|
|
307
|
-
const runCommand = async (
|
|
348
|
+
const runCommand = async (
|
|
349
|
+
command: string,
|
|
350
|
+
): Promise<{ ok: boolean; error?: string }> => {
|
|
308
351
|
try {
|
|
309
352
|
await execAsync(command, {
|
|
310
353
|
shell: "/bin/bash",
|
|
@@ -322,8 +365,13 @@ export function CliToolsScreen() {
|
|
|
322
365
|
if (!status) return;
|
|
323
366
|
|
|
324
367
|
const { tool, installed, hasUpdate, updateCommand } = status;
|
|
325
|
-
const action = !installed
|
|
326
|
-
|
|
368
|
+
const action = !installed
|
|
369
|
+
? "Installing"
|
|
370
|
+
: hasUpdate
|
|
371
|
+
? "Updating"
|
|
372
|
+
: "Reinstalling";
|
|
373
|
+
const command =
|
|
374
|
+
installed && updateCommand ? updateCommand : tool.installCommand;
|
|
327
375
|
|
|
328
376
|
modal.loading(`${action} ${tool.displayName}...`);
|
|
329
377
|
const result = await runCommand(command);
|
|
@@ -386,7 +434,11 @@ export function CliToolsScreen() {
|
|
|
386
434
|
const handleUpdateAll = async () => {
|
|
387
435
|
const updatable = toolStatuses.filter((s) => s.hasUpdate);
|
|
388
436
|
if (updatable.length === 0) {
|
|
389
|
-
await modal.message(
|
|
437
|
+
await modal.message(
|
|
438
|
+
"Up to Date",
|
|
439
|
+
"All tools are already up to date.",
|
|
440
|
+
"info",
|
|
441
|
+
);
|
|
390
442
|
return;
|
|
391
443
|
}
|
|
392
444
|
|
|
@@ -406,15 +458,15 @@ export function CliToolsScreen() {
|
|
|
406
458
|
const installedCount = toolStatuses.filter((s) => s.installed).length;
|
|
407
459
|
const updateCount = toolStatuses.filter((s) => s.hasUpdate).length;
|
|
408
460
|
const statusContent = (
|
|
409
|
-
<text>
|
|
410
|
-
<span fg=
|
|
411
|
-
<span fg=
|
|
461
|
+
<text fg={theme.colors.text}>
|
|
462
|
+
<span fg={theme.colors.muted}>Installed: </span>
|
|
463
|
+
<span fg={theme.colors.info}>
|
|
412
464
|
{installedCount}/{toolStatuses.length}
|
|
413
465
|
</span>
|
|
414
466
|
{updateCount > 0 && (
|
|
415
467
|
<>
|
|
416
|
-
<span fg=
|
|
417
|
-
<span fg=
|
|
468
|
+
<span fg={theme.colors.muted}> │ Updates: </span>
|
|
469
|
+
<span fg={theme.colors.warning}>{updateCount}</span>
|
|
418
470
|
</>
|
|
419
471
|
)}
|
|
420
472
|
</text>
|
|
@@ -3,9 +3,7 @@ import { useApp, useModal } from "../state/AppContext.js";
|
|
|
3
3
|
import { useDimensions } from "../state/DimensionsContext.js";
|
|
4
4
|
import { useKeyboard } from "../hooks/useKeyboard.js";
|
|
5
5
|
import { ScreenLayout } from "../components/layout/index.js";
|
|
6
|
-
import {
|
|
7
|
-
SETTINGS_CATALOG,
|
|
8
|
-
} from "../../data/settings-catalog.js";
|
|
6
|
+
import { SETTINGS_CATALOG } from "../../data/settings-catalog.js";
|
|
9
7
|
import {
|
|
10
8
|
readAllSettingsBothScopes,
|
|
11
9
|
writeSettingValue,
|
|
@@ -15,8 +13,12 @@ import {
|
|
|
15
13
|
buildSettingsBrowserItems,
|
|
16
14
|
type SettingsBrowserItem,
|
|
17
15
|
} from "../adapters/settingsAdapter.js";
|
|
18
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
renderSettingRow,
|
|
18
|
+
renderSettingDetail,
|
|
19
|
+
} from "../renderers/settingsRenderers.js";
|
|
19
20
|
import { ScrollableList } from "../components/ScrollableList.js";
|
|
21
|
+
import { theme } from "../theme.js";
|
|
20
22
|
|
|
21
23
|
export function SettingsScreen() {
|
|
22
24
|
const { state, dispatch } = useApp();
|
|
@@ -28,9 +30,13 @@ export function SettingsScreen() {
|
|
|
28
30
|
dispatch({ type: "SETTINGS_DATA_LOADING" });
|
|
29
31
|
try {
|
|
30
32
|
// Populate dynamic output style options from installed plugins
|
|
31
|
-
const outputStyleSetting = SETTINGS_CATALOG.find(
|
|
33
|
+
const outputStyleSetting = SETTINGS_CATALOG.find(
|
|
34
|
+
(s) => s.id === "output-style",
|
|
35
|
+
);
|
|
32
36
|
if (outputStyleSetting && outputStyleSetting.type === "select") {
|
|
33
|
-
outputStyleSetting.options = await discoverOutputStyles(
|
|
37
|
+
outputStyleSetting.options = await discoverOutputStyles(
|
|
38
|
+
state.projectPath,
|
|
39
|
+
);
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
const values = await readAllSettingsBothScopes(
|
|
@@ -157,10 +163,10 @@ export function SettingsScreen() {
|
|
|
157
163
|
|
|
158
164
|
const renderDetail = () => {
|
|
159
165
|
if (settings.values.status === "loading") {
|
|
160
|
-
return <text fg=
|
|
166
|
+
return <text fg={theme.colors.muted}>Loading settings...</text>;
|
|
161
167
|
}
|
|
162
168
|
if (settings.values.status === "error") {
|
|
163
|
-
return <text fg=
|
|
169
|
+
return <text fg={theme.colors.danger}>Failed to load settings</text>;
|
|
164
170
|
}
|
|
165
171
|
return renderSettingDetail(selectedItem);
|
|
166
172
|
};
|
|
@@ -173,10 +179,10 @@ export function SettingsScreen() {
|
|
|
173
179
|
: 0;
|
|
174
180
|
|
|
175
181
|
const statusContent = (
|
|
176
|
-
<text>
|
|
177
|
-
<span fg=
|
|
178
|
-
<span fg=
|
|
179
|
-
<span fg=
|
|
182
|
+
<text fg={theme.colors.text}>
|
|
183
|
+
<span fg={theme.colors.muted}>Settings: </span>
|
|
184
|
+
<span fg={theme.colors.info}>{totalSet} configured</span>
|
|
185
|
+
<span fg={theme.colors.muted}> │ u:user p:project</span>
|
|
180
186
|
</text>
|
|
181
187
|
);
|
|
182
188
|
|
|
@@ -193,7 +199,7 @@ export function SettingsScreen() {
|
|
|
193
199
|
]}
|
|
194
200
|
listPanel={
|
|
195
201
|
settings.values.status !== "success" ? (
|
|
196
|
-
<text fg=
|
|
202
|
+
<text fg={theme.colors.muted}>
|
|
197
203
|
{settings.values.status === "loading"
|
|
198
204
|
? "Loading..."
|
|
199
205
|
: "Error loading settings"}
|