use crate::Claude;
use crate::command::ClaudeCommand;
use crate::error::Result;
use crate::exec::{self, CommandOutput};
use crate::types::Scope;
#[derive(Debug, Clone, Default)]
pub struct MarketplaceListCommand {
json: bool,
}
impl MarketplaceListCommand {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn json(mut self) -> Self {
self.json = true;
self
}
}
impl ClaudeCommand for MarketplaceListCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
let mut args = vec![
"plugin".to_string(),
"marketplace".to_string(),
"list".to_string(),
];
if self.json {
args.push("--json".to_string());
}
args
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone)]
pub struct MarketplaceAddCommand {
source: String,
scope: Option<Scope>,
sparse: Vec<String>,
}
impl MarketplaceAddCommand {
#[must_use]
pub fn new(source: impl Into<String>) -> Self {
Self {
source: source.into(),
scope: None,
sparse: Vec::new(),
}
}
#[must_use]
pub fn scope(mut self, scope: Scope) -> Self {
self.scope = Some(scope);
self
}
#[must_use]
pub fn sparse(mut self, paths: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.sparse.extend(paths.into_iter().map(Into::into));
self
}
}
impl ClaudeCommand for MarketplaceAddCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
let mut args = vec![
"plugin".to_string(),
"marketplace".to_string(),
"add".to_string(),
];
if let Some(ref scope) = self.scope {
args.push("--scope".to_string());
args.push(scope.as_arg().to_string());
}
if !self.sparse.is_empty() {
args.push("--sparse".to_string());
args.extend(self.sparse.clone());
}
args.push(self.source.clone());
args
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone)]
pub struct MarketplaceRemoveCommand {
name: String,
}
impl MarketplaceRemoveCommand {
#[must_use]
pub fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
}
impl ClaudeCommand for MarketplaceRemoveCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
vec![
"plugin".to_string(),
"marketplace".to_string(),
"remove".to_string(),
self.name.clone(),
]
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone, Default)]
pub struct MarketplaceUpdateCommand {
name: Option<String>,
}
impl MarketplaceUpdateCommand {
#[must_use]
pub fn all() -> Self {
Self { name: None }
}
#[must_use]
pub fn new(name: impl Into<String>) -> Self {
Self {
name: Some(name.into()),
}
}
}
impl ClaudeCommand for MarketplaceUpdateCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
let mut args = vec![
"plugin".to_string(),
"marketplace".to_string(),
"update".to_string(),
];
if let Some(ref name) = self.name {
args.push(name.clone());
}
args
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::command::ClaudeCommand;
#[test]
fn test_marketplace_list() {
let cmd = MarketplaceListCommand::new().json();
assert_eq!(
ClaudeCommand::args(&cmd),
vec!["plugin", "marketplace", "list", "--json"]
);
}
#[test]
fn test_marketplace_add() {
let cmd = MarketplaceAddCommand::new("https://github.com/org/mp").scope(Scope::User);
assert_eq!(
ClaudeCommand::args(&cmd),
vec![
"plugin",
"marketplace",
"add",
"--scope",
"user",
"https://github.com/org/mp"
]
);
}
#[test]
fn test_marketplace_add_sparse() {
let cmd = MarketplaceAddCommand::new("https://github.com/org/monorepo")
.sparse([".claude-plugin", "plugins"]);
let args = ClaudeCommand::args(&cmd);
assert!(args.contains(&"--sparse".to_string()));
assert!(args.contains(&".claude-plugin".to_string()));
assert!(args.contains(&"plugins".to_string()));
}
#[test]
fn test_marketplace_remove() {
let cmd = MarketplaceRemoveCommand::new("old-mp");
assert_eq!(
ClaudeCommand::args(&cmd),
vec!["plugin", "marketplace", "remove", "old-mp"]
);
}
#[test]
fn test_marketplace_update_all() {
let cmd = MarketplaceUpdateCommand::all();
assert_eq!(
ClaudeCommand::args(&cmd),
vec!["plugin", "marketplace", "update"]
);
}
#[test]
fn test_marketplace_update_specific() {
let cmd = MarketplaceUpdateCommand::new("my-mp");
assert_eq!(
ClaudeCommand::args(&cmd),
vec!["plugin", "marketplace", "update", "my-mp"]
);
}
}