claudeup 4.18.0 → 4.22.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/bin/claudeup.js +43 -19
- package/package.json +14 -19
- package/scripts/build-binaries.ts +77 -0
- package/scripts/check-optional-deps.ts +49 -0
- package/scripts/test-isolated.ts +43 -0
- package/src/__tests__/alias-adopt.test.ts +364 -0
- package/src/__tests__/alias-parser.test.ts +92 -0
- package/src/__tests__/alias-shell-writer.test.ts +7 -0
- package/src/__tests__/alias-store.test.ts +77 -0
- package/src/__tests__/cli-router.test.ts +65 -0
- package/src/__tests__/conventions-integration.test.ts +745 -0
- package/src/__tests__/conventions-manager.test.ts +1172 -0
- package/src/__tests__/doctor-bins.test.ts +35 -0
- package/src/__tests__/doctor.test.ts +450 -0
- package/src/__tests__/dual-write-prevention.test.ts +14 -4
- package/src/__tests__/file-locking.test.ts +208 -0
- package/src/__tests__/gitignore-prerun.test.ts +1 -0
- package/src/__tests__/install-command.test.ts +81 -0
- package/src/__tests__/install-plan.test.ts +98 -0
- package/src/__tests__/manifest.test.ts +136 -0
- package/src/__tests__/marketplace-refresh.test.ts +267 -0
- package/src/__tests__/plugin-requires.test.ts +133 -0
- package/src/__tests__/plugin-setup.test.ts +118 -0
- package/src/__tests__/profile-command.test.ts +116 -0
- package/src/__tests__/profile-materializer.test.ts +82 -0
- package/src/__tests__/profile-sync.test.ts +136 -0
- package/src/__tests__/registry-version-resolution.test.ts +74 -0
- package/src/__tests__/resolve-executable.test.ts +42 -0
- package/src/__tests__/resolver.test.ts +218 -0
- package/src/__tests__/symlink-manager.test.ts +99 -0
- package/src/__tests__/toolchain.test.ts +56 -0
- package/src/cli/claude.ts +21 -0
- package/src/cli/doctor.ts +132 -0
- package/src/cli/install.ts +360 -0
- package/src/cli/profile.ts +166 -0
- package/src/cli/router.ts +107 -0
- package/src/cli/update.ts +85 -0
- package/src/data/alias-flags.ts +11 -1
- package/src/data/cli-tools.ts +7 -7
- package/src/data/gitignore-defaults.ts +4 -0
- package/src/data/marketplaces.ts +12 -0
- package/src/data/predefined-profiles.ts +3 -4
- package/src/main.tsx +11 -154
- package/src/prerunner/index.ts +62 -27
- package/src/services/alias-shell-writer.ts +382 -8
- package/src/services/alias-store.ts +60 -0
- package/src/services/claude-cli.ts +19 -22
- package/src/services/claude-settings.ts +99 -26
- package/src/services/conventions-manager.ts +865 -0
- package/src/services/doctor-bins.ts +49 -0
- package/src/services/doctor.ts +509 -0
- package/src/services/install-plan.ts +107 -0
- package/src/services/manifest.ts +166 -0
- package/src/services/marketplace-refresh.ts +173 -0
- package/src/services/plugin-manager.ts +7 -1
- package/src/services/plugin-requires.ts +215 -0
- package/src/services/plugin-setup.ts +61 -4
- package/src/services/plugin-version-check.ts +9 -4
- package/src/services/profile-materializer.ts +61 -0
- package/src/services/profile-sync.ts +150 -0
- package/src/services/resolver.ts +293 -0
- package/src/services/symlink-manager.ts +146 -0
- package/src/services/toolchain.ts +97 -0
- package/src/services/version-check.ts +10 -11
- package/src/types/index.ts +138 -31
- package/src/ui/App.tsx +16 -11
- package/src/ui/components/FlagDetailEditor.tsx +0 -0
- package/src/ui/components/modals/ConfirmModal.tsx +1 -1
- package/src/ui/screens/AliasScreen.tsx +491 -359
- package/src/ui/screens/CliToolsScreen.tsx +11 -3
- package/src/ui/screens/PluginsScreen.tsx +3 -1
- package/src/ui/screens/index.ts +0 -1
- package/src/ui/state/reducer.ts +6 -102
- package/src/ui/state/types.ts +8 -35
- package/src/utils/command-utils.ts +23 -0
- package/src/utils/file-locking.ts +144 -0
- package/src/data/alias-flags.js +0 -196
- package/src/data/cli-tools.js +0 -123
- package/src/data/gitignore-defaults.js +0 -24
- package/src/data/gitignore-reasons.js +0 -97
- package/src/data/gitignore-templates.js +0 -21
- package/src/data/marketplaces.js +0 -138
- package/src/data/mcp-servers.js +0 -509
- package/src/data/predefined-profiles.js +0 -248
- package/src/data/settings-catalog.js +0 -625
- package/src/data/skill-repos.js +0 -160
- package/src/data/statuslines.js +0 -159
- package/src/data/statuslines.ts +0 -188
- package/src/index.js +0 -4
- package/src/index.ts +0 -5
- package/src/main.js +0 -170
- package/src/prerunner/index.js +0 -252
- package/src/services/alias-settings.js +0 -51
- package/src/services/alias-shell-writer.js +0 -764
- package/src/services/alias-store.js +0 -77
- package/src/services/claude-cli.js +0 -189
- package/src/services/claude-runner.js +0 -28
- package/src/services/claude-settings.js +0 -1223
- package/src/services/gitignore-detector.js +0 -155
- package/src/services/gitignore-fixer.js +0 -231
- package/src/services/gitignore-prerun.js +0 -46
- package/src/services/gitignore-resolver.js +0 -143
- package/src/services/gitignore-service.js +0 -117
- package/src/services/local-marketplace.js +0 -339
- package/src/services/marketplace-fetcher.js +0 -96
- package/src/services/marketplace-sync.js +0 -94
- package/src/services/mcp-registry.js +0 -87
- package/src/services/plugin-manager.js +0 -473
- package/src/services/plugin-mcp-config.js +0 -177
- package/src/services/plugin-setup.js +0 -444
- package/src/services/plugin-version-check.js +0 -262
- package/src/services/profiles.js +0 -161
- package/src/services/settings-manager.js +0 -243
- package/src/services/skills-manager.js +0 -393
- package/src/services/skillsmp-client.js +0 -87
- package/src/services/update-cache.js +0 -52
- package/src/services/version-check.js +0 -99
- package/src/types/gitignore.js +0 -6
- package/src/types/index.js +0 -1
- package/src/ui/App.js +0 -346
- package/src/ui/adapters/pluginsAdapter.js +0 -139
- package/src/ui/adapters/settingsAdapter.js +0 -111
- package/src/ui/adapters/skillsAdapter.js +0 -154
- package/src/ui/components/CategoryHeader.js +0 -9
- package/src/ui/components/EmptyFilterState.js +0 -4
- package/src/ui/components/ScopeIndicator.js +0 -30
- package/src/ui/components/ScrollableList.js +0 -36
- package/src/ui/components/SearchInput.js +0 -19
- package/src/ui/components/StyledText.js +0 -39
- package/src/ui/components/TabBar.js +0 -19
- package/src/ui/components/layout/FooterHints.js +0 -29
- package/src/ui/components/layout/Panel.js +0 -6
- package/src/ui/components/layout/ProgressBar.js +0 -14
- package/src/ui/components/layout/ScopeTabs.js +0 -6
- package/src/ui/components/layout/ScreenLayout.js +0 -16
- package/src/ui/components/layout/index.js +0 -5
- package/src/ui/components/modals/ConfirmModal.js +0 -14
- package/src/ui/components/modals/InputModal.js +0 -5
- package/src/ui/components/modals/LoadingModal.js +0 -17
- package/src/ui/components/modals/MessageModal.js +0 -16
- package/src/ui/components/modals/ModalContainer.js +0 -137
- package/src/ui/components/modals/SelectModal.js +0 -18
- package/src/ui/components/modals/VersionMismatchModal.js +0 -36
- package/src/ui/components/modals/index.js +0 -6
- package/src/ui/components/primitives/ActionHints.js +0 -13
- package/src/ui/components/primitives/DetailSection.js +0 -7
- package/src/ui/components/primitives/KeyValueLine.js +0 -8
- package/src/ui/components/primitives/ListCategoryRow.js +0 -8
- package/src/ui/components/primitives/MetaText.js +0 -8
- package/src/ui/components/primitives/ScopeDetail.js +0 -32
- package/src/ui/components/primitives/ScopeSquares.js +0 -11
- package/src/ui/components/primitives/SelectableRow.js +0 -5
- package/src/ui/components/primitives/index.js +0 -8
- package/src/ui/hooks/index.js +0 -4
- package/src/ui/hooks/useAsyncData.js +0 -77
- package/src/ui/hooks/useGitignoreModal.js +0 -74
- package/src/ui/hooks/useKeyboard.js +0 -13
- package/src/ui/hooks/useKeyboardHandler.js +0 -39
- package/src/ui/hooks/useMismatchModal.js +0 -77
- package/src/ui/registry.js +0 -1
- package/src/ui/renderers/cliToolRenderers.js +0 -54
- package/src/ui/renderers/gitignoreRenderers.js +0 -46
- package/src/ui/renderers/mcpRenderers.js +0 -26
- package/src/ui/renderers/pluginRenderers.js +0 -124
- package/src/ui/renderers/profileRenderers.js +0 -177
- package/src/ui/renderers/settingsRenderers.js +0 -73
- package/src/ui/renderers/skillRenderers.js +0 -138
- package/src/ui/screens/AliasScreen.js +0 -1008
- package/src/ui/screens/CliToolsScreen.js +0 -338
- package/src/ui/screens/EnvVarsScreen.js +0 -152
- package/src/ui/screens/GitignoreScreen.js +0 -328
- package/src/ui/screens/McpRegistryScreen.js +0 -238
- package/src/ui/screens/McpScreen.js +0 -176
- package/src/ui/screens/ModelSelectorScreen.js +0 -296
- package/src/ui/screens/ModelSelectorScreen.tsx +0 -444
- package/src/ui/screens/PluginsScreen.js +0 -766
- package/src/ui/screens/ProfilesScreen.js +0 -298
- package/src/ui/screens/SkillsScreen.js +0 -549
- package/src/ui/screens/StatusLineScreen.js +0 -206
- package/src/ui/screens/StatusLineScreen.tsx +0 -416
- package/src/ui/screens/index.js +0 -10
- package/src/ui/state/AnimationContext.js +0 -34
- package/src/ui/state/AppContext.js +0 -162
- package/src/ui/state/DimensionsContext.js +0 -71
- package/src/ui/state/reducer.js +0 -543
- package/src/ui/state/types.js +0 -1
- package/src/ui/theme.js +0 -47
- package/src/utils/clipboard.js +0 -56
- package/src/utils/command-utils.js +0 -19
- package/src/utils/fuzzy-search.js +0 -101
- package/src/utils/string-utils.js +0 -62
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { CategoryHeader } from "../components/CategoryHeader.js";
|
|
3
|
-
import { SelectableRow, ScopeSquares, ActionHints, MetaText, KeyValueLine, DetailSection, } from "../components/primitives/index.js";
|
|
4
|
-
import { theme } from "../theme.js";
|
|
5
|
-
import { highlightMatches } from "../../utils/fuzzy-search.js";
|
|
6
|
-
// ─── Category renderers ───────────────────────────────────────────────────────
|
|
7
|
-
function categoryRow(item, isSelected) {
|
|
8
|
-
const mp = item.marketplace;
|
|
9
|
-
if (isSelected) {
|
|
10
|
-
const arrow = item.isExpanded ? "▼" : "▶";
|
|
11
|
-
const count = item.pluginCount > 0 ? ` (${item.pluginCount})` : "";
|
|
12
|
-
return (_jsx(SelectableRow, { selected: true, children: _jsxs("strong", { children: [" ", arrow, " ", mp.displayName, count, " "] }) }));
|
|
13
|
-
}
|
|
14
|
-
// Map tone to a statusColor for CategoryHeader (legacy component)
|
|
15
|
-
const statusColorMap = {
|
|
16
|
-
yellow: "yellow",
|
|
17
|
-
gray: "gray",
|
|
18
|
-
green: "green",
|
|
19
|
-
red: "red",
|
|
20
|
-
purple: theme.colors.accent,
|
|
21
|
-
teal: "cyan",
|
|
22
|
-
};
|
|
23
|
-
return (_jsx(CategoryHeader, { title: mp.displayName, expanded: item.isExpanded, count: item.pluginCount, status: item.badge, statusColor: statusColorMap[item.tone] }));
|
|
24
|
-
}
|
|
25
|
-
function categoryDetail(item, collapsedMarketplaces) {
|
|
26
|
-
const mp = item.marketplace;
|
|
27
|
-
const isEnabled = item.marketplaceEnabled;
|
|
28
|
-
const isCollapsed = collapsedMarketplaces.has(mp.name);
|
|
29
|
-
const hasPlugins = item.pluginCount > 0;
|
|
30
|
-
let actionHint = "Add";
|
|
31
|
-
if (isEnabled) {
|
|
32
|
-
if (isCollapsed) {
|
|
33
|
-
actionHint = "Expand";
|
|
34
|
-
}
|
|
35
|
-
else if (hasPlugins) {
|
|
36
|
-
actionHint = "Collapse";
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
actionHint = "Remove";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: theme.colors.info, children: _jsxs("strong", { children: [mp.displayName, item.badge ? ` ${item.badge}` : ""] }) }), _jsx("text", { fg: theme.colors.muted, children: mp.description || "No description" }), _jsx("text", { fg: isEnabled ? theme.colors.success : theme.colors.muted, children: isEnabled ? "● Added" : "○ Not added" }), _jsxs("text", { fg: theme.colors.link, children: ["github.com/", mp.source.repo] }), _jsxs("text", { children: ["Plugins: ", item.pluginCount] }), _jsx(ActionHints, { hints: [
|
|
43
|
-
{ key: "Enter", label: actionHint, tone: isEnabled ? "primary" : "default" },
|
|
44
|
-
] }), isEnabled ? (_jsx("box", { children: _jsx("text", { fg: theme.colors.muted, children: "\u2190 \u2192 to expand/collapse" }) })) : null] }));
|
|
45
|
-
}
|
|
46
|
-
// ─── Plugin renderers ─────────────────────────────────────────────────────────
|
|
47
|
-
function pluginRow(item, isSelected) {
|
|
48
|
-
const { plugin } = item;
|
|
49
|
-
const hasUser = !!plugin.userScope?.enabled;
|
|
50
|
-
const hasProject = !!plugin.projectScope?.enabled;
|
|
51
|
-
const hasLocal = !!plugin.localScope?.enabled;
|
|
52
|
-
const hasAnyScope = hasUser || hasProject || hasLocal;
|
|
53
|
-
// Build version string — only show if plugin is installed in at least one scope
|
|
54
|
-
let versionStr = "";
|
|
55
|
-
if (plugin.isOrphaned) {
|
|
56
|
-
versionStr = " deprecated";
|
|
57
|
-
}
|
|
58
|
-
else if (hasAnyScope && plugin.installedVersion && plugin.installedVersion !== "0.0.0") {
|
|
59
|
-
versionStr = ` v${plugin.installedVersion}`;
|
|
60
|
-
if (plugin.hasUpdate && plugin.version) {
|
|
61
|
-
versionStr += ` → v${plugin.version}`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (isSelected) {
|
|
65
|
-
return (_jsxs("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: [" ", _jsx(ScopeSquares, { user: hasUser, project: hasProject, local: hasLocal, selected: true }), " ", plugin.name, versionStr, " "] }));
|
|
66
|
-
}
|
|
67
|
-
// Fuzzy highlight
|
|
68
|
-
const segments = item.matches ? highlightMatches(plugin.name, item.matches) : null;
|
|
69
|
-
const displayName = segments ? segments.map((seg) => seg.text).join("") : plugin.name;
|
|
70
|
-
if (plugin.isOrphaned) {
|
|
71
|
-
const ver = plugin.installedVersion && plugin.installedVersion !== "0.0.0"
|
|
72
|
-
? ` v${plugin.installedVersion}`
|
|
73
|
-
: "";
|
|
74
|
-
return (_jsxs("text", { children: [_jsx("span", { fg: theme.colors.danger, children: " \u25A0\u25A0\u25A0 " }), _jsx("span", { fg: theme.colors.muted, children: displayName }), ver ? _jsx("span", { fg: theme.colors.warning, children: ver }) : null, _jsx("span", { fg: theme.colors.danger, children: " deprecated" })] }));
|
|
75
|
-
}
|
|
76
|
-
return (_jsxs("text", { children: [_jsx("span", { children: " " }), _jsx(ScopeSquares, { user: hasUser, project: hasProject, local: hasLocal }), _jsx("span", { children: " " }), _jsx("span", { fg: hasAnyScope ? theme.colors.text : theme.colors.muted, children: displayName }), _jsx(MetaText, { text: versionStr, tone: plugin.hasUpdate ? "warning" : "muted" })] }));
|
|
77
|
-
}
|
|
78
|
-
function pluginDetail(item) {
|
|
79
|
-
const { plugin } = item;
|
|
80
|
-
const isInstalled = plugin.userScope?.enabled ||
|
|
81
|
-
plugin.projectScope?.enabled ||
|
|
82
|
-
plugin.localScope?.enabled;
|
|
83
|
-
// Orphaned/deprecated plugin
|
|
84
|
-
if (plugin.isOrphaned) {
|
|
85
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { justifyContent: "center", children: _jsx("text", { bg: theme.colors.warning, fg: "black", children: _jsxs("strong", { children: [" ", plugin.name, " \u2014 DEPRECATED "] }) }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: theme.colors.warning, children: "This plugin is no longer in the marketplace." }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: theme.colors.muted, children: "It was removed from the marketplace but still referenced in your settings. Press d to uninstall and clean up." }) }), _jsx(ActionHints, { hints: [{ key: "d", label: isInstalled ? "Remove from all scopes" : "Clean up stale reference", tone: "danger" }] })] }));
|
|
86
|
-
}
|
|
87
|
-
// Build component counts
|
|
88
|
-
const components = [];
|
|
89
|
-
if (plugin.agents?.length)
|
|
90
|
-
components.push(`${plugin.agents.length} agents`);
|
|
91
|
-
if (plugin.commands?.length)
|
|
92
|
-
components.push(`${plugin.commands.length} commands`);
|
|
93
|
-
if (plugin.skills?.length)
|
|
94
|
-
components.push(`${plugin.skills.length} skills`);
|
|
95
|
-
if (plugin.mcpServers?.length)
|
|
96
|
-
components.push(`${plugin.mcpServers.length} MCP`);
|
|
97
|
-
if (plugin.lspServers && Object.keys(plugin.lspServers).length) {
|
|
98
|
-
components.push(`${Object.keys(plugin.lspServers).length} LSP`);
|
|
99
|
-
}
|
|
100
|
-
const showVersion = plugin.version && plugin.version !== "0.0.0";
|
|
101
|
-
const showInstalledVersion = isInstalled && plugin.installedVersion && plugin.installedVersion !== "0.0.0";
|
|
102
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { justifyContent: "center", children: _jsx("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: _jsxs("strong", { children: [" ", plugin.name, isInstalled && plugin.hasUpdate ? " ⬆" : "", " "] }) }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: isInstalled ? theme.colors.success : theme.colors.muted, children: isInstalled ? "● Installed" : "○ Not installed" }) }), _jsx("box", { marginTop: 1, marginBottom: 1, children: _jsx("text", { fg: theme.colors.text, children: plugin.description }) }), showVersion ? (_jsx(KeyValueLine, { label: "Version", value: _jsxs("span", { children: [_jsxs("span", { fg: theme.colors.link, children: ["v", plugin.version] }), showInstalledVersion && plugin.installedVersion !== plugin.version ? (_jsxs("span", { children: [" (v", plugin.installedVersion, " installed)"] })) : null] }) })) : null, plugin.category ? (_jsx(KeyValueLine, { label: "Category", value: _jsx("span", { fg: theme.colors.accent, children: plugin.category }) })) : null, plugin.author ? (_jsx(KeyValueLine, { label: "Author", value: _jsx("span", { children: plugin.author.name }) })) : null, components.length > 0 ? (_jsx(KeyValueLine, { label: "Contains", value: _jsx("span", { fg: theme.colors.warning, children: components.join(" · ") }) })) : null, _jsxs(DetailSection, { children: [_jsx("text", { children: "─".repeat(24) }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsxs("span", { bg: theme.scopes.user, fg: "black", children: [" ", "u", " "] }), _jsx("span", { fg: plugin.userScope?.enabled ? theme.scopes.user : theme.colors.muted, children: plugin.userScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: theme.scopes.user, children: "User" }), _jsx("span", { children: " global" }), plugin.userScope?.version ? (_jsxs("span", { fg: theme.scopes.user, children: [" v", plugin.userScope.version] })) : null] }), _jsxs("text", { children: [_jsxs("span", { bg: theme.scopes.project, fg: "black", children: [" ", "p", " "] }), _jsx("span", { fg: plugin.projectScope?.enabled ? theme.scopes.project : theme.colors.muted, children: plugin.projectScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: theme.scopes.project, children: "Project" }), _jsx("span", { children: " team" }), plugin.projectScope?.version ? (_jsxs("span", { fg: theme.scopes.project, children: [" v", plugin.projectScope.version] })) : null] }), _jsxs("text", { children: [_jsxs("span", { bg: theme.scopes.local, fg: "black", children: [" ", "l", " "] }), _jsx("span", { fg: plugin.localScope?.enabled ? theme.scopes.local : theme.colors.muted, children: plugin.localScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: theme.scopes.local, children: "Local" }), _jsx("span", { children: " private" }), plugin.localScope?.version ? (_jsxs("span", { fg: theme.scopes.local, children: [" v", plugin.localScope.version] })) : null] })] })] }), isInstalled && plugin.hasUpdate ? (_jsx(ActionHints, { hints: [{ key: "U", label: `Update to v${plugin.version}`, tone: "primary" }] })) : null] }));
|
|
103
|
-
}
|
|
104
|
-
// ─── Public dispatch functions ────────────────────────────────────────────────
|
|
105
|
-
/**
|
|
106
|
-
* Render a plugin browser list row by item kind.
|
|
107
|
-
*/
|
|
108
|
-
export function renderPluginRow(item, _index, isSelected) {
|
|
109
|
-
if (item.kind === "category") {
|
|
110
|
-
return categoryRow(item, isSelected);
|
|
111
|
-
}
|
|
112
|
-
return pluginRow(item, isSelected);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Render the detail panel for a plugin browser item.
|
|
116
|
-
*/
|
|
117
|
-
export function renderPluginDetail(item, collapsedMarketplaces) {
|
|
118
|
-
if (!item)
|
|
119
|
-
return _jsx("text", { fg: theme.colors.muted, children: "Select an item" });
|
|
120
|
-
if (item.kind === "category") {
|
|
121
|
-
return categoryDetail(item, collapsedMarketplaces);
|
|
122
|
-
}
|
|
123
|
-
return pluginDetail(item);
|
|
124
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { theme } from "../theme.js";
|
|
3
|
-
// ─── Helpers ───────────────────────────────────────────────────────────────────
|
|
4
|
-
function truncate(s, maxLen) {
|
|
5
|
-
if (s.length <= maxLen)
|
|
6
|
-
return s;
|
|
7
|
-
return s.slice(0, maxLen - 1) + "\u2026";
|
|
8
|
-
}
|
|
9
|
-
export function humanizeValue(_key, value) {
|
|
10
|
-
if (typeof value === "boolean")
|
|
11
|
-
return value ? "on" : "off";
|
|
12
|
-
if (typeof value !== "string")
|
|
13
|
-
return String(value);
|
|
14
|
-
if (value === "claude-sonnet-4-6")
|
|
15
|
-
return "Sonnet";
|
|
16
|
-
if (value === "claude-opus-4-6")
|
|
17
|
-
return "Opus";
|
|
18
|
-
if (value === "claude-haiku-4-6")
|
|
19
|
-
return "Haiku";
|
|
20
|
-
if (value.startsWith("claude-sonnet"))
|
|
21
|
-
return "Sonnet";
|
|
22
|
-
if (value.startsWith("claude-opus"))
|
|
23
|
-
return "Opus";
|
|
24
|
-
if (value.startsWith("claude-haiku"))
|
|
25
|
-
return "Haiku";
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
export function humanizeKey(key) {
|
|
29
|
-
const labels = {
|
|
30
|
-
effortLevel: "Effort",
|
|
31
|
-
model: "Model",
|
|
32
|
-
outputStyle: "Output",
|
|
33
|
-
alwaysThinkingEnabled: "Thinking",
|
|
34
|
-
includeGitInstructions: "Git Instructions",
|
|
35
|
-
respectGitignore: "Gitignore",
|
|
36
|
-
enableAllProjectMcpServers: "Auto MCP",
|
|
37
|
-
autoUpdatesChannel: "Updates",
|
|
38
|
-
language: "Language",
|
|
39
|
-
cleanupPeriodDays: "Cleanup",
|
|
40
|
-
};
|
|
41
|
-
return labels[key] ?? key;
|
|
42
|
-
}
|
|
43
|
-
export function stripSuffix(pluginName) {
|
|
44
|
-
return pluginName
|
|
45
|
-
.replace(/@magus$/, "")
|
|
46
|
-
.replace(/@claude-plugins-official$/, "");
|
|
47
|
-
}
|
|
48
|
-
export function wrapNames(names, lineMax = 40) {
|
|
49
|
-
const lines = [];
|
|
50
|
-
let current = "";
|
|
51
|
-
for (const name of names) {
|
|
52
|
-
const add = current ? `, ${name}` : name;
|
|
53
|
-
if (current && current.length + add.length > lineMax) {
|
|
54
|
-
lines.push(current);
|
|
55
|
-
current = name;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
current += current ? `, ${name}` : name;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (current)
|
|
62
|
-
lines.push(current);
|
|
63
|
-
return lines;
|
|
64
|
-
}
|
|
65
|
-
export function formatDate(iso) {
|
|
66
|
-
try {
|
|
67
|
-
const d = new Date(iso);
|
|
68
|
-
return d.toLocaleDateString("en-US", {
|
|
69
|
-
month: "short",
|
|
70
|
-
day: "numeric",
|
|
71
|
-
year: "numeric",
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return iso;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// ─── Header renderer ───────────────────────────────────────────────────────────
|
|
79
|
-
const headerRenderer = {
|
|
80
|
-
renderRow: ({ item }) => (_jsx("text", { bg: item.color, fg: "white", children: _jsxs("strong", { children: [" ", item.label, " (", item.count, ")", " "] }) })),
|
|
81
|
-
renderDetail: () => (_jsx("text", { fg: theme.colors.muted, children: "Select a profile to see details" })),
|
|
82
|
-
};
|
|
83
|
-
// ─── Predefined renderer ───────────────────────────────────────────────────────
|
|
84
|
-
const DIVIDER = "────────────────────────";
|
|
85
|
-
const predefinedRenderer = {
|
|
86
|
-
renderRow: ({ item, isSelected }) => {
|
|
87
|
-
const { profile } = item;
|
|
88
|
-
const pluginCount = profile.magusPlugins.length + profile.anthropicPlugins.length;
|
|
89
|
-
const skillCount = profile.skills.length;
|
|
90
|
-
const countStr = `${pluginCount}p ${skillCount}s`;
|
|
91
|
-
if (isSelected) {
|
|
92
|
-
return (_jsxs("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: [" ", profile.name, " ", countStr, " "] }));
|
|
93
|
-
}
|
|
94
|
-
return (_jsxs("text", { children: [_jsxs("span", { fg: "white", children: [" ", profile.name] }), _jsxs("span", { fg: theme.colors.dim, children: [" ", countStr] })] }));
|
|
95
|
-
},
|
|
96
|
-
renderDetail: ({ item }) => {
|
|
97
|
-
const { profile } = item;
|
|
98
|
-
const settingEntries = Object.entries(profile.settings).filter(([k]) => k !== "env");
|
|
99
|
-
const envMap = profile.settings["env"] ?? {};
|
|
100
|
-
const tasksOn = envMap["CLAUDE_CODE_ENABLE_TASKS"] === "true";
|
|
101
|
-
const teamsOn = envMap["CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"] === "true";
|
|
102
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { children: _jsx("text", { bg: theme.colors.accent, fg: "white", children: _jsxs("strong", { children: [" ", profile.name, " "] }) }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: theme.colors.muted, children: profile.description }) }), _jsx("box", { children: _jsx("text", { fg: theme.colors.muted, children: `\nMagus (${profile.magusPlugins.length})` }) }), _jsx("box", { children: _jsx("text", { fg: "#00bfa5", children: profile.magusPlugins.map((p) => ` ■ ${p}`).join("\n") }) }), _jsx("box", { children: _jsx("text", { fg: theme.colors.muted, children: `\nAnthropic (${profile.anthropicPlugins.length})` }) }), _jsx("box", { children: _jsx("text", { fg: "#b39ddb", children: profile.anthropicPlugins.map((p) => ` ■ ${p}`).join("\n") }) }), profile.skills.length > 0 && (_jsxs(_Fragment, { children: [_jsx("box", { children: _jsx("text", { fg: theme.colors.muted, children: `\nSkills (${profile.skills.length})` }) }), _jsx("box", { children: _jsx("text", { fg: "#ffd54f", children: profile.skills.map((s) => ` ■ ${s}`).join("\n") }) })] })), _jsx("box", { children: _jsx("text", { fg: theme.colors.dim, children: `\n${DIVIDER}` }) }), _jsx("box", { children: _jsx("text", { fg: theme.colors.muted, children: [
|
|
103
|
-
...settingEntries.map(([k, v]) => ` ${humanizeKey(k).padEnd(18)}${humanizeValue(k, v)}`),
|
|
104
|
-
...(tasksOn ? [` ${"Tasks".padEnd(18)}on`] : []),
|
|
105
|
-
...(teamsOn ? [` ${"Agent Teams".padEnd(18)}on`] : []),
|
|
106
|
-
].join("\n") }) }), _jsx("box", { children: _jsx("text", { fg: theme.colors.dim, children: `\n${DIVIDER}` }) }), _jsx("box", { children: _jsx("text", { fg: theme.colors.info, children: " Enter/a to apply" }) })] }));
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
// ─── Saved renderer ────────────────────────────────────────────────────────────
|
|
110
|
-
const savedRenderer = {
|
|
111
|
-
renderRow: ({ item, isSelected }) => {
|
|
112
|
-
const { entry } = item;
|
|
113
|
-
const pluginCount = Object.keys(entry.plugins).length;
|
|
114
|
-
const dateStr = formatDate(entry.updatedAt);
|
|
115
|
-
const label = truncate(`${entry.name} — ${pluginCount} plugin${pluginCount !== 1 ? "s" : ""} · ${dateStr}`, 45);
|
|
116
|
-
if (isSelected) {
|
|
117
|
-
return (_jsxs("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: [" ", label, " "] }));
|
|
118
|
-
}
|
|
119
|
-
const scopeColor = entry.scope === "user" ? theme.scopes.user : theme.scopes.project;
|
|
120
|
-
const scopeLabel = entry.scope === "user" ? "[user]" : "[proj]";
|
|
121
|
-
return (_jsxs("text", { children: [_jsxs("span", { fg: scopeColor, children: [scopeLabel, " "] }), _jsx("span", { fg: theme.colors.text, children: label })] }));
|
|
122
|
-
},
|
|
123
|
-
renderDetail: ({ item }) => {
|
|
124
|
-
const { entry: selectedProfile } = item;
|
|
125
|
-
const plugins = Object.keys(selectedProfile.plugins);
|
|
126
|
-
const cleanPlugins = plugins.map(stripSuffix);
|
|
127
|
-
const scopeColor = selectedProfile.scope === "user" ? theme.scopes.user : theme.scopes.project;
|
|
128
|
-
const scopeLabel = selectedProfile.scope === "user"
|
|
129
|
-
? "User (~/.claude/profiles.json)"
|
|
130
|
-
: "Project (.claude/profiles.json — committed to git)";
|
|
131
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: theme.colors.info, children: _jsx("strong", { children: selectedProfile.name }) }), _jsxs("box", { marginTop: 1, children: [_jsx("text", { fg: theme.colors.muted, children: "Scope: " }), _jsx("text", { fg: scopeColor, children: scopeLabel })] }), _jsx("box", { marginTop: 1, children: _jsxs("text", { fg: theme.colors.muted, children: ["Created: ", formatDate(selectedProfile.createdAt), " \u00B7 Updated:", " ", formatDate(selectedProfile.updatedAt)] }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { fg: theme.colors.muted, children: ["Plugins (", plugins.length, plugins.length === 0 ? " — applying will disable all plugins" : "", "):"] }), cleanPlugins.length === 0 ? (_jsx("text", { fg: theme.colors.warning, children: " (none)" })) : (wrapNames(cleanPlugins).map((line, i) => (_jsxs("text", { fg: theme.colors.text, children: [" ", line] }, i))))] }), _jsxs("box", { marginTop: 2, flexDirection: "column", children: [_jsxs("box", { children: [_jsxs("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: [" ", "Enter/a", " "] }), _jsx("text", { fg: theme.colors.muted, children: " Apply profile" })] }), _jsxs("box", { marginTop: 1, children: [_jsxs("text", { bg: theme.colors.dim, fg: "white", children: [" ", "r", " "] }), _jsx("text", { fg: theme.colors.muted, children: " Rename" })] }), _jsxs("box", { marginTop: 1, children: [_jsxs("text", { bg: theme.colors.danger, fg: "white", children: [" ", "d", " "] }), _jsx("text", { fg: theme.colors.muted, children: " Delete" })] }), _jsxs("box", { marginTop: 1, children: [_jsxs("text", { bg: "blue", fg: "white", children: [" ", "c", " "] }), _jsx("text", { fg: theme.colors.muted, children: " Copy JSON to clipboard" })] }), _jsxs("box", { marginTop: 1, children: [_jsxs("text", { bg: theme.colors.success, fg: "white", children: [" ", "i", " "] }), _jsx("text", { fg: theme.colors.muted, children: " Import from clipboard" })] })] })] }));
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
// ─── Dispatch helpers ──────────────────────────────────────────────────────────
|
|
135
|
-
export function renderProfileRow(item, _index, isSelected) {
|
|
136
|
-
if (item.kind === "header") {
|
|
137
|
-
return headerRenderer.renderRow({ item, isSelected });
|
|
138
|
-
}
|
|
139
|
-
if (item.kind === "predefined") {
|
|
140
|
-
return predefinedRenderer.renderRow({ item, isSelected });
|
|
141
|
-
}
|
|
142
|
-
return savedRenderer.renderRow({ item, isSelected });
|
|
143
|
-
}
|
|
144
|
-
export function renderProfileDetail(item, loading, error) {
|
|
145
|
-
if (loading)
|
|
146
|
-
return _jsx("text", { fg: theme.colors.muted, children: "Loading profiles..." });
|
|
147
|
-
if (error)
|
|
148
|
-
return _jsxs("text", { fg: theme.colors.danger, children: ["Error: ", error] });
|
|
149
|
-
if (!item || item.kind === "header")
|
|
150
|
-
return _jsx("text", { fg: theme.colors.muted, children: "Select a profile to see details" });
|
|
151
|
-
if (item.kind === "predefined") {
|
|
152
|
-
return predefinedRenderer.renderDetail({ item });
|
|
153
|
-
}
|
|
154
|
-
return savedRenderer.renderDetail({ item });
|
|
155
|
-
}
|
|
156
|
-
export function buildProfileListItems(profileList, PREDEFINED_PROFILES) {
|
|
157
|
-
const items = [];
|
|
158
|
-
items.push({
|
|
159
|
-
kind: "header",
|
|
160
|
-
label: "Presets",
|
|
161
|
-
color: "#4527a0",
|
|
162
|
-
count: PREDEFINED_PROFILES.length,
|
|
163
|
-
});
|
|
164
|
-
for (const p of PREDEFINED_PROFILES) {
|
|
165
|
-
items.push({ kind: "predefined", profile: p });
|
|
166
|
-
}
|
|
167
|
-
items.push({
|
|
168
|
-
kind: "header",
|
|
169
|
-
label: "Your Profiles",
|
|
170
|
-
color: "#00695c",
|
|
171
|
-
count: profileList.length,
|
|
172
|
-
});
|
|
173
|
-
for (const e of profileList) {
|
|
174
|
-
items.push({ kind: "saved", entry: e });
|
|
175
|
-
}
|
|
176
|
-
return items;
|
|
177
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { CATEGORY_LABELS, CATEGORY_BG, CATEGORY_COLOR, CATEGORY_DESCRIPTIONS, formatValue, } from "../adapters/settingsAdapter.js";
|
|
3
|
-
import { MetaText } from "../components/primitives/index.js";
|
|
4
|
-
import { theme } from "../theme.js";
|
|
5
|
-
// ─── Category renderer ─────────────────────────────────────────────────────────
|
|
6
|
-
const categoryRenderer = {
|
|
7
|
-
renderRow: ({ item, isSelected }) => {
|
|
8
|
-
const star = item.category === "recommended" ? "★ " : "";
|
|
9
|
-
const label = `${star}${CATEGORY_LABELS[item.category]}`;
|
|
10
|
-
const bg = isSelected ? theme.selection.bg : CATEGORY_BG[item.category];
|
|
11
|
-
return (_jsx("box", { width: "100%", children: _jsx("text", { bg: bg, fg: "white", children: _jsxs("strong", { children: [" ", label, " "] }) }) }));
|
|
12
|
-
},
|
|
13
|
-
renderDetail: ({ item }) => {
|
|
14
|
-
const cat = item.category;
|
|
15
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: CATEGORY_COLOR[cat], children: _jsx("strong", { children: CATEGORY_LABELS[cat] }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: theme.colors.muted, children: CATEGORY_DESCRIPTIONS[cat] }) })] }));
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
// ─── Setting renderer ──────────────────────────────────────────────────────────
|
|
19
|
-
const settingRenderer = {
|
|
20
|
-
renderRow: ({ item, isSelected }) => {
|
|
21
|
-
const { setting } = item;
|
|
22
|
-
const indicator = item.isDefault ? "○" : "●";
|
|
23
|
-
const displayValue = formatValue(setting, item.effectiveValue);
|
|
24
|
-
if (isSelected) {
|
|
25
|
-
return (_jsxs("text", { bg: theme.selection.bg, fg: theme.selection.fg, children: [" ", indicator, " ", setting.name.padEnd(28), displayValue, " "] }));
|
|
26
|
-
}
|
|
27
|
-
const indicatorColor = item.isDefault ? theme.colors.muted : theme.colors.info;
|
|
28
|
-
const valueColor = item.isDefault ? theme.colors.muted : theme.colors.success;
|
|
29
|
-
return (_jsxs("text", { children: [_jsxs("span", { fg: indicatorColor, children: [" ", indicator, " "] }), _jsx("span", { children: setting.name.padEnd(28) }), _jsx("span", { fg: valueColor, children: displayValue })] }));
|
|
30
|
-
},
|
|
31
|
-
renderDetail: ({ item }) => {
|
|
32
|
-
const { setting } = item;
|
|
33
|
-
const scoped = item.scopedValues;
|
|
34
|
-
const storageDesc = setting.storage.type === "attribution"
|
|
35
|
-
? "settings.json: attribution"
|
|
36
|
-
: setting.storage.type === "attribution-text"
|
|
37
|
-
? "settings.json: attribution"
|
|
38
|
-
: setting.storage.type === "env"
|
|
39
|
-
? `env: ${setting.storage.key}`
|
|
40
|
-
: `settings.json: ${setting.storage.key}`;
|
|
41
|
-
const userValue = formatValue(setting, scoped.user);
|
|
42
|
-
const projectValue = formatValue(setting, scoped.project);
|
|
43
|
-
const userIsSet = scoped.user !== undefined && scoped.user !== "";
|
|
44
|
-
const projectIsSet = scoped.project !== undefined && scoped.project !== "";
|
|
45
|
-
const actionLabel = setting.type === "boolean"
|
|
46
|
-
? "toggle"
|
|
47
|
-
: setting.type === "select"
|
|
48
|
-
? "choose"
|
|
49
|
-
: "edit";
|
|
50
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: theme.colors.info, children: _jsx("strong", { children: setting.name }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: theme.colors.text, children: setting.description }) }), _jsx("box", { marginTop: 1, children: _jsxs("text", { children: [_jsx("span", { fg: theme.colors.muted, children: "Stored " }), _jsx("span", { fg: theme.colors.link, children: storageDesc })] }) }), setting.defaultValue !== undefined && (_jsx("box", { children: _jsxs("text", { children: [_jsx("span", { fg: theme.colors.muted, children: "Default " }), _jsx("span", { children: setting.defaultValue })] }) })), _jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { children: "────────────────────────" }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsxs("span", { bg: theme.scopes.user, fg: "black", children: [" ", "u", " "] }), _jsx("span", { fg: userIsSet ? theme.scopes.user : theme.colors.muted, children: userIsSet ? " ● " : " ○ " }), _jsx("span", { fg: theme.scopes.user, children: "User" }), _jsx("span", { children: " global" }), _jsxs("span", { fg: userIsSet ? theme.scopes.user : theme.colors.muted, children: [" ", userValue] })] }), _jsxs("text", { children: [_jsxs("span", { bg: theme.scopes.project, fg: "black", children: [" ", "p", " "] }), _jsx("span", { fg: projectIsSet ? theme.scopes.project : theme.colors.muted, children: projectIsSet ? " ● " : " ○ " }), _jsx("span", { fg: theme.scopes.project, children: "Project" }), _jsx("span", { children: " team" }), _jsxs("span", { fg: projectIsSet ? theme.scopes.project : theme.colors.muted, children: [" ", projectValue] })] })] })] }), _jsx("box", { marginTop: 1, children: _jsxs("text", { fg: theme.colors.muted, children: ["Press u/p to ", actionLabel, " in scope"] }) })] }));
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
// ─── Dispatch helpers ──────────────────────────────────────────────────────────
|
|
54
|
-
export const settingsRenderers = {
|
|
55
|
-
category: categoryRenderer,
|
|
56
|
-
setting: settingRenderer,
|
|
57
|
-
};
|
|
58
|
-
export function renderSettingRow(item, _index, isSelected) {
|
|
59
|
-
if (item.kind === "category") {
|
|
60
|
-
return settingsRenderers.category.renderRow({ item, isSelected });
|
|
61
|
-
}
|
|
62
|
-
return settingsRenderers.setting.renderRow({ item, isSelected });
|
|
63
|
-
}
|
|
64
|
-
export function renderSettingDetail(item) {
|
|
65
|
-
if (!item)
|
|
66
|
-
return _jsx("text", { fg: theme.colors.muted, children: "Select a setting to see details" });
|
|
67
|
-
if (item.kind === "category") {
|
|
68
|
-
return settingsRenderers.category.renderDetail({ item });
|
|
69
|
-
}
|
|
70
|
-
return settingsRenderers.setting.renderDetail({ item });
|
|
71
|
-
}
|
|
72
|
-
// Suppress unused import warning — MetaText may be used in future extensions
|
|
73
|
-
void MetaText;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
-
import { STAR_RELIABILITY_INFO } from "../../data/skill-repos.js";
|
|
3
|
-
import { SelectableRow, ListCategoryRow, ScopeSquares, MetaText, KeyValueLine, DetailSection, } from "../components/primitives/index.js";
|
|
4
|
-
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
5
|
-
function formatStarsNum(stars) {
|
|
6
|
-
if (!stars)
|
|
7
|
-
return "";
|
|
8
|
-
if (stars >= 1000000)
|
|
9
|
-
return `${(stars / 1000000).toFixed(1)}M`;
|
|
10
|
-
if (stars >= 10000)
|
|
11
|
-
return `${Math.round(stars / 1000)}K`;
|
|
12
|
-
if (stars >= 1000)
|
|
13
|
-
return `${(stars / 1000).toFixed(1)}K`;
|
|
14
|
-
return `${stars}`;
|
|
15
|
-
}
|
|
16
|
-
/** Star icon and color based on reliability classification */
|
|
17
|
-
function starIcon(reliability) {
|
|
18
|
-
if (reliability === "mega-repo")
|
|
19
|
-
return "☆";
|
|
20
|
-
if (reliability === "skill-dump")
|
|
21
|
-
return "☆";
|
|
22
|
-
return "★";
|
|
23
|
-
}
|
|
24
|
-
function starColor(reliability) {
|
|
25
|
-
if (reliability === "mega-repo")
|
|
26
|
-
return "gray";
|
|
27
|
-
if (reliability === "skill-dump")
|
|
28
|
-
return "#888800";
|
|
29
|
-
return "yellow";
|
|
30
|
-
}
|
|
31
|
-
function formatStars(stars, reliability) {
|
|
32
|
-
if (!stars)
|
|
33
|
-
return "";
|
|
34
|
-
return `${starIcon(reliability)} ${formatStarsNum(stars)}`;
|
|
35
|
-
}
|
|
36
|
-
// ─── Category renderer ────────────────────────────────────────────────────────
|
|
37
|
-
const categoryRenderer = {
|
|
38
|
-
renderRow: ({ item, isSelected }) => {
|
|
39
|
-
const label = `${item.star ?? ""}${item.title}`;
|
|
40
|
-
return (_jsx(ListCategoryRow, { selected: isSelected, title: label, count: item.count, badge: item.badge, tone: item.tone }));
|
|
41
|
-
},
|
|
42
|
-
renderDetail: ({ item }) => {
|
|
43
|
-
const isRec = item.categoryKey === "recommended";
|
|
44
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsx("text", { fg: isRec ? "green" : "cyan", children: _jsxs("strong", { children: [item.star ?? "", item.title] }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: isRec
|
|
45
|
-
? "Curated skills recommended for most projects"
|
|
46
|
-
: "Popular skills sorted by stars" }) })] }));
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
// ─── Skill renderer ───────────────────────────────────────────────────────────
|
|
50
|
-
const MAX_SKILL_NAME_LEN = 35;
|
|
51
|
-
function truncateName(name) {
|
|
52
|
-
return name.length > MAX_SKILL_NAME_LEN
|
|
53
|
-
? name.slice(0, MAX_SKILL_NAME_LEN - 1) + "\u2026"
|
|
54
|
-
: name;
|
|
55
|
-
}
|
|
56
|
-
const skillRenderer = {
|
|
57
|
-
renderRow: ({ item, isSelected }) => {
|
|
58
|
-
const { skill } = item;
|
|
59
|
-
const hasUser = skill.installedScope === "user";
|
|
60
|
-
const hasProject = skill.installedScope === "project";
|
|
61
|
-
const reliability = skill.starReliability;
|
|
62
|
-
const starsStr = formatStars(skill.stars, reliability);
|
|
63
|
-
const sColor = starColor(reliability);
|
|
64
|
-
const displayName = truncateName(skill.name);
|
|
65
|
-
const indentLevel = item.indent ?? 1;
|
|
66
|
-
return (_jsxs(SelectableRow, { selected: isSelected, indent: indentLevel, children: [_jsx(ScopeSquares, { user: hasUser, project: hasProject, selected: isSelected }), _jsx("span", { children: " " }), _jsx("span", { fg: isSelected ? "white" : skill.installed ? "white" : "gray", children: displayName }), skill.hasUpdate ? _jsx(MetaText, { text: " \u2B06", tone: "warning" }) : null, starsStr ? _jsx("span", { fg: sColor, children: ` ${starsStr}` }) : null] }));
|
|
67
|
-
},
|
|
68
|
-
renderDetail: ({ item }) => {
|
|
69
|
-
const { skill } = item;
|
|
70
|
-
const fm = skill.frontmatter;
|
|
71
|
-
const description = fm?.description || skill.description || "Loading...";
|
|
72
|
-
const reliability = skill.starReliability;
|
|
73
|
-
const starsStr = formatStars(skill.stars, reliability);
|
|
74
|
-
const sColor = starColor(reliability);
|
|
75
|
-
const reliabilityInfo = reliability ? STAR_RELIABILITY_INFO[reliability] : null;
|
|
76
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("text", { fg: "cyan", children: [_jsx("strong", { children: skill.name }), starsStr ? _jsxs("span", { fg: sColor, children: [" ", starsStr] }) : null] }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "white", children: description }) }), fm?.category ? (_jsx(KeyValueLine, { label: "Category", value: _jsx("span", { fg: "cyan", children: fm.category }) })) : null, fm?.author ? (_jsx(KeyValueLine, { label: "Author", value: _jsx("span", { children: fm.author }) })) : null, fm?.version ? (_jsx(KeyValueLine, { label: "Version", value: _jsx("span", { children: fm.version }) })) : null, fm?.tags && fm.tags.length > 0 ? (_jsx(KeyValueLine, { label: "Tags", value: _jsx("span", { children: fm.tags.join(", ") }) })) : null, _jsxs(DetailSection, { children: [_jsxs("text", { children: [_jsx("span", { fg: "gray", children: "Source " }), _jsx("span", { fg: "#5c9aff", children: skill.source.repo })] }), _jsxs("text", { children: [_jsx("span", { fg: "gray", children: " " }), _jsx("span", { fg: "gray", children: skill.repoPath })] })] }), reliabilityInfo && reliability !== "dedicated" && (_jsx("box", { marginTop: 1, children: _jsxs("text", { children: [_jsxs("span", { fg: sColor, children: [starIcon(reliability), " "] }), _jsx("span", { fg: sColor, children: _jsx("strong", { children: reliabilityInfo.label }) }), _jsxs("span", { fg: "gray", children: [" \u2014 ", reliabilityInfo.description] })] }) })), _jsxs(DetailSection, { children: [_jsx("text", { children: "─".repeat(24) }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsx("span", { bg: "cyan", fg: "black", children: " u " }), _jsx("span", { fg: skill.installedScope === "user" ? "cyan" : "gray", children: skill.installedScope === "user" ? " ● " : " ○ " }), _jsx("span", { fg: "cyan", children: "User" }), _jsx("span", { fg: "gray", children: " ~/.claude/skills/" })] }), _jsxs("text", { children: [_jsx("span", { bg: "green", fg: "black", children: " p " }), _jsx("span", { fg: skill.installedScope === "project" ? "green" : "gray", children: skill.installedScope === "project" ? " ● " : " ○ " }), _jsx("span", { fg: "green", children: "Project" }), _jsx("span", { fg: "gray", children: " .claude/skills/" })] })] })] }), skill.hasUpdate && (_jsx("box", { marginTop: 1, children: _jsx("text", { bg: "yellow", fg: "black", children: " UPDATE AVAILABLE " }) })), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: skill.installed
|
|
77
|
-
? "Press u/p to toggle scope"
|
|
78
|
-
: "Press u/p to install" }) }), _jsx("box", { children: _jsxs("text", { children: [_jsx("span", { bg: "#555555", fg: "white", children: " o " }), _jsx("span", { fg: "gray", children: " Open in browser" })] }) })] }));
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
// ─── Skill Set renderer ──────────────────────────────────────────────────────
|
|
82
|
-
const MAX_SET_NAME_LEN = 28;
|
|
83
|
-
const skillSetRenderer = {
|
|
84
|
-
renderRow: ({ item, isSelected }) => {
|
|
85
|
-
const { skillSet, expanded } = item;
|
|
86
|
-
const arrow = expanded ? "\u25BC" : "\u25B6";
|
|
87
|
-
const displayName = skillSet.name.length > MAX_SET_NAME_LEN
|
|
88
|
-
? skillSet.name.slice(0, MAX_SET_NAME_LEN - 1) + "\u2026"
|
|
89
|
-
: skillSet.name;
|
|
90
|
-
// Count installed child skills
|
|
91
|
-
const installedCount = skillSet.loaded
|
|
92
|
-
? skillSet.skills.filter((s) => s.installed).length
|
|
93
|
-
: 0;
|
|
94
|
-
const totalCount = skillSet.loaded ? skillSet.skills.length : "...";
|
|
95
|
-
const countStr = `(${installedCount}/${totalCount})`;
|
|
96
|
-
// Any child installed at user or project scope?
|
|
97
|
-
const hasUser = skillSet.loaded && skillSet.skills.some((s) => s.installedScope === "user");
|
|
98
|
-
const hasProject = skillSet.loaded && skillSet.skills.some((s) => s.installedScope === "project");
|
|
99
|
-
const starsStr = formatStars(skillSet.stars);
|
|
100
|
-
return (_jsxs(SelectableRow, { selected: isSelected, indent: 1, children: [_jsxs("span", { fg: isSelected ? "white" : "gray", children: [arrow, " "] }), _jsxs("span", { fg: isSelected ? "white" : "yellow", children: [skillSet.icon, " "] }), _jsx("span", { fg: isSelected ? "white" : "cyan", children: _jsx("strong", { children: displayName }) }), _jsxs("span", { fg: "gray", children: [" ", countStr] }), starsStr ? _jsx(MetaText, { text: ` ${starsStr}`, tone: "warning" }) : null, _jsx("span", { children: " " }), _jsx(ScopeSquares, { user: hasUser, project: hasProject, selected: isSelected })] }));
|
|
101
|
-
},
|
|
102
|
-
renderDetail: ({ item }) => {
|
|
103
|
-
const { skillSet, expanded } = item;
|
|
104
|
-
const starsStr = formatStars(skillSet.stars);
|
|
105
|
-
return (_jsxs("box", { flexDirection: "column", children: [_jsxs("text", { fg: "cyan", children: [_jsxs("strong", { children: [skillSet.icon, " ", skillSet.name] }), starsStr ? _jsxs("span", { fg: "yellow", children: [" ", starsStr] }) : null] }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "white", children: skillSet.description }) }), _jsx(DetailSection, { children: _jsxs("text", { children: [_jsx("span", { fg: "gray", children: "Source " }), _jsx("span", { fg: "#5c9aff", children: skillSet.repo })] }) }), skillSet.loading && (_jsx("box", { marginTop: 1, children: _jsx("text", { fg: "yellow", children: "Loading skills..." }) })), skillSet.error && (_jsx("box", { marginTop: 1, children: _jsxs("text", { fg: "red", children: ["Error: ", skillSet.error] }) })), skillSet.loaded && skillSet.skills.length > 0 && (_jsxs(DetailSection, { children: [_jsxs("text", { children: [_jsx("strong", { children: "Skills in this set:" }), _jsxs("span", { fg: "gray", children: [" ", "(", skillSet.skills.filter((s) => s.installed).length, "/", skillSet.skills.length, " installed)"] })] }), _jsx("box", { marginTop: 1, flexDirection: "column", children: skillSet.skills.map((s) => (_jsxs("text", { children: [_jsx("span", { fg: s.installedScope === "user" ? "cyan" : "gray", children: s.installedScope === "user" ? "\u25A0" : "\u25A1" }), _jsx("span", { fg: s.installedScope === "project" ? "green" : "gray", children: s.installedScope === "project" ? "\u25A0" : "\u25A1" }), _jsxs("span", { fg: s.installed ? "white" : "gray", children: [" ", s.name] })] }, s.id))) })] })), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: expanded
|
|
106
|
-
? "Press Enter to collapse \u2022 u/p to install all"
|
|
107
|
-
: "Press Enter to expand \u2022 u/p to install all" }) }), _jsx("box", { children: _jsxs("text", { children: [_jsx("span", { bg: "#555555", fg: "white", children: " o " }), _jsx("span", { fg: "gray", children: " Open in browser" })] }) })] }));
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
// ─── Registry ─────────────────────────────────────────────────────────────────
|
|
111
|
-
export const skillRenderers = {
|
|
112
|
-
category: categoryRenderer,
|
|
113
|
-
skill: skillRenderer,
|
|
114
|
-
skillset: skillSetRenderer,
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
* Dispatch rendering by item kind.
|
|
118
|
-
*/
|
|
119
|
-
export function renderSkillRow(item, _index, isSelected) {
|
|
120
|
-
if (item.kind === "category") {
|
|
121
|
-
return skillRenderers.category.renderRow({ item, isSelected });
|
|
122
|
-
}
|
|
123
|
-
if (item.kind === "skillset") {
|
|
124
|
-
return skillRenderers.skillset.renderRow({ item, isSelected });
|
|
125
|
-
}
|
|
126
|
-
return skillRenderers.skill.renderRow({ item, isSelected });
|
|
127
|
-
}
|
|
128
|
-
export function renderSkillDetail(item) {
|
|
129
|
-
if (!item)
|
|
130
|
-
return _jsx("text", { fg: "gray", children: "Select a skill to see details" });
|
|
131
|
-
if (item.kind === "category") {
|
|
132
|
-
return skillRenderers.category.renderDetail({ item });
|
|
133
|
-
}
|
|
134
|
-
if (item.kind === "skillset") {
|
|
135
|
-
return skillRenderers.skillset.renderDetail({ item });
|
|
136
|
-
}
|
|
137
|
-
return skillRenderers.skill.renderDetail({ item });
|
|
138
|
-
}
|