diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 65544fd..763d924 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,6 +9,21 @@ "name": "astral", "source": "./plugins/astral", "description": "Skills for working with Python using Astral tools." + }, + { + "name": "ruff-format", + "source": "./plugins/ruff-format", + "description": "Auto-format Python files with ruff after edits." + }, + { + "name": "cargo-format", + "source": "./plugins/cargo-format", + "description": "Auto-format Rust files with cargo fmt after edits." + }, + { + "name": "prettier-format", + "source": "./plugins/prettier-format", + "description": "Auto-format files with prettier after edits." } ] } diff --git a/plugins/cargo-format/.claude-plugin/hooks/post-edit-format.py b/plugins/cargo-format/.claude-plugin/hooks/post-edit-format.py new file mode 100644 index 0000000..27baa08 --- /dev/null +++ b/plugins/cargo-format/.claude-plugin/hooks/post-edit-format.py @@ -0,0 +1,45 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [] +# /// + +"""Post-edit hook to auto-format Rust files with cargo fmt.""" + +import json +import os +import subprocess +import sys +from pathlib import Path + + +def main() -> None: + input_data = json.load(sys.stdin) + + tool_name = input_data.get("tool_name") + tool_input = input_data.get("tool_input", {}) + file_path = tool_input.get("file_path") + + if tool_name not in ("Write", "Edit", "MultiEdit"): + return + + if not file_path: + return + + path = Path(file_path) + if path.suffix != ".rs": + return + + cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd()) + + try: + subprocess.run( + ["cargo", "fmt", "--", file_path], + cwd=cwd, + capture_output=True, + ) + except FileNotFoundError: + pass + + +if __name__ == "__main__": + main() diff --git a/plugins/cargo-format/.claude-plugin/plugin.json b/plugins/cargo-format/.claude-plugin/plugin.json new file mode 100644 index 0000000..5006329 --- /dev/null +++ b/plugins/cargo-format/.claude-plugin/plugin.json @@ -0,0 +1,19 @@ +{ + "name": "cargo-format", + "description": "Auto-format Rust files with cargo fmt after edits.", + "version": "0.1.0", + "author": { + "name": "Astral", + "url": "https://astral.sh" + }, + "repository": "https://github.com/astral-sh/claude-code-plugins", + "license": "MIT", + "keywords": ["rust", "cargo", "formatting"], + "hooks": [ + { + "type": "PostToolUse", + "command": "python", + "args": [".claude-plugin/hooks/post-edit-format.py"] + } + ] +} diff --git a/plugins/prettier-format/.claude-plugin/hooks/post-edit-format.py b/plugins/prettier-format/.claude-plugin/hooks/post-edit-format.py new file mode 100644 index 0000000..0b69b9d --- /dev/null +++ b/plugins/prettier-format/.claude-plugin/hooks/post-edit-format.py @@ -0,0 +1,45 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [] +# /// + +"""Post-edit hook to auto-format files with prettier.""" + +import json +import os +import subprocess +import sys +from pathlib import Path + + +def main() -> None: + input_data = json.load(sys.stdin) + + tool_name = input_data.get("tool_name") + tool_input = input_data.get("tool_input", {}) + file_path = tool_input.get("file_path") + + if tool_name not in ("Write", "Edit", "MultiEdit"): + return + + if not file_path: + return + + path = Path(file_path) + if path.suffix not in (".json5", ".yaml", ".yml", ".md"): + return + + cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd()) + + try: + subprocess.run( + ["npx", "prettier", "--write", file_path], + cwd=cwd, + capture_output=True, + ) + except FileNotFoundError: + pass + + +if __name__ == "__main__": + main() diff --git a/plugins/prettier-format/.claude-plugin/plugin.json b/plugins/prettier-format/.claude-plugin/plugin.json new file mode 100644 index 0000000..183889b --- /dev/null +++ b/plugins/prettier-format/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "prettier-format", + "description": "Auto-format files with prettier after edits.", + "version": "0.1.0", + "repository": "https://github.com/astral-sh/claude-code-plugins", + "license": "MIT", + "keywords": ["prettier", "formatting", "json", "yaml", "markdown"], + "hooks": [ + { + "type": "PostToolUse", + "command": "python", + "args": [".claude-plugin/hooks/post-edit-format.py"] + } + ] +} diff --git a/plugins/ruff-format/.claude-plugin/hooks/post-edit-format.py b/plugins/ruff-format/.claude-plugin/hooks/post-edit-format.py new file mode 100644 index 0000000..76ce4cf --- /dev/null +++ b/plugins/ruff-format/.claude-plugin/hooks/post-edit-format.py @@ -0,0 +1,45 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [] +# /// + +"""Post-edit hook to auto-format Python files with ruff.""" + +import json +import os +import subprocess +import sys +from pathlib import Path + + +def main() -> None: + input_data = json.load(sys.stdin) + + tool_name = input_data.get("tool_name") + tool_input = input_data.get("tool_input", {}) + file_path = tool_input.get("file_path") + + if tool_name not in ("Write", "Edit", "MultiEdit"): + return + + if not file_path: + return + + path = Path(file_path) + if path.suffix not in (".py", ".pyi"): + return + + cwd = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd()) + + try: + subprocess.run( + ["uvx", "ruff", "format", file_path], + cwd=cwd, + capture_output=True, + ) + except FileNotFoundError: + pass + + +if __name__ == "__main__": + main() diff --git a/plugins/ruff-format/.claude-plugin/plugin.json b/plugins/ruff-format/.claude-plugin/plugin.json new file mode 100644 index 0000000..9d1b2dc --- /dev/null +++ b/plugins/ruff-format/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "ruff-format", + "description": "Auto-format Python files with ruff after edits.", + "version": "0.1.0", + "author": { + "name": "Astral", + "url": "https://astral.sh" + }, + "homepage": "https://docs.astral.sh/ruff/", + "repository": "https://github.com/astral-sh/claude-code-plugins", + "license": "MIT", + "keywords": ["ruff", "python", "formatting"], + "hooks": [ + { + "type": "PostToolUse", + "command": "python", + "args": [".claude-plugin/hooks/post-edit-format.py"] + } + ] +}