@@ -252,7 +252,11 @@ def uninstall_plugin(
252252 plugin : str = typer .Argument (..., help = "Plugin name to uninstall" ),
253253 force : bool = typer .Option (False , "--force" , "-f" , help = "Skip confirmation" ),
254254):
255- """Uninstall an installed plugin."""
255+ """Uninstall an installed plugin.
256+
257+ For marketplace plugins, this removes the plugin from enabled plugins settings.
258+ For standalone plugins, this uses Claude CLI to fully uninstall.
259+ """
256260 _check_claude_cli ()
257261 handler = _get_handler ()
258262
@@ -268,8 +272,128 @@ def uninstall_plugin(
268272 f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
269273 )
270274 else :
271- typer .echo (f"{ Colors .RED } ✗ { msg } { Colors .RESET } " )
272- raise typer .Exit (1 )
275+ # Claude CLI failed - try to remove from settings directly
276+ # This handles marketplace plugins which can't be "uninstalled" via CLI
277+ typer .echo (
278+ f"{ Colors .YELLOW } Claude CLI uninstall failed, trying to remove from settings...{ Colors .RESET } "
279+ )
280+
281+ removed = _remove_plugin_from_settings (handler , plugin )
282+ if removed :
283+ typer .echo (
284+ f"{ Colors .GREEN } ✓ Removed '{ plugin } ' from enabled plugins{ Colors .RESET } "
285+ )
286+ typer .echo (
287+ f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
288+ )
289+ else :
290+ typer .echo (
291+ f"{ Colors .RED } ✗ Plugin '{ plugin } ' not found in settings{ Colors .RESET } "
292+ )
293+ raise typer .Exit (1 )
294+
295+
296+ def _remove_plugin_from_settings (handler , plugin : str ) -> bool :
297+ """Remove a plugin from Claude's settings.json.
298+
299+ Args:
300+ handler: Claude plugin handler
301+ plugin: Plugin name (with or without @marketplace suffix)
302+
303+ Returns:
304+ True if plugin was found and removed, False otherwise
305+ """
306+ import json
307+
308+ settings_file = handler .settings_file
309+ if not settings_file .exists ():
310+ return False
311+
312+ try :
313+ with open (settings_file , "r" ) as f :
314+ settings = json .load (f )
315+ except Exception :
316+ return False
317+
318+ enabled = settings .get ("enabledPlugins" , {})
319+ if not enabled :
320+ return False
321+
322+ # Find matching plugin key(s)
323+ keys_to_remove = []
324+ plugin_lower = plugin .lower ()
325+ for key in enabled :
326+ # Match exact key or plugin name part (before @)
327+ key_name = key .split ("@" )[0 ] if "@" in key else key
328+ if key .lower () == plugin_lower or key_name .lower () == plugin_lower :
329+ keys_to_remove .append (key )
330+
331+ if not keys_to_remove :
332+ return False
333+
334+ # Remove the plugin(s)
335+ for key in keys_to_remove :
336+ del enabled [key ]
337+
338+ settings ["enabledPlugins" ] = enabled
339+
340+ # Write back
341+ try :
342+ with open (settings_file , "w" ) as f :
343+ json .dump (settings , f , indent = 2 )
344+ return True
345+ except Exception :
346+ return False
347+
348+
349+ def _set_plugin_enabled (handler , plugin : str , enabled : bool ) -> bool :
350+ """Set a plugin's enabled state in Claude's settings.json.
351+
352+ Args:
353+ handler: Claude plugin handler
354+ plugin: Plugin name (with or without @marketplace suffix)
355+ enabled: True to enable, False to disable
356+
357+ Returns:
358+ True if plugin was found and updated, False otherwise
359+ """
360+ import json
361+
362+ settings_file = handler .settings_file
363+ if not settings_file .exists ():
364+ return False
365+
366+ try :
367+ with open (settings_file , "r" ) as f :
368+ settings = json .load (f )
369+ except Exception :
370+ return False
371+
372+ enabled_plugins = settings .get ("enabledPlugins" , {})
373+
374+ # Find matching plugin key
375+ plugin_lower = plugin .lower ()
376+ matching_key = None
377+ for key in enabled_plugins :
378+ key_name = key .split ("@" )[0 ] if "@" in key else key
379+ if key .lower () == plugin_lower or key_name .lower () == plugin_lower :
380+ matching_key = key
381+ break
382+
383+ if not matching_key :
384+ return False
385+
386+ # Update the enabled state
387+ enabled_plugins [matching_key ] = enabled
388+ settings ["enabledPlugins" ] = enabled_plugins
389+
390+ # Write back
391+ try :
392+ with open (settings_file , "w" ) as f :
393+ json .dump (settings , f , indent = 2 )
394+ return True
395+ except Exception :
396+ return False
273397
274398
275399@plugin_app .command ("enable" )
@@ -289,8 +413,22 @@ def enable_plugin(
289413 f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
290414 )
291415 else :
292- typer .echo (f"{ Colors .RED } ✗ { msg } { Colors .RESET } " )
293- raise typer .Exit (1 )
416+ # Claude CLI failed - try to enable in settings directly
417+ typer .echo (
418+ f"{ Colors .YELLOW } Claude CLI enable failed, trying to update settings...{ Colors .RESET } "
419+ )
420+
421+ enabled = _set_plugin_enabled (handler , plugin , True )
422+ if enabled :
423+ typer .echo (f"{ Colors .GREEN } ✓ Enabled '{ plugin } ' in settings{ Colors .RESET } " )
424+ typer .echo (
425+ f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
426+ )
427+ else :
428+ typer .echo (
429+ f"{ Colors .RED } ✗ Plugin '{ plugin } ' not found in settings{ Colors .RESET } "
430+ )
431+ raise typer .Exit (1 )
294432
295433
296434@plugin_app .command ("disable" )
@@ -310,8 +448,22 @@ def disable_plugin(
310448 f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
311449 )
312450 else :
313- typer .echo (f"{ Colors .RED } ✗ { msg } { Colors .RESET } " )
314- raise typer .Exit (1 )
451+ # Claude CLI failed - try to disable in settings directly
452+ typer .echo (
453+ f"{ Colors .YELLOW } Claude CLI disable failed, trying to update settings...{ Colors .RESET } "
454+ )
455+
456+ disabled = _set_plugin_enabled (handler , plugin , False )
457+ if disabled :
458+ typer .echo (f"{ Colors .GREEN } ✓ Disabled '{ plugin } ' in settings{ Colors .RESET } " )
459+ typer .echo (
460+ f"\n { Colors .YELLOW } Note: Restart Claude Code to apply changes.{ Colors .RESET } "
461+ )
462+ else :
463+ typer .echo (
464+ f"{ Colors .RED } ✗ Plugin '{ plugin } ' not found in settings{ Colors .RESET } "
465+ )
466+ raise typer .Exit (1 )
315467
316468
317469@plugin_app .command ("validate" )
0 commit comments