diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index dbdbd07b64..eaa0713ace 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -3542,6 +3542,37 @@ fn run_resume_command( json: Some(handle_skills_slash_command_json(args.as_deref(), &cwd)?), }) } + SlashCommand::Plugins { action, target } => { + // Only list is supported in resume mode (no runtime to reload) + match action.as_deref() { + Some("install") | Some("uninstall") | Some("enable") | Some("disable") + | Some("update") => { + return Err( + "resumed /plugins mutations are interactive-only; start `claw` and run `/plugins` in the REPL".into(), + ); + } + _ => {} + } + let cwd = env::current_dir()?; + let loader = ConfigLoader::default_for(&cwd); + let runtime_config = loader.load()?; + let mut manager = build_plugin_manager(&cwd, &loader, &runtime_config); + let result = + handle_plugins_slash_command(action.as_deref(), target.as_deref(), &mut manager)?; + let action_str = action.as_deref().unwrap_or("list"); + let json = serde_json::json!({ + "kind": "plugin", + "action": action_str, + "target": target, + "message": &result.message, + "reload_runtime": result.reload_runtime, + }); + Ok(ResumeCommandOutcome { + session: session.clone(), + message: Some(result.message), + json: Some(json), + }) + } SlashCommand::Doctor => { let report = render_doctor_report()?; Ok(ResumeCommandOutcome { @@ -3628,7 +3659,6 @@ fn run_resume_command( | SlashCommand::Model { .. } | SlashCommand::Permissions { .. } | SlashCommand::Session { .. } - | SlashCommand::Plugins { .. } | SlashCommand::Login | SlashCommand::Logout | SlashCommand::Vim diff --git a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs index e5d8372cff..c305d93979 100644 --- a/rust/crates/rusty-claude-cli/tests/output_format_contract.rs +++ b/rust/crates/rusty-claude-cli/tests/output_format_contract.rs @@ -360,6 +360,34 @@ fn resumed_inventory_commands_emit_structured_json_when_requested() { assert_eq!(skills["action"], "list"); assert!(skills["summary"]["total"].is_number()); assert!(skills["skills"].is_array()); + + let plugins = assert_json_command_with_env( + &root, + &[ + "--output-format", + "json", + "--resume", + session_path.to_str().expect("utf8 session path"), + "/plugins", + ], + &[ + ( + "CLAW_CONFIG_HOME", + config_home.to_str().expect("utf8 config home"), + ), + ("HOME", home.to_str().expect("utf8 home")), + ], + ); + assert_eq!(plugins["kind"], "plugin"); + assert_eq!(plugins["action"], "list"); + assert!( + plugins["reload_runtime"].is_boolean(), + "plugins reload_runtime should be a boolean" + ); + assert!( + plugins["target"].is_null(), + "plugins target should be null when no plugin is targeted" + ); } #[test]