From 4a18b7aaf6337449aa2f28c16cf03cf7740b8e46 Mon Sep 17 00:00:00 2001 From: Tanq16 <37408906+Tanq16@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:07:41 -0400 Subject: [PATCH] cmd: add init-plugin command for plugin scaffolding Scaffold a Claude Code plugin directory from a name argument: empty skills/agents/hooks/output-styles dirs (each with a .gitkeep), plus .claude-plugin/plugin.json, .mcp.json, .lsp.json and settings.json skeletons. Refuses to overwrite an existing directory. --- cmd/init-plugin.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 1 + 2 files changed, 75 insertions(+) create mode 100644 cmd/init-plugin.go diff --git a/cmd/init-plugin.go b/cmd/init-plugin.go new file mode 100644 index 0000000..ae6a715 --- /dev/null +++ b/cmd/init-plugin.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/spf13/cobra" + u "github.com/tanq16/claudex/utils" +) + +var initPluginCmd = &cobra.Command{ + Use: "init-plugin ", + Short: "Scaffold a Claude Code plugin directory", + Args: cobra.ExactArgs(1), + Run: runInitPlugin, +} + +func runInitPlugin(cmd *cobra.Command, args []string) { + name := args[0] + + cwd, err := os.Getwd() + if err != nil { + u.PrintFatal("failed to resolve current directory", err) + } + target := filepath.Join(cwd, name) + + if _, err := os.Stat(target); err == nil { + u.PrintFatal(fmt.Sprintf("%s already exists; refusing to overwrite", target), nil) + } + + if err := os.MkdirAll(target, 0o755); err != nil { + u.PrintFatal("failed to create plugin scaffold", err) + } + for _, sub := range []string{"skills", "agents", "hooks", "output-styles"} { + dir := filepath.Join(target, sub) + if err := os.MkdirAll(dir, 0o755); err != nil { + u.PrintFatal("failed to create plugin scaffold", err) + } + if err := os.WriteFile(filepath.Join(dir, ".gitkeep"), nil, 0o644); err != nil { + u.PrintFatal("failed to create plugin scaffold", err) + } + } + + if err := os.MkdirAll(filepath.Join(target, ".claude-plugin"), 0o755); err != nil { + u.PrintFatal("failed to create plugin scaffold", err) + } + + files := []struct { + path string + body any + }{ + {filepath.Join(target, ".claude-plugin", "plugin.json"), map[string]any{"name": name, "version": "0.0.1"}}, + {filepath.Join(target, ".mcp.json"), map[string]any{"mcpServers": map[string]any{}}}, + {filepath.Join(target, ".lsp.json"), map[string]any{}}, + {filepath.Join(target, "settings.json"), map[string]any{}}, + } + for _, f := range files { + if err := writeJSON(f.path, f.body); err != nil { + u.PrintFatal("failed to create plugin scaffold", err) + } + } + + u.PrintSuccess(fmt.Sprintf("Created plugin scaffold at %s", target)) +} + +func writeJSON(path string, v any) error { + data, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + return os.WriteFile(path, append(data, '\n'), 0o644) +} diff --git a/cmd/root.go b/cmd/root.go index b4444fc..caab65f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -66,4 +66,5 @@ func init() { rootCmd.AddCommand(launchCmd) rootCmd.AddCommand(configureCmd) rootCmd.AddCommand(aiDocsCmd) + rootCmd.AddCommand(initPluginCmd) }