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.
Files changed (72) hide show
  1. package/package.json +4 -4
  2. package/src/__tests__/catalog-cache-store.test.ts +271 -0
  3. package/src/__tests__/catalog-notice.test.ts +155 -0
  4. package/src/__tests__/github-budget.test.ts +200 -0
  5. package/src/__tests__/plugin-manager-fallback.test.ts +200 -8
  6. package/src/__tests__/scope-squares.test.tsx +165 -0
  7. package/src/__tests__/theme-adaptive-colors.test.ts +307 -0
  8. package/src/__tests__/uppercase-keybindings.test.ts +101 -0
  9. package/src/main.tsx +21 -5
  10. package/src/opentui.d.ts +21 -12
  11. package/src/services/catalog-cache-store.ts +218 -0
  12. package/src/services/github-budget.ts +274 -0
  13. package/src/services/marketplace-catalog-git.ts +170 -0
  14. package/src/services/marketplace-catalog.ts +95 -0
  15. package/src/services/marketplace-fetcher.ts +310 -87
  16. package/src/services/plugin-manager.ts +103 -92
  17. package/src/ui/App.tsx +19 -12
  18. package/src/ui/adapters/catalogNotice.ts +122 -0
  19. package/src/ui/adapters/pluginsAdapter.ts +174 -168
  20. package/src/ui/adapters/settingsAdapter.ts +119 -116
  21. package/src/ui/adapters/skillsAdapter.ts +203 -196
  22. package/src/ui/components/CategoryHeader.tsx +9 -8
  23. package/src/ui/components/EmptyFilterState.tsx +10 -5
  24. package/src/ui/components/FlagDetailEditor.tsx +0 -0
  25. package/src/ui/components/ScopeIndicator.tsx +10 -6
  26. package/src/ui/components/ScrollableList.tsx +3 -2
  27. package/src/ui/components/SearchInput.tsx +2 -1
  28. package/src/ui/components/StyledText.tsx +5 -4
  29. package/src/ui/components/TabBar.tsx +4 -3
  30. package/src/ui/components/layout/FooterHints.tsx +37 -30
  31. package/src/ui/components/layout/Panel.tsx +6 -5
  32. package/src/ui/components/layout/ProgressBar.tsx +7 -6
  33. package/src/ui/components/layout/ScopeTabs.tsx +6 -5
  34. package/src/ui/components/layout/ScreenLayout.tsx +46 -26
  35. package/src/ui/components/layout/index.ts +3 -3
  36. package/src/ui/components/modals/ConfirmModal.tsx +12 -11
  37. package/src/ui/components/modals/InputModal.tsx +14 -6
  38. package/src/ui/components/modals/LoadingModal.tsx +6 -5
  39. package/src/ui/components/modals/MessageModal.tsx +9 -8
  40. package/src/ui/components/modals/SelectModal.tsx +11 -7
  41. package/src/ui/components/modals/VersionMismatchModal.tsx +14 -16
  42. package/src/ui/components/primitives/ActionHints.tsx +26 -26
  43. package/src/ui/components/primitives/DetailSection.tsx +13 -12
  44. package/src/ui/components/primitives/KeyValueLine.tsx +9 -8
  45. package/src/ui/components/primitives/ListCategoryRow.tsx +25 -27
  46. package/src/ui/components/primitives/MetaText.tsx +3 -3
  47. package/src/ui/components/primitives/ScopeDetail.tsx +48 -48
  48. package/src/ui/components/primitives/ScopeSquares.tsx +47 -22
  49. package/src/ui/components/primitives/SelectableRow.tsx +22 -16
  50. package/src/ui/hooks/useGitignoreModal.ts +78 -74
  51. package/src/ui/registry.ts +11 -11
  52. package/src/ui/renderers/cliToolRenderers.tsx +260 -203
  53. package/src/ui/renderers/gitignoreRenderers.tsx +43 -42
  54. package/src/ui/renderers/mcpRenderers.tsx +121 -117
  55. package/src/ui/renderers/pluginRenderers.tsx +566 -471
  56. package/src/ui/renderers/profileRenderers.tsx +346 -300
  57. package/src/ui/renderers/settingsRenderers.tsx +183 -176
  58. package/src/ui/renderers/skillRenderers.tsx +410 -326
  59. package/src/ui/screens/AliasScreen.tsx +1336 -1309
  60. package/src/ui/screens/CliToolsScreen.tsx +92 -40
  61. package/src/ui/screens/EnvVarsScreen.tsx +19 -13
  62. package/src/ui/screens/GitignoreScreen.tsx +510 -493
  63. package/src/ui/screens/McpRegistryScreen.tsx +28 -21
  64. package/src/ui/screens/McpScreen.tsx +12 -3
  65. package/src/ui/screens/PluginsScreen.tsx +152 -33
  66. package/src/ui/screens/ProfilesScreen.tsx +39 -23
  67. package/src/ui/screens/SkillsScreen.tsx +832 -688
  68. package/src/ui/state/reducer.ts +11 -2
  69. package/src/ui/state/types.ts +16 -1
  70. package/src/ui/theme-mode.ts +73 -0
  71. package/src/ui/theme.ts +147 -53
  72. package/src/utils/config-dir.ts +47 -0
@@ -5,141 +5,145 @@ import { theme } from "../theme.js";
5
5
  // ─── List item types ───────────────────────────────────────────────────────────
6
6
 
7
7
  export type McpListItem =
8
- | { kind: "category"; label: string }
9
- | { kind: "server"; server: McpServer; isInstalled: boolean };
8
+ | { kind: "category"; label: string }
9
+ | { kind: "server"; server: McpServer; isInstalled: boolean };
10
10
 
11
11
  // ─── Row renderers ─────────────────────────────────────────────────────────────
12
12
 
13
13
  export function renderMcpRow(
14
- item: McpListItem,
15
- _index: number,
16
- isSelected: boolean,
14
+ item: McpListItem,
15
+ _index: number,
16
+ isSelected: boolean,
17
17
  ): React.ReactNode {
18
- if (item.kind === "category") {
19
- return (
20
- <text fg={theme.selection.bg}>
21
- <strong>{"▸ "}{item.label}</strong>
22
- </text>
23
- );
24
- }
18
+ if (item.kind === "category") {
19
+ return (
20
+ <text fg={theme.selection.bg}>
21
+ <strong>
22
+ {"▸ "}
23
+ {item.label}
24
+ </strong>
25
+ </text>
26
+ );
27
+ }
25
28
 
26
- const { server, isInstalled } = item;
27
- const icon = isInstalled ? "●" : "○";
28
- const iconColor = isInstalled ? theme.colors.success : theme.colors.muted;
29
+ const { server, isInstalled } = item;
30
+ const icon = isInstalled ? "●" : "○";
31
+ const iconColor = isInstalled ? theme.colors.success : theme.colors.muted;
29
32
 
30
- if (isSelected) {
31
- return (
32
- <text bg={theme.selection.bg} fg={theme.selection.fg}>
33
- {" "}
34
- {icon} {server.name}{" "}
35
- </text>
36
- );
37
- }
33
+ if (isSelected) {
34
+ return (
35
+ <text bg={theme.selection.bg} fg={theme.selection.fg}>
36
+ {" "}
37
+ {icon} {server.name}{" "}
38
+ </text>
39
+ );
40
+ }
38
41
 
39
- return (
40
- <text>
41
- <span fg={iconColor}>{icon}</span>
42
- <span fg={theme.colors.text}> {server.name}</span>
43
- {server.requiresConfig ? (
44
- <span fg={theme.colors.warning}> ⚙</span>
45
- ) : null}
46
- </text>
47
- );
42
+ return (
43
+ <text fg={theme.colors.text}>
44
+ <span fg={iconColor}>{icon}</span>
45
+ <span fg={theme.colors.text}> {server.name}</span>
46
+ {server.requiresConfig ? <span fg={theme.colors.warning}> ⚙</span> : null}
47
+ </text>
48
+ );
48
49
  }
49
50
 
50
51
  // ─── Detail renderer ───────────────────────────────────────────────────────────
51
52
 
52
53
  export function renderMcpDetail(
53
- item: McpListItem | undefined,
54
- loading: boolean,
54
+ item: McpListItem | undefined,
55
+ loading: boolean,
55
56
  ): React.ReactNode {
56
- if (loading) {
57
- return <text fg={theme.colors.muted}>Loading MCP servers...</text>;
58
- }
57
+ if (loading) {
58
+ return <text fg={theme.colors.muted}>Loading MCP servers...</text>;
59
+ }
59
60
 
60
- if (!item || item.kind === "category") {
61
- return (
62
- <box
63
- flexDirection="column"
64
- alignItems="center"
65
- justifyContent="center"
66
- flexGrow={1}
67
- >
68
- <text fg={theme.colors.muted}>Select a server to see details</text>
69
- </box>
70
- );
71
- }
61
+ if (!item || item.kind === "category") {
62
+ return (
63
+ <box
64
+ flexDirection="column"
65
+ alignItems="center"
66
+ justifyContent="center"
67
+ flexGrow={1}
68
+ >
69
+ <text fg={theme.colors.muted}>Select a server to see details</text>
70
+ </box>
71
+ );
72
+ }
72
73
 
73
- const { server, isInstalled } = item;
74
+ const { server, isInstalled } = item;
74
75
 
75
- return (
76
- <box flexDirection="column">
77
- <box marginBottom={1}>
78
- <text fg={theme.colors.info}>
79
- <strong>{"⚡ "}{server.name}</strong>
80
- </text>
81
- {server.requiresConfig ? (
82
- <text fg={theme.colors.warning}> ⚙</text>
83
- ) : null}
84
- </box>
76
+ return (
77
+ <box flexDirection="column">
78
+ <box marginBottom={1}>
79
+ <text fg={theme.colors.info}>
80
+ <strong>
81
+ {"⚡ "}
82
+ {server.name}
83
+ </strong>
84
+ </text>
85
+ {server.requiresConfig ? (
86
+ <text fg={theme.colors.warning}> ⚙</text>
87
+ ) : null}
88
+ </box>
85
89
 
86
- <text fg={theme.colors.muted}>{server.description}</text>
90
+ <text fg={theme.colors.muted}>{server.description}</text>
87
91
 
88
- <box marginTop={1} flexDirection="column">
89
- <box>
90
- <text fg={theme.colors.muted}>{"Status "}</text>
91
- {isInstalled ? (
92
- <text fg={theme.colors.success}>{"● Installed"}</text>
93
- ) : (
94
- <text fg={theme.colors.muted}>{"○ Not installed"}</text>
95
- )}
96
- </box>
97
- <box>
98
- <text fg={theme.colors.muted}>{"Type "}</text>
99
- <text fg={theme.colors.text}>
100
- {server.type === "http" ? "HTTP" : "Command"}
101
- </text>
102
- </box>
103
- {server.type === "http" ? (
104
- <box>
105
- <text fg={theme.colors.muted}>{"URL "}</text>
106
- <text fg={theme.colors.link}>{server.url}</text>
107
- </box>
108
- ) : (
109
- <box>
110
- <text fg={theme.colors.muted}>{"Command "}</text>
111
- <text fg={theme.colors.info}>{server.command}</text>
112
- </box>
113
- )}
114
- {server.requiresConfig ? (
115
- <box>
116
- <text fg={theme.colors.muted}>{"Config "}</text>
117
- <text fg={theme.colors.warning}>
118
- {server.configFields?.length ?? 0} fields required
119
- </text>
120
- </box>
121
- ) : null}
122
- </box>
92
+ <box marginTop={1} flexDirection="column">
93
+ <box>
94
+ <text fg={theme.colors.muted}>{"Status "}</text>
95
+ {isInstalled ? (
96
+ <text fg={theme.colors.success}>{"● Installed"}</text>
97
+ ) : (
98
+ <text fg={theme.colors.muted}>{"○ Not installed"}</text>
99
+ )}
100
+ </box>
101
+ <box>
102
+ <text fg={theme.colors.muted}>{"Type "}</text>
103
+ <text fg={theme.colors.text}>
104
+ {server.type === "http" ? "HTTP" : "Command"}
105
+ </text>
106
+ </box>
107
+ {server.type === "http" ? (
108
+ <box>
109
+ <text fg={theme.colors.muted}>{"URL "}</text>
110
+ <text fg={theme.colors.link}>{server.url}</text>
111
+ </box>
112
+ ) : (
113
+ <box>
114
+ <text fg={theme.colors.muted}>{"Command "}</text>
115
+ <text fg={theme.colors.info}>{server.command}</text>
116
+ </box>
117
+ )}
118
+ {server.requiresConfig ? (
119
+ <box>
120
+ <text fg={theme.colors.muted}>{"Config "}</text>
121
+ <text fg={theme.colors.warning}>
122
+ {server.configFields?.length ?? 0} fields required
123
+ </text>
124
+ </box>
125
+ ) : null}
126
+ </box>
123
127
 
124
- <box marginTop={2}>
125
- {isInstalled ? (
126
- <box>
127
- <text bg={theme.colors.danger} fg="white">
128
- {" "}
129
- Enter{" "}
130
- </text>
131
- <text fg={theme.colors.muted}> Remove server</text>
132
- </box>
133
- ) : (
134
- <box>
135
- <text bg={theme.colors.success} fg="black">
136
- {" "}
137
- Enter{" "}
138
- </text>
139
- <text fg={theme.colors.muted}> Install server</text>
140
- </box>
141
- )}
142
- </box>
143
- </box>
144
- );
128
+ <box marginTop={2}>
129
+ {isInstalled ? (
130
+ <box>
131
+ <text bg={theme.colors.danger} fg={theme.hints.fg}>
132
+ {" "}
133
+ Enter{" "}
134
+ </text>
135
+ <text fg={theme.colors.muted}> Remove server</text>
136
+ </box>
137
+ ) : (
138
+ <box>
139
+ <text bg={theme.colors.success} fg={theme.hints.fg}>
140
+ {" "}
141
+ Enter{" "}
142
+ </text>
143
+ <text fg={theme.colors.muted}> Install server</text>
144
+ </box>
145
+ )}
146
+ </box>
147
+ </box>
148
+ );
145
149
  }