docs(command-development): add SlashCommand tool coverage #27
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Plugin Component Validation | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review] | |
| paths: | |
| - "plugins/plugin-dev/commands/**" | |
| - "plugins/plugin-dev/skills/**" | |
| - "plugins/plugin-dev/agents/**" | |
| - "plugins/plugin-dev/hooks/**" | |
| # Cancel any in-progress validation for the same PR when new commits are pushed | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| validate: | |
| # Skip bots and draft PRs | |
| if: | | |
| github.actor != 'dependabot[bot]' && | |
| github.actor != 'claude[bot]' && | |
| github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| id-token: write | |
| actions: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get changed plugin component files | |
| id: changed-files | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Get list of changed files in this PR, filtered to plugin components | |
| # Note: gh pr diff includes deleted files, so we filter to only existing files | |
| changed_files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only | \ | |
| grep -E '^plugins/plugin-dev/(commands|skills|agents|hooks)/' | \ | |
| grep -v '\-SUGGESTED\.md$' | \ | |
| grep -v '\-BACKUP\.md$' | \ | |
| grep -v '\-OLD\.md$' | \ | |
| while read -r file; do [ -f "$file" ] && echo "$file"; done || true) | |
| if [ -z "$changed_files" ]; then | |
| echo "No plugin component files changed" | |
| echo "has_changes=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Changed plugin component files:" | |
| echo "$changed_files" | |
| echo "has_changes=true" >> "$GITHUB_OUTPUT" | |
| # Store as newline-separated list for the prompt | |
| { | |
| echo "files<<EOF" | |
| echo "$changed_files" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Validate plugin components | |
| if: steps.changed-files.outputs.has_changes == 'true' | |
| uses: anthropics/claude-code-action@6337623ebba10cf8c8214b507993f8062fd4ccfb # v1.0.22 | |
| id: validate | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| prompt: | | |
| Validate ONLY the changed plugin component files listed below. | |
| ## Context | |
| - Repository: ${{ github.repository }} | |
| - PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }} | |
| ## Changed Files to Validate | |
| ``` | |
| ${{ steps.changed-files.outputs.files }} | |
| ``` | |
| **IMPORTANT**: Only validate the files listed above. Do NOT validate other files in the plugin directories. | |
| ## Instructions | |
| 1. Read and validate ONLY the changed files listed above | |
| 2. Return structured JSON with validation results | |
| ## Validation Rules | |
| ### Commands (`plugins/plugin-dev/commands/*.md`) | |
| For each changed command file, verify: | |
| - [ ] YAML frontmatter exists with `name`, `description`, `allowed-tools` fields | |
| - [ ] `description` is 60 characters or fewer | |
| - [ ] `allowed-tools` follows these rules: | |
| - MUST use `Bash(gh:*)` not unrestricted `Bash` (security requirement) | |
| - `Read` is always allowed (reading files is safe) | |
| - `Write` is allowed ONLY if the command creates/exports files (e.g., status export) | |
| - `AskUserQuestion` is always allowed (user interaction is safe) | |
| - Do NOT flag tools that are appropriate for the command's purpose | |
| - [ ] Body uses imperative form ("Do X", "Create Y") not second person ("You should X") | |
| - [ ] No draft file patterns in filename (`*-SUGGESTED.md`, `*-BACKUP.md`, `*-OLD.md`) | |
| ### Skills (`plugins/plugin-dev/skills/*/SKILL.md`) | |
| For each changed skill SKILL.md file, verify: | |
| - [ ] YAML frontmatter exists with `name`, `description` fields | |
| - [ ] `description` uses third-person with trigger phrases (starts with "This skill should be used when...") | |
| - [ ] Body length is reasonable (core concepts, not exhaustive documentation) | |
| ### Agents (`plugins/plugin-dev/agents/*.md`) | |
| For each changed agent file, verify: | |
| - [ ] YAML frontmatter exists with `name`, `description`, `model`, `color`, `tools` fields | |
| - [ ] `description` field includes `<example>` blocks (at least 2, ideally 3-4) | |
| - [ ] Each `<example>` block has proper structure (Context line, `user:` and `assistant:` dialogue lines, and `<commentary>` XML tags) | |
| - [ ] `tools` list is present and appropriate for the agent's purpose | |
| ### Hooks (`plugins/plugin-dev/hooks/hooks.json`) | |
| For changed hooks file, verify: | |
| - [ ] File is valid JSON | |
| - [ ] Event types are valid: UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, PreCompact, Notification | |
| - [ ] Matcher patterns are valid regex (test by attempting to compile) | |
| ## Output Format | |
| Return ONLY valid JSON matching this schema: | |
| ```json | |
| { | |
| "commands_valid": true/false, | |
| "commands_issues": ["issue 1", "issue 2"], | |
| "skills_valid": true/false, | |
| "skills_issues": ["issue 1", "issue 2"], | |
| "agents_valid": true/false, | |
| "agents_issues": ["issue 1", "issue 2"], | |
| "hooks_valid": true/false, | |
| "hooks_issues": ["issue 1", "issue 2"], | |
| "all_valid": true/false, | |
| "summary": "Brief overall summary" | |
| } | |
| ``` | |
| Set `all_valid` to true only if all changed files pass validation. | |
| Set category to valid (true) if no changed files exist for that category. | |
| Include specific file names and line numbers in issues when possible. | |
| claude_args: | | |
| --allowedTools "Read,Glob,Grep" | |
| --json-schema '{"type":"object","properties":{"commands_valid":{"type":"boolean"},"commands_issues":{"type":"array","items":{"type":"string"}},"skills_valid":{"type":"boolean"},"skills_issues":{"type":"array","items":{"type":"string"}},"agents_valid":{"type":"boolean"},"agents_issues":{"type":"array","items":{"type":"string"}},"hooks_valid":{"type":"boolean"},"hooks_issues":{"type":"array","items":{"type":"string"}},"all_valid":{"type":"boolean"},"summary":{"type":"string"}},"required":["all_valid"]}' | |
| - name: Check validation result | |
| if: always() && steps.changed-files.outputs.has_changes == 'true' && steps.validate.outputs.structured_output != '' | |
| env: | |
| VALIDATION_OUTPUT: ${{ steps.validate.outputs.structured_output }} | |
| run: | | |
| { | |
| echo "## Validation Results" | |
| echo '```json' | |
| echo "$VALIDATION_OUTPUT" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| # Validate JSON output before processing | |
| if ! all_valid=$(echo "$VALIDATION_OUTPUT" | jq -r '.all_valid' 2>/dev/null); then | |
| echo "Error: Invalid JSON output from validation step" | |
| echo "Raw output:" | |
| echo "$VALIDATION_OUTPUT" | |
| exit 1 | |
| fi | |
| if [ "$all_valid" != "true" ]; then | |
| { | |
| echo "" | |
| echo "### Issues Found" | |
| # Group issues by component type for cleaner output | |
| # Use // 0 to handle null/missing arrays gracefully | |
| if [ "$(echo "$VALIDATION_OUTPUT" | jq -r '(.commands_issues | length) // 0')" -gt 0 ]; then | |
| echo "**Commands:**" | |
| echo "$VALIDATION_OUTPUT" | jq -r '.commands_issues[] | "- " + .' | |
| fi | |
| if [ "$(echo "$VALIDATION_OUTPUT" | jq -r '(.skills_issues | length) // 0')" -gt 0 ]; then | |
| echo "**Skills:**" | |
| echo "$VALIDATION_OUTPUT" | jq -r '.skills_issues[] | "- " + .' | |
| fi | |
| if [ "$(echo "$VALIDATION_OUTPUT" | jq -r '(.agents_issues | length) // 0')" -gt 0 ]; then | |
| echo "**Agents:**" | |
| echo "$VALIDATION_OUTPUT" | jq -r '.agents_issues[] | "- " + .' | |
| fi | |
| if [ "$(echo "$VALIDATION_OUTPUT" | jq -r '(.hooks_issues | length) // 0')" -gt 0 ]; then | |
| echo "**Hooks:**" | |
| echo "$VALIDATION_OUTPUT" | jq -r '.hooks_issues[] | "- " + .' | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| echo "" | |
| echo "Component validation failed. Please fix the issues above." | |
| exit 1 | |
| fi | |
| { | |
| echo "" | |
| echo "All changed plugin components are valid." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Skip validation (no changes) | |
| if: steps.changed-files.outputs.has_changes != 'true' | |
| run: | | |
| echo "## Validation Skipped" >> "$GITHUB_STEP_SUMMARY" | |
| echo "No plugin component files were changed in this PR." >> "$GITHUB_STEP_SUMMARY" |