fix: Handle object plugin sources in marketplace.json
marketplace.json source field can be a relative path string or an
object (github, url, npm, pip). Pinch only supports relative paths
since it clones the marketplace repo; object sources now get a clear
error instead of a deserialization failure.

Assisted-by: Claude Opus 4.6 via pi
change yvslwqoqtlwyvqnlmpsoowuwmosswnom
commit 761d01d9ccd39c9a78babc75739a0a3d27f0fa2b
author Alpha Chen <alpha@kejadlen.dev>
date
parent spztvkwr
diff --git a/src/marketplace.rs b/src/marketplace.rs
index aff70ff..c6f0c1e 100644
--- a/src/marketplace.rs
+++ b/src/marketplace.rs
@@ -1,6 +1,6 @@
 use std::path::Path;
 
-use color_eyre::eyre::{Context, Result, eyre};
+use color_eyre::eyre::{Context, Result, bail, eyre};
 use serde::Deserialize;
 
 const DEFAULT_PATH: &str = ".claude-plugin/marketplace.json";
@@ -13,7 +13,21 @@ pub struct Marketplace {
 #[derive(Debug, Deserialize)]
 pub struct MarketplacePlugin {
     pub name: String,
-    pub source: String,
+    pub source: PluginSource,
+}
+
+/// A plugin source in marketplace.json.
+///
+/// Can be a relative path string (e.g. `"./plugins/my-plugin"`) or an object
+/// describing an external source (github, git url, npm, pip). Pinch only
+/// supports relative paths since it clones the marketplace repo directly.
+#[derive(Debug, Deserialize)]
+#[serde(untagged)]
+pub enum PluginSource {
+    /// Relative path within the marketplace repo.
+    Path(String),
+    /// External source (github, url, npm, pip) — not supported by pinch.
+    External(serde_json::Value),
 }
 
 /// Find the source path for a plugin by name in the marketplace.json.
@@ -29,16 +43,26 @@ pub fn find_plugin_source(
     let marketplace: Marketplace = serde_json::from_str(&contents)
         .with_context(|| format!("failed to parse {}", manifest_path.display()))?;
 
-    marketplace
+    let plugin = marketplace
         .plugins
         .iter()
         .find(|mp| mp.name == plugin_name)
-        .map(|mp| mp.source.clone())
         .ok_or_else(|| {
             eyre!(
                 "plugin '{}' not found in {}",
                 plugin_name,
                 manifest_path.display()
             )
-        })
+        })?;
+
+    match &plugin.source {
+        PluginSource::Path(path) => Ok(path.clone()),
+        PluginSource::External(value) => {
+            bail!(
+                "plugin '{}': external source {} — pinch only supports relative path sources",
+                plugin_name,
+                value
+            );
+        }
+    }
 }