claudeup 3.10.0 → 3.11.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeup",
3
- "version": "3.10.0",
3
+ "version": "3.11.0",
4
4
  "description": "TUI tool for managing Claude Code plugins, MCPs, and configuration",
5
5
  "type": "module",
6
6
  "main": "src/main.tsx",
@@ -251,8 +251,6 @@ export function PluginsScreen() {
251
251
  handleUpdate();
252
252
  else if (event.name === "a")
253
253
  handleUpdateAll();
254
- else if (event.name === "d")
255
- handleUninstall();
256
254
  else if (event.name === "s")
257
255
  handleSaveAsProfile();
258
256
  // "/" to enter search mode
@@ -621,7 +619,7 @@ export function PluginsScreen() {
621
619
  const plugin = item.plugin;
622
620
  const latestVersion = plugin.version || "0.0.0";
623
621
  const scopeLabel = scope === "user" ? "User" : scope === "project" ? "Project" : "Local";
624
- // Check if installed in this scope
622
+ // Check if installed in this specific scope
625
623
  const scopeData = scope === "user"
626
624
  ? plugin.userScope
627
625
  : scope === "project"
@@ -629,12 +627,16 @@ export function PluginsScreen() {
629
627
  : plugin.localScope;
630
628
  const isInstalledInScope = scopeData?.enabled;
631
629
  const installedVersion = scopeData?.version;
630
+ // Also check if installed in ANY scope (for the toggle behavior)
631
+ const isInstalledAnywhere = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
632
632
  // Check if this scope has an update available
633
633
  const hasUpdateInScope = isInstalledInScope &&
634
634
  installedVersion &&
635
635
  latestVersion !== "0.0.0" &&
636
636
  installedVersion !== latestVersion;
637
- // Determine action: update if available, otherwise toggle install/uninstall
637
+ // Determine action: if installed in this scope → uninstall
638
+ // If installed anywhere else but not this scope → uninstall from detected scope
639
+ // Otherwise → install
638
640
  let action;
639
641
  if (isInstalledInScope && hasUpdateInScope) {
640
642
  action = "update";
@@ -642,9 +644,13 @@ export function PluginsScreen() {
642
644
  else if (isInstalledInScope) {
643
645
  action = "uninstall";
644
646
  }
645
- else {
647
+ else if (!isInstalledAnywhere) {
646
648
  action = "install";
647
649
  }
650
+ else {
651
+ // Installed in a different scope — uninstall from the scope it's actually in
652
+ action = "uninstall";
653
+ }
648
654
  const actionLabel = action === "update"
649
655
  ? `Updating ${scopeLabel}`
650
656
  : action === "install"
@@ -801,18 +807,15 @@ export function PluginsScreen() {
801
807
  const plugin = item.plugin;
802
808
  let statusIcon = "○";
803
809
  let statusColor = "gray";
810
+ const isAnyScope = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
804
811
  if (plugin.isOrphaned) {
805
812
  statusIcon = "x";
806
813
  statusColor = "red";
807
814
  }
808
- else if (plugin.enabled) {
815
+ else if (isAnyScope) {
809
816
  statusIcon = "●";
810
817
  statusColor = "green";
811
818
  }
812
- else if (plugin.installedVersion) {
813
- statusIcon = "●";
814
- statusColor = "yellow";
815
- }
816
819
  // Build version string
817
820
  let versionStr = "";
818
821
  if (plugin.isOrphaned) {
@@ -881,7 +884,7 @@ export function PluginsScreen() {
881
884
  }
882
885
  if (selectedItem.type === "plugin" && selectedItem.plugin) {
883
886
  const plugin = selectedItem.plugin;
884
- const isInstalled = plugin.enabled || plugin.installedVersion;
887
+ const isInstalled = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
885
888
  // Orphaned/deprecated plugin
886
889
  if (plugin.isOrphaned) {
887
890
  return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { justifyContent: "center", children: _jsx("text", { bg: "yellow", fg: "black", children: _jsxs("strong", { children: [" ", plugin.name, " \u2014 DEPRECATED "] }) }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "yellow", children: "This plugin is no longer in the marketplace." }) }), _jsx("box", { marginTop: 1, children: _jsx("text", { fg: "gray", children: "It was removed from the marketplace but still referenced in your settings. Press d to uninstall and clean up." }) }), isInstalled && (_jsx("box", { flexDirection: "column", marginTop: 2, children: _jsxs("box", { children: [_jsx("text", { bg: "red", fg: "white", children: " d " }), _jsx("text", { children: " Uninstall (recommended)" })] }) }))] }));
@@ -903,13 +906,13 @@ export function PluginsScreen() {
903
906
  const showVersion = plugin.version && plugin.version !== "0.0.0";
904
907
  const showInstalledVersion = plugin.installedVersion && plugin.installedVersion !== "0.0.0";
905
908
  return (_jsxs("box", { flexDirection: "column", children: [_jsx("box", { justifyContent: "center", children: _jsx("text", { bg: "magenta", fg: "white", children: _jsxs("strong", { children: [" ", plugin.name, plugin.hasUpdate ? " ⬆" : "", " "] }) }) }), _jsx("box", { marginTop: 1, children: isInstalled ? (_jsx("text", { fg: "green", children: "\u25CF Installed" })) : (_jsx("text", { fg: "gray", children: "\u25CB Not installed" })) }), _jsx("box", { marginTop: 1, marginBottom: 1, children: _jsx("text", { fg: "white", children: plugin.description }) }), showVersion && (_jsxs("text", { children: [_jsx("span", { children: "Version " }), _jsxs("span", { fg: "#5c9aff", children: ["v", plugin.version] }), showInstalledVersion &&
906
- plugin.installedVersion !== plugin.version && (_jsxs("span", { children: [" (v", plugin.installedVersion, " installed)"] }))] })), plugin.category && (_jsxs("text", { children: [_jsx("span", { children: "Category " }), _jsx("span", { fg: "magenta", children: plugin.category })] })), plugin.author && (_jsxs("text", { children: [_jsx("span", { children: "Author " }), _jsx("span", { children: plugin.author.name })] })), components.length > 0 && (_jsxs("text", { children: [_jsx("span", { children: "Contains " }), _jsx("span", { fg: "yellow", children: components.join(" · ") })] })), _jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsxs("span", { bg: "cyan", fg: "black", children: [" ", "u", " "] }), _jsx("span", { fg: plugin.userScope?.enabled ? "cyan" : "gray", children: plugin.userScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "cyan", children: "User" }), _jsx("span", { children: " global" }), plugin.userScope?.version && (_jsxs("span", { fg: "cyan", children: [" v", plugin.userScope.version] }))] }), _jsxs("text", { children: [_jsxs("span", { bg: "green", fg: "black", children: [" ", "p", " "] }), _jsx("span", { fg: plugin.projectScope?.enabled ? "green" : "gray", children: plugin.projectScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "green", children: "Project" }), _jsx("span", { children: " team" }), plugin.projectScope?.version && (_jsxs("span", { fg: "green", children: [" v", plugin.projectScope.version] }))] }), _jsxs("text", { children: [_jsxs("span", { bg: "yellow", fg: "black", children: [" ", "l", " "] }), _jsx("span", { fg: plugin.localScope?.enabled ? "yellow" : "gray", children: plugin.localScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "yellow", children: "Local" }), _jsx("span", { children: " private" }), plugin.localScope?.version && (_jsxs("span", { fg: "yellow", children: [" v", plugin.localScope.version] }))] })] })] }), isInstalled && (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [plugin.hasUpdate && (_jsxs("box", { children: [_jsxs("text", { bg: "magenta", fg: "white", children: [" ", "U", " "] }), _jsxs("text", { children: [" Update to v", plugin.version] })] })), _jsxs("box", { children: [_jsxs("text", { bg: "red", fg: "white", children: [" ", "d", " "] }), _jsx("text", { children: " Uninstall" })] })] }))] }));
909
+ plugin.installedVersion !== plugin.version && (_jsxs("span", { children: [" (v", plugin.installedVersion, " installed)"] }))] })), plugin.category && (_jsxs("text", { children: [_jsx("span", { children: "Category " }), _jsx("span", { fg: "magenta", children: plugin.category })] })), plugin.author && (_jsxs("text", { children: [_jsx("span", { children: "Author " }), _jsx("span", { children: plugin.author.name })] })), components.length > 0 && (_jsxs("text", { children: [_jsx("span", { children: "Contains " }), _jsx("span", { fg: "yellow", children: components.join(" · ") })] })), _jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsx("text", { children: _jsx("strong", { children: "Scopes:" }) }), _jsxs("box", { marginTop: 1, flexDirection: "column", children: [_jsxs("text", { children: [_jsxs("span", { bg: "cyan", fg: "black", children: [" ", "u", " "] }), _jsx("span", { fg: plugin.userScope?.enabled ? "cyan" : "gray", children: plugin.userScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "cyan", children: "User" }), _jsx("span", { children: " global" }), plugin.userScope?.version && (_jsxs("span", { fg: "cyan", children: [" v", plugin.userScope.version] }))] }), _jsxs("text", { children: [_jsxs("span", { bg: "green", fg: "black", children: [" ", "p", " "] }), _jsx("span", { fg: plugin.projectScope?.enabled ? "green" : "gray", children: plugin.projectScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "green", children: "Project" }), _jsx("span", { children: " team" }), plugin.projectScope?.version && (_jsxs("span", { fg: "green", children: [" v", plugin.projectScope.version] }))] }), _jsxs("text", { children: [_jsxs("span", { bg: "yellow", fg: "black", children: [" ", "l", " "] }), _jsx("span", { fg: plugin.localScope?.enabled ? "yellow" : "gray", children: plugin.localScope?.enabled ? " ● " : " ○ " }), _jsx("span", { fg: "yellow", children: "Local" }), _jsx("span", { children: " private" }), plugin.localScope?.version && (_jsxs("span", { fg: "yellow", children: [" v", plugin.localScope.version] }))] })] })] }), isInstalled && (_jsx("box", { flexDirection: "column", marginTop: 1, children: plugin.hasUpdate && (_jsxs("box", { children: [_jsxs("text", { bg: "magenta", fg: "white", children: [" ", "U", " "] }), _jsxs("text", { children: [" Update to v", plugin.version] })] })) }))] }));
907
910
  }
908
911
  return null;
909
912
  };
910
913
  const footerHints = isSearchActive
911
914
  ? "type to filter │ Enter:done │ Esc:clear"
912
- : "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │ /:search";
915
+ : "u/p/l:toggle │ U:update │ a:all │ s:profile │ /:search";
913
916
  // Calculate status for subtitle
914
917
  const scopeLabel = pluginsState.scope === "global" ? "Global" : "Project";
915
918
  const plugins = pluginsState.plugins.status === "success" ? pluginsState.plugins.data : [];
@@ -317,7 +317,6 @@ export function PluginsScreen() {
317
317
  else if (event.name === "l") handleScopeToggle("local");
318
318
  else if (event.name === "U") handleUpdate();
319
319
  else if (event.name === "a") handleUpdateAll();
320
- else if (event.name === "d") handleUninstall();
321
320
  else if (event.name === "s") handleSaveAsProfile();
322
321
  // "/" to enter search mode
323
322
  else if (event.name === "/") {
@@ -792,7 +791,7 @@ export function PluginsScreen() {
792
791
  const scopeLabel =
793
792
  scope === "user" ? "User" : scope === "project" ? "Project" : "Local";
794
793
 
795
- // Check if installed in this scope
794
+ // Check if installed in this specific scope
796
795
  const scopeData =
797
796
  scope === "user"
798
797
  ? plugin.userScope
@@ -802,6 +801,9 @@ export function PluginsScreen() {
802
801
  const isInstalledInScope = scopeData?.enabled;
803
802
  const installedVersion = scopeData?.version;
804
803
 
804
+ // Also check if installed in ANY scope (for the toggle behavior)
805
+ const isInstalledAnywhere = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
806
+
805
807
  // Check if this scope has an update available
806
808
  const hasUpdateInScope =
807
809
  isInstalledInScope &&
@@ -809,14 +811,19 @@ export function PluginsScreen() {
809
811
  latestVersion !== "0.0.0" &&
810
812
  installedVersion !== latestVersion;
811
813
 
812
- // Determine action: update if available, otherwise toggle install/uninstall
814
+ // Determine action: if installed in this scope → uninstall
815
+ // If installed anywhere else but not this scope → uninstall from detected scope
816
+ // Otherwise → install
813
817
  let action: "update" | "install" | "uninstall";
814
818
  if (isInstalledInScope && hasUpdateInScope) {
815
819
  action = "update";
816
820
  } else if (isInstalledInScope) {
817
821
  action = "uninstall";
818
- } else {
822
+ } else if (!isInstalledAnywhere) {
819
823
  action = "install";
824
+ } else {
825
+ // Installed in a different scope — uninstall from the scope it's actually in
826
+ action = "uninstall";
820
827
  }
821
828
 
822
829
  const actionLabel =
@@ -1046,15 +1053,13 @@ export function PluginsScreen() {
1046
1053
  let statusIcon = "○";
1047
1054
  let statusColor = "gray";
1048
1055
 
1056
+ const isAnyScope = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
1049
1057
  if (plugin.isOrphaned) {
1050
1058
  statusIcon = "x";
1051
1059
  statusColor = "red";
1052
- } else if (plugin.enabled) {
1060
+ } else if (isAnyScope) {
1053
1061
  statusIcon = "●";
1054
1062
  statusColor = "green";
1055
- } else if (plugin.installedVersion) {
1056
- statusIcon = "●";
1057
- statusColor = "yellow";
1058
1063
  }
1059
1064
 
1060
1065
  // Build version string
@@ -1178,7 +1183,7 @@ export function PluginsScreen() {
1178
1183
 
1179
1184
  if (selectedItem.type === "plugin" && selectedItem.plugin) {
1180
1185
  const plugin = selectedItem.plugin;
1181
- const isInstalled = plugin.enabled || plugin.installedVersion;
1186
+ const isInstalled = plugin.userScope?.enabled || plugin.projectScope?.enabled || plugin.localScope?.enabled;
1182
1187
 
1183
1188
  // Orphaned/deprecated plugin
1184
1189
  if (plugin.isOrphaned) {
@@ -1345,13 +1350,6 @@ export function PluginsScreen() {
1345
1350
  <text> Update to v{plugin.version}</text>
1346
1351
  </box>
1347
1352
  )}
1348
- <box>
1349
- <text bg="red" fg="white">
1350
- {" "}
1351
- d{" "}
1352
- </text>
1353
- <text> Uninstall</text>
1354
- </box>
1355
1353
  </box>
1356
1354
  )}
1357
1355
  </box>
@@ -1363,7 +1361,7 @@ export function PluginsScreen() {
1363
1361
 
1364
1362
  const footerHints = isSearchActive
1365
1363
  ? "type to filter │ Enter:done │ Esc:clear"
1366
- : "u/p/l:scope │ U:update │ a:all │ d:remove │ s:profile │ /:search";
1364
+ : "u/p/l:toggle │ U:update │ a:all │ s:profile │ /:search";
1367
1365
 
1368
1366
  // Calculate status for subtitle
1369
1367
  const scopeLabel = pluginsState.scope === "global" ? "Global" : "Project";