@@ -678,6 +678,8 @@ func runPluginMarketplaceCLI(state *bootstrap.State, args []string, stdout io.Wr
678678 return runPluginMarketplaceUpdateCLI (state , args [1 :], stdout , stderr )
679679 case "plugins" , "available" , "browse" , "discover" , "search" , "find" :
680680 return runPluginMarketplacePluginsCLI (state , args [1 :], stdout , stderr )
681+ case "show" , "info" :
682+ return runPluginMarketplaceShowCLI (state , args [1 :], stdout , stderr )
681683 default :
682684 fmt .Fprintf (stderr , "ccgo plugin marketplace: unsupported subcommand %s\n " , args [0 ])
683685 return 2
@@ -946,6 +948,82 @@ func runPluginMarketplacePluginsCLI(state *bootstrap.State, args []string, stdou
946948 return 0
947949}
948950
951+ func runPluginMarketplaceShowCLI (state * bootstrap.State , args []string , stdout io.Writer , stderr io.Writer ) int {
952+ flags := flag .NewFlagSet ("claude plugin marketplace show" , flag .ContinueOnError )
953+ flags .SetOutput (stderr )
954+ jsonOutput := flags .Bool ("json" , false , "output JSON" )
955+ if err := flags .Parse (args ); err != nil {
956+ if err == flag .ErrHelp {
957+ return 0
958+ }
959+ return 2
960+ }
961+ name := strings .TrimSpace (strings .Join (flags .Args (), " " ))
962+ if name == "" {
963+ fmt .Fprintln (stderr , "ccgo plugin marketplace show: usage: claude plugin marketplace show [--json] <plugin>" )
964+ return 2
965+ }
966+ runner , err := state .ConversationRunner ()
967+ if err != nil {
968+ fmt .Fprintf (stderr , "ccgo plugin marketplace show: %v\n " , err )
969+ return 1
970+ }
971+ settings := runnerMergedSettings (runner )
972+ marketplacePlugins := pluginpkg .LoadMarketplacePluginDirsWithSettings (settings )
973+ installedPlugins := pluginpkg .LoadPluginDirs (pluginpkg .InstalledPluginDirs (runner .WorkingDirectory ))
974+ entries := pluginCLIMarketplacePluginEntries (marketplacePlugins , installedPlugins , "" )
975+ entry , ok := pluginCLIMarketplaceFindEntry (entries , name )
976+ if ! ok {
977+ fmt .Fprintf (stderr , "ccgo plugin marketplace show: plugin %q not found in configured marketplaces\n " , name )
978+ return 1
979+ }
980+ if * jsonOutput {
981+ encoder := json .NewEncoder (stdout )
982+ encoder .SetIndent ("" , " " )
983+ if err := encoder .Encode (entry ); err != nil {
984+ fmt .Fprintf (stderr , "ccgo plugin marketplace show: %v\n " , err )
985+ return 1
986+ }
987+ return 0
988+ }
989+ writePluginMarketplaceShowResult (stdout , entry )
990+ return 0
991+ }
992+
993+ func writePluginMarketplaceShowResult (stdout io.Writer , plugin pluginCLIAvailableEntry ) {
994+ status := plugin .Status
995+ if status == "" {
996+ status = "available"
997+ }
998+ lines := []string {
999+ "Marketplace plugin" ,
1000+ "Name: " + plugin .Name ,
1001+ }
1002+ if plugin .PluginID != "" {
1003+ lines = append (lines , "Plugin ID: " + plugin .PluginID )
1004+ }
1005+ if plugin .MarketplaceName != "" {
1006+ lines = append (lines , "Marketplace: " + plugin .MarketplaceName )
1007+ }
1008+ if plugin .Version != "" {
1009+ lines = append (lines , "Version: " + plugin .Version )
1010+ }
1011+ lines = append (lines , "Status: " + status )
1012+ if plugin .InstalledVersion != "" {
1013+ lines = append (lines , "Installed version: " + plugin .InstalledVersion )
1014+ }
1015+ if plugin .InstallPath != "" {
1016+ lines = append (lines , "Installed path: " + plugin .InstallPath )
1017+ }
1018+ if plugin .Source != "" {
1019+ lines = append (lines , "Source: " + plugin .Source )
1020+ }
1021+ if description := strings .TrimSpace (plugin .Description ); description != "" {
1022+ lines = append (lines , "Description: " + description )
1023+ }
1024+ fmt .Fprintln (stdout , strings .Join (lines , "\n " ))
1025+ }
1026+
9491027func writePluginInstallResult (stdout io.Writer , result pluginpkg.PluginInstallResult ) {
9501028 lines := []string {
9511029 "Plugin installed" ,
@@ -1258,6 +1336,37 @@ func pluginCLIMarketplacePluginEntries(marketplacePlugins []pluginpkg.LoadedPlug
12581336 return out
12591337}
12601338
1339+ func pluginCLIMarketplaceFindEntry (entries []pluginCLIAvailableEntry , name string ) (pluginCLIAvailableEntry , bool ) {
1340+ name = strings .TrimSpace (name )
1341+ if name == "" {
1342+ return pluginCLIAvailableEntry {}, false
1343+ }
1344+ for _ , entry := range entries {
1345+ for _ , candidate := range pluginCLIMarketplaceEntryNames (entry ) {
1346+ if strings .EqualFold (candidate , name ) {
1347+ return entry , true
1348+ }
1349+ }
1350+ }
1351+ return pluginCLIAvailableEntry {}, false
1352+ }
1353+
1354+ func pluginCLIMarketplaceEntryNames (entry pluginCLIAvailableEntry ) []string {
1355+ var names []string
1356+ for _ , candidate := range []string {
1357+ entry .PluginID ,
1358+ entry .Name ,
1359+ entry .Name + "@" + entry .MarketplaceName ,
1360+ entry .Name + "@" + entry .Version ,
1361+ } {
1362+ candidate = strings .TrimSpace (strings .Trim (candidate , "@" ))
1363+ if candidate != "" {
1364+ names = append (names , candidate )
1365+ }
1366+ }
1367+ return names
1368+ }
1369+
12611370func pluginCLIMarketplaceEntryMatches (entry pluginCLIAvailableEntry , query string ) bool {
12621371 fields := []string {
12631372 entry .PluginID ,
0 commit comments