refactor: consolidate plugin marketplace — remove duplicates, add repo-native plugins

Remove claude/qa/ and claude/ci/ plugins (replaced by go-build and
go-devops repo-native plugins). Strip duplicate qa command from code
plugin. Marketplace now references plugins at their source repos.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-13 10:06:58 +00:00
parent 63cb1e31bb
commit a607a49287
22 changed files with 19 additions and 1036 deletions

View file

@ -9,14 +9,14 @@
{
"name": "code",
"source": "./claude/code",
"description": "Core development plugin - hooks, scripts, data collection skills",
"version": "0.1.0"
"description": "Core development hooks, auto-approve workflow, and research data collection",
"version": "0.2.0"
},
{
"name": "review",
"source": "./claude/review",
"description": "Code review automation - PR review, security checks",
"version": "0.1.0"
"version": "0.2.0"
},
{
"name": "verify",
@ -25,15 +25,21 @@
"version": "0.1.0"
},
{
"name": "qa",
"source": "./claude/qa",
"description": "Quality assurance - iterative fix loops, lint enforcement",
"name": "core-php",
"source": "forge.lthn.ai/core/php",
"description": "PHP/Laravel development skills, API generation, and formatting",
"version": "0.1.0"
},
{
"name": "ci",
"source": "./claude/ci",
"description": "CI integration - GitHub Actions, test automation",
"name": "go-build",
"source": "forge.lthn.ai/core/go-build",
"description": "Go QA pipeline, build tooling, and development skills",
"version": "0.1.0"
},
{
"name": "devops",
"source": "forge.lthn.ai/core/go-devops",
"description": "CI/CD, deployment, issue tracking, and Coolify integration",
"version": "0.1.0"
}
]

View file

@ -1,8 +0,0 @@
{
"name": "ci",
"description": "CI integration - GitHub Actions status, workflow management",
"version": "0.1.0",
"author": {
"name": "Lethean"
}
}

View file

@ -1,54 +0,0 @@
---
name: ci
description: Check CI status and manage workflows
args: [status|run|logs|fix]
---
# CI Integration
Check CI status and manage workflows using the `core` CLI (supports Forgejo and GitHub).
## Commands
### Status (default)
```
/ci:ci
/ci:ci status
```
```bash
core dev ci
core dev ci --branch $(git branch --show-current)
core dev ci --failed
```
### List workflows
```
/ci:ci workflows
```
```bash
core dev workflow list
```
### Issues
```
/ci:ci issues
```
```bash
core dev issues
core dev issues --assignee @me
```
### Reviews / PRs
```
/ci:ci reviews
```
```bash
core dev reviews
core dev reviews --all
```
### Fix failing CI
```
/ci:ci fix
```
Analyse failing CI and suggest fixes. See `/ci:fix`.

View file

@ -1,47 +0,0 @@
---
name: fix
description: Analyse and fix failing CI
---
# Fix CI
Analyse failing CI runs and suggest/apply fixes.
## Process
1. **Get failing runs**
```bash
core dev ci --failed
```
2. **Analyse failure**
- Parse error messages from CI output
- Identify root cause
- Check if local issue or CI-specific
3. **Reproduce locally**
```bash
core go test
core go lint
core go vet
```
4. **Suggest fix**
- Code changes if needed
- CI config changes if needed
5. **Apply fix** (if approved)
## Common CI Failures
### Test Failures
→ Run `core go test --run TestFoo`, fix the test, push
### Lint Failures
→ Run `core go lint`, fix lint issues
### Build Failures
→ Run `core build`, check imports, run `core go fmt`
### Dependency Issues
→ Check go.mod, `core go fmt`, retry

View file

@ -1,33 +0,0 @@
---
name: run
description: Trigger a CI workflow run
args: [workflow-name]
---
# Run Workflow
Trigger a CI workflow or view available workflows.
## Usage
```
/ci:run # List available workflows
/ci:run tests # Trigger specific workflow
```
## Commands
```bash
# List available workflows
core dev workflow list
# Sync workflows across repos
core dev workflow sync
```
## Notes
- Forgejo Actions uses `.forgejo/workflows/` or `.github/workflows/` (both supported)
- Workflows are triggered automatically on push/PR/tag
- Manual dispatch: use the Forgejo web UI at `forge.lthn.ai/{owner}/{repo}/actions`
- Runner: `build-noc` on the noc server

View file

@ -1,63 +0,0 @@
---
name: status
description: Show CI status for current branch
---
# CI Status
Show CI status for the current branch.
## Usage
```
/ci:status
```
## Detection
Detect the CI provider from git remote, then use the appropriate method:
```bash
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
```
### Forgejo (forge.lthn.ai)
```bash
# Extract owner/repo from remote
OWNER_REPO=$(git remote get-url origin 2>/dev/null | sed -E 's#.*forge\.lthn\.ai[:/]+([0-9]+/)?##; s#\.git$##')
# List recent workflow runs (requires FORGEJO_TOKEN or use web UI)
curl -s "https://forge.lthn.ai/api/v1/repos/${OWNER_REPO}/actions/tasks?limit=10&state=running"
# Or just open the Actions page
echo "https://forge.lthn.ai/${OWNER_REPO}/actions"
```
### GitHub (fallback, requires gh CLI)
```bash
core dev ci
core dev ci --branch $(git branch --show-current)
core dev ci --failed
```
## Output
Present results as a status table:
```markdown
## CI Status: main
| Workflow | Status | When |
|----------|--------|------|
| Tests | pass | 5m ago |
| Build | pass | 5m ago |
**All checks passing**
```
If no API token available, output the web URL:
```
View CI status: https://forge.lthn.ai/{owner}/{repo}/actions
```

View file

@ -1,87 +0,0 @@
---
name: workflow
description: Create or update CI workflow
args: <workflow-type>
---
# Workflow Generator
Create or update CI workflows. Forgejo Actions uses the same YAML format as GitHub Actions.
## Usage
```
/ci:workflow test
/ci:workflow lint
/ci:workflow release
```
## List existing workflows
```bash
core dev workflow list
```
## Sync workflows across repos
```bash
core dev workflow sync
```
## Workflow directory
Forgejo supports both:
- `.forgejo/workflows/` (preferred)
- `.github/workflows/` (also works)
## Templates
### Go Test Workflow
```yaml
name: Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test -v -race ./...
```
### Go Release Workflow (core build)
```yaml
name: Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build and release
run: core build release --we-are-go-for-launch
```
## Forgejo Notes
- Runner label: `ubuntu-latest` (maps to Forgejo runner labels)
- Secrets: Set via repo Settings → Actions → Secrets
- Runner: `build-noc` on the noc server
- Web UI: `forge.lthn.ai/{owner}/{repo}/actions`

View file

@ -1,17 +0,0 @@
{
"$schema": "https://claude.ai/schemas/hooks.json",
"hooks": {
"PostToolUse": [
{
"matcher": "tool == \"Bash\" && tool_input.command matches \"^git push\"",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/post-push-ci.sh"
}
],
"description": "Show CI status after push"
}
]
}
}

View file

@ -1,21 +0,0 @@
#!/bin/bash
# Detect CI provider from git remote
# Outputs: "forgejo" or "github" or "unknown"
# Also exports FORGE_API, FORGE_OWNER, FORGE_REPO
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
if echo "$REMOTE_URL" | grep -q "forge.lthn.ai"; then
echo "forgejo"
# Extract owner/repo from SSH or HTTPS URL
# SSH: ssh://git@forge.lthn.ai:2223/core/go.git
# HTTPS: https://forge.lthn.ai/core/go.git
OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's#.*forge\.lthn\.ai[:/]+([0-9]+/)?##; s#\.git$##')
export FORGE_API="https://forge.lthn.ai/api/v1"
export FORGE_OWNER=$(echo "$OWNER_REPO" | cut -d'/' -f1)
export FORGE_REPO=$(echo "$OWNER_REPO" | cut -d'/' -f2)
elif echo "$REMOTE_URL" | grep -qE "github\.com"; then
echo "github"
else
echo "unknown"
fi

View file

@ -1,23 +0,0 @@
#!/bin/bash
# Show CI status hint after push
read -r input
EXIT_CODE=$(echo "$input" | jq -r '.tool_response.exit_code // 0')
if [ "$EXIT_CODE" = "0" ]; then
# Check if repo has workflows (Forgejo or GitHub)
if [ -d ".forgejo/workflows" ] || [ -d ".github/workflows" ]; then
cat << 'EOF'
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Push successful. CI workflows will run shortly.\n\nRun `/ci:status` to check progress or `core dev ci` to view status."
}
}
EOF
else
echo "$input"
fi
else
echo "$input"
fi

View file

@ -1,7 +1,7 @@
{
"name": "code",
"description": "Advanced Claude Code plugin for Host UK monorepo - core CLI integration, data collection skills, and autonomous workflows",
"version": "0.1.3",
"description": "Core development hooks, auto-approve workflow, and cryptocurrency research data collection skills",
"version": "0.2.0",
"author": {
"name": "Lethean",
"email": "hello@host.uk.com"
@ -10,11 +10,8 @@
"repository": "https://forge.lthn.ai/core/agent.git",
"license": "EUPL-1.2",
"keywords": [
"devops",
"monorepo",
"go",
"php",
"laravel",
"hooks",
"auto-approve",
"data-collection",
"cryptocurrency",
"archive"

View file

@ -1,155 +0,0 @@
---
name: qa
description: Run QA checks and fix all issues iteratively
hooks:
PostToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "${CLAUDE_PLUGIN_ROOT}/scripts/qa-filter.sh"
Stop:
- hooks:
- type: command
command: "${CLAUDE_PLUGIN_ROOT}/scripts/qa-verify.sh"
once: true
---
# QA Fix Loop
Run the full QA pipeline and fix all issues.
## Detection
First, detect the project type:
- If `go.mod` exists → Go project → `core go qa`
- If `composer.json` exists → PHP project → `core php qa`
- If both exist → ask user or check current directory
## Process
1. **Run QA**: Execute `core go qa` or `core php qa`
2. **Parse issues**: Extract failures from output (see format below)
3. **Fix each issue**: Address one at a time, simplest first
4. **Re-verify**: After fixes, re-run QA
5. **Repeat**: Until all checks pass
6. **Report**: Summary of what was fixed
## Issue Priority
Fix in this order (fastest feedback first):
1. **fmt** - formatting issues (auto-fix with `core go fmt`)
2. **lint** - static analysis (usually quick fixes)
3. **test** - failing tests (may need more investigation)
4. **build** - compilation errors (fix before tests can run)
## Output Parsing
### Go QA Output
```
=== FMT ===
FAIL: pkg/api/handler.go needs formatting
=== LINT ===
pkg/api/handler.go:42:15: undefined: ErrNotFound (typecheck)
pkg/api/handler.go:87:2: ineffectual assignment to err (ineffassign)
=== TEST ===
--- FAIL: TestCreateUser (0.02s)
handler_test.go:45: expected 200, got 500
FAIL
=== RESULT ===
fmt: FAIL
lint: FAIL (2 issues)
test: FAIL (1 failed)
```
### PHP QA Output
```
=== PINT ===
FAIL: 2 files need formatting
=== STAN ===
src/Http/Controller.php:42 - Undefined variable $user
=== TEST ===
✗ CreateUserTest::testSuccess
Expected status 200, got 500
=== RESULT ===
pint: FAIL
stan: FAIL (1 error)
test: FAIL (1 failed)
```
## Fixing Strategy
**Formatting (fmt/pint):**
- Just run `core go fmt` or `core php fmt`
- No code reading needed
**Lint errors:**
- Read the specific file:line
- Understand the error type
- Make minimal fix
**Test failures:**
- Read the test file to understand expectation
- Read the implementation
- Fix the root cause (not just the symptom)
**Build errors:**
- Usually missing imports or typos
- Fix before attempting other checks
## Stop Condition
Only stop when:
- All QA checks pass, OR
- User explicitly cancels, OR
- Same error repeats 3 times (stuck - ask for help)
## Example Session
```
Detecting project type... Found go.mod → Go project
Running: core go qa
## QA Issues
pkg/api/handler.go:42:15: undefined: ErrNotFound
--- FAIL: TestCreateUser (0.02s)
**Summary:** lint: FAIL (1) | test: FAIL (1)
---
Fixing lint issue: undefined ErrNotFound
Reading pkg/api/handler.go...
Adding error variable definition.
Running: core go qa
## QA Issues
--- FAIL: TestCreateUser (0.02s)
expected 200, got 404
**Summary:** lint: PASS | test: FAIL (1)
---
Fixing test issue: expected 200, got 404
Reading test setup...
Correcting test data.
Running: core go qa
✓ All checks passed!
**Summary:**
- Fixed: undefined ErrNotFound (added error variable)
- Fixed: TestCreateUser (corrected test setup)
- 2 issues resolved, all checks passing
```

View file

@ -1,62 +0,0 @@
#!/bin/bash
# Filter QA output to show only actionable issues during /core:qa mode
#
# PostToolUse hook that processes QA command output and extracts
# only the failures, hiding verbose success output.
read -r input
COMMAND=$(echo "$input" | jq -r '.tool_input.command // empty')
OUTPUT=$(echo "$input" | jq -r '.tool_response.stdout // .tool_response.output // empty')
EXIT_CODE=$(echo "$input" | jq -r '.tool_response.exit_code // 0')
# Only process QA-related commands
case "$COMMAND" in
"core go qa"*|"core php qa"*|"core go test"*|"core php test"*|"core go lint"*|"core php stan"*)
;;
*)
# Not a QA command, pass through unchanged
echo "$input"
exit 0
;;
esac
# Extract failures from output
FAILURES=$(echo "$OUTPUT" | grep -E "^(FAIL|---\s*FAIL|✗|ERROR|undefined:|error:|panic:)" | head -20)
SUMMARY=$(echo "$OUTPUT" | grep -E "^(fmt:|lint:|test:|pint:|stan:|=== RESULT ===)" | tail -5)
# Also grab specific error lines with file:line references
FILE_ERRORS=$(echo "$OUTPUT" | grep -E "^[a-zA-Z0-9_/.-]+\.(go|php):[0-9]+:" | head -10)
if [ -z "$FAILURES" ] && [ "$EXIT_CODE" = "0" ]; then
# All passed - show brief confirmation
cat << 'EOF'
{
"suppressOutput": true,
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "✓ QA passed"
}
}
EOF
else
# Combine failures and file errors
ISSUES="$FAILURES"
if [ -n "$FILE_ERRORS" ]; then
ISSUES="$ISSUES
$FILE_ERRORS"
fi
# Escape for JSON
ISSUES_ESCAPED=$(echo "$ISSUES" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
SUMMARY_ESCAPED=$(echo "$SUMMARY" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/ | /g')
cat << EOF
{
"suppressOutput": true,
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "## QA Issues\n\n\`\`\`\n$ISSUES_ESCAPED\n\`\`\`\n\n**Summary:** $SUMMARY_ESCAPED"
}
}
EOF
fi

View file

@ -1,44 +0,0 @@
#!/bin/bash
# Verify QA passes before stopping during /core:qa mode
#
# Stop hook that runs QA checks and blocks if any failures exist.
# Ensures Claude fixes all issues before completing the task.
read -r input
STOP_ACTIVE=$(echo "$input" | jq -r '.stop_hook_active // false')
# Prevent infinite loop
if [ "$STOP_ACTIVE" = "true" ]; then
exit 0
fi
# Detect project type and run QA
if [ -f "go.mod" ]; then
PROJECT="go"
RESULT=$(core go qa 2>&1) || true
elif [ -f "composer.json" ]; then
PROJECT="php"
RESULT=$(core php qa 2>&1) || true
else
# Not a Go or PHP project, allow stop
exit 0
fi
# Check if QA passed
if echo "$RESULT" | grep -qE "FAIL|ERROR|✗|panic:|undefined:"; then
# Extract top issues for context
ISSUES=$(echo "$RESULT" | grep -E "^(FAIL|ERROR|✗|undefined:|panic:)|^[a-zA-Z0-9_/.-]+\.(go|php):[0-9]+:" | head -5)
# Escape for JSON
ISSUES_ESCAPED=$(echo "$ISSUES" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
cat << EOF
{
"decision": "block",
"reason": "QA still has issues:\n\n$ISSUES_ESCAPED\n\nPlease fix these before stopping."
}
EOF
else
# QA passed, allow stop
exit 0
fi

View file

@ -1,8 +0,0 @@
{
"name": "qa",
"description": "Quality assurance - iterative fix loops, lint enforcement, test coverage",
"version": "0.1.0",
"author": {
"name": "Lethean"
}
}

View file

@ -1,74 +0,0 @@
---
name: check
description: Run QA checks without fixing (report only)
args: [--go|--php|--all]
---
# QA Check
Run QA pipeline and report issues without fixing them.
## Usage
```
/qa:check # Auto-detect project type
/qa:check --go # Force Go checks
/qa:check --php # Force PHP checks
/qa:check --all # Run both if applicable
```
## Process
1. **Detect project type**
2. **Run QA pipeline**
3. **Parse and report issues**
4. **Do NOT fix anything**
## Go Checks
```bash
core go qa
```
Runs:
- `go fmt` - Formatting
- `go vet` - Static analysis
- `golangci-lint` - Linting
- `go test` - Tests
## PHP Checks
```bash
core php qa
```
Runs:
- `pint` - Formatting
- `phpstan` - Static analysis
- `pest` - Tests
## Output
```markdown
## QA Report
**Project**: Go (go.mod detected)
**Status**: 3 issues found
### Formatting
✗ 2 files need formatting
- pkg/api/handler.go
- pkg/auth/token.go
### Linting
✗ 1 issue
- pkg/api/handler.go:42 - undefined: ErrNotFound
### Tests
✓ All passing (47/47)
---
**Summary**: fmt: FAIL | lint: FAIL | test: PASS
Run `/qa:qa` to fix these issues automatically.
```

View file

@ -1,57 +0,0 @@
---
name: fix
description: Fix a specific QA issue
args: <issue-description>
---
# Fix Issue
Fix a specific issue from QA output.
## Usage
```
/qa:fix undefined: ErrNotFound in pkg/api/handler.go:42
/qa:fix TestCreateUser failing - expected 200, got 500
/qa:fix pkg/api/handler.go needs formatting
```
## Process
1. **Parse the issue**: Extract file, line, error type
2. **Read context**: Read the file around the error line
3. **Understand**: Determine root cause
4. **Fix**: Make minimal change to resolve
5. **Verify**: Run relevant test/lint check
## Issue Types
### Undefined variable/type
```
undefined: ErrNotFound
```
→ Add missing import or define the variable
### Test failure
```
expected 200, got 500
```
→ Read test and implementation, fix logic
### Formatting
```
file needs formatting
```
→ Run `core go fmt` or `core php fmt`
### Lint warning
```
ineffectual assignment to err
```
→ Use the variable or remove assignment
### Type error
```
cannot use X as Y
```
→ Fix type conversion or function signature

View file

@ -1,78 +0,0 @@
---
name: lint
description: Run linter and fix issues
args: [--check|--fix]
---
# Lint
Run linter and optionally fix issues.
## Usage
```
/qa:lint # Run lint, report issues
/qa:lint --check # Check only, no fixes
/qa:lint --fix # Auto-fix where possible
```
## Process
### Go
```bash
# Check
core go lint
# Some issues can be auto-fixed
golangci-lint run --fix
```
### PHP
```bash
# Check
core php stan
# PHPStan doesn't auto-fix, but can suggest fixes
```
## Common Issues
### Go
| Issue | Fix |
|-------|-----|
| `undefined: X` | Add import or define variable |
| `ineffectual assignment` | Use variable or remove |
| `unused parameter` | Use `_` prefix or remove |
| `error return value not checked` | Handle the error |
### PHP
| Issue | Fix |
|-------|-----|
| `Undefined variable` | Define or check existence |
| `Parameter $x has no type` | Add type hint |
| `Method has no return type` | Add return type |
## Output
```markdown
## Lint Results
**Linter**: golangci-lint
**Issues**: 3
### Errors
1. **pkg/api/handler.go:42** - undefined: ErrNotFound
→ Add `var ErrNotFound = errors.New("not found")`
2. **pkg/api/handler.go:87** - error return value not checked
→ Handle error: `if err != nil { return err }`
### Warnings
1. **pkg/api/handler.go:15** - unused parameter ctx
→ Rename to `_` or use it
---
Run `/qa:lint --fix` to auto-fix where possible.
```

View file

@ -1,66 +0,0 @@
---
name: qa
description: Run full QA pipeline and fix all issues iteratively
hooks:
PostToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "${CLAUDE_PLUGIN_ROOT}/scripts/qa-filter.sh"
Stop:
- hooks:
- type: command
command: "${CLAUDE_PLUGIN_ROOT}/scripts/qa-verify.sh"
once: true
---
# QA Fix Loop
Run the full QA pipeline and fix all issues until everything passes.
## Detection
First, detect the project type:
- If `go.mod` exists → Go project → `core go qa`
- If `composer.json` exists → PHP project → `core php qa`
- If both exist → check current directory or ask
## Process
1. **Run QA**: Execute `core go qa` or `core php qa`
2. **Parse issues**: Extract failures from output
3. **Fix each issue**: Address one at a time, simplest first
4. **Re-verify**: After fixes, re-run QA
5. **Repeat**: Until all checks pass
6. **Report**: Summary of what was fixed
## Issue Priority
Fix in this order (fastest feedback first):
1. **fmt** - formatting (auto-fix with `core go fmt`)
2. **lint** - static analysis (usually quick fixes)
3. **test** - failing tests (may need investigation)
4. **build** - compilation errors (fix before tests can run)
## Fixing Strategy
**Formatting (fmt/pint):**
- Just run `core go fmt` or `core php fmt`
- No code reading needed
**Lint errors:**
- Read the specific file:line
- Understand the error type
- Make minimal fix
**Test failures:**
- Read the test file to understand expectation
- Read the implementation
- Fix the root cause (not just the symptom)
## Stop Condition
Only stop when:
- All QA checks pass, OR
- User explicitly cancels, OR
- Same error repeats 3 times (stuck - ask for help)

View file

@ -1,17 +0,0 @@
{
"$schema": "https://claude.ai/schemas/hooks.json",
"hooks": {
"PostToolUse": [
{
"matcher": "tool == \"Bash\" && tool_input.command matches \"^core (go|php) (qa|test|lint|stan)\"",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/qa-filter.sh"
}
],
"description": "Filter QA output to show only actionable issues"
}
]
}
}

View file

@ -1,62 +0,0 @@
#!/bin/bash
# Filter QA output to show only actionable issues during /core:qa mode
#
# PostToolUse hook that processes QA command output and extracts
# only the failures, hiding verbose success output.
read -r input
COMMAND=$(echo "$input" | jq -r '.tool_input.command // empty')
OUTPUT=$(echo "$input" | jq -r '.tool_response.stdout // .tool_response.output // empty')
EXIT_CODE=$(echo "$input" | jq -r '.tool_response.exit_code // 0')
# Only process QA-related commands
case "$COMMAND" in
"core go qa"*|"core php qa"*|"core go test"*|"core php test"*|"core go lint"*|"core php stan"*)
;;
*)
# Not a QA command, pass through unchanged
echo "$input"
exit 0
;;
esac
# Extract failures from output
FAILURES=$(echo "$OUTPUT" | grep -E "^(FAIL|---\s*FAIL|✗|ERROR|undefined:|error:|panic:)" | head -20)
SUMMARY=$(echo "$OUTPUT" | grep -E "^(fmt:|lint:|test:|pint:|stan:|=== RESULT ===)" | tail -5)
# Also grab specific error lines with file:line references
FILE_ERRORS=$(echo "$OUTPUT" | grep -E "^[a-zA-Z0-9_/.-]+\.(go|php):[0-9]+:" | head -10)
if [ -z "$FAILURES" ] && [ "$EXIT_CODE" = "0" ]; then
# All passed - show brief confirmation
cat << 'EOF'
{
"suppressOutput": true,
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "✓ QA passed"
}
}
EOF
else
# Combine failures and file errors
ISSUES="$FAILURES"
if [ -n "$FILE_ERRORS" ]; then
ISSUES="$ISSUES
$FILE_ERRORS"
fi
# Escape for JSON
ISSUES_ESCAPED=$(echo "$ISSUES" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
SUMMARY_ESCAPED=$(echo "$SUMMARY" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/ | /g')
cat << EOF
{
"suppressOutput": true,
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "## QA Issues\n\n\`\`\`\n$ISSUES_ESCAPED\n\`\`\`\n\n**Summary:** $SUMMARY_ESCAPED"
}
}
EOF
fi

View file

@ -1,44 +0,0 @@
#!/bin/bash
# Verify QA passes before stopping during /core:qa mode
#
# Stop hook that runs QA checks and blocks if any failures exist.
# Ensures Claude fixes all issues before completing the task.
read -r input
STOP_ACTIVE=$(echo "$input" | jq -r '.stop_hook_active // false')
# Prevent infinite loop
if [ "$STOP_ACTIVE" = "true" ]; then
exit 0
fi
# Detect project type and run QA
if [ -f "go.mod" ]; then
PROJECT="go"
RESULT=$(core go qa 2>&1) || true
elif [ -f "composer.json" ]; then
PROJECT="php"
RESULT=$(core php qa 2>&1) || true
else
# Not a Go or PHP project, allow stop
exit 0
fi
# Check if QA passed
if echo "$RESULT" | grep -qE "FAIL|ERROR|✗|panic:|undefined:"; then
# Extract top issues for context
ISSUES=$(echo "$RESULT" | grep -E "^(FAIL|ERROR|✗|undefined:|panic:)|^[a-zA-Z0-9_/.-]+\.(go|php):[0-9]+:" | head -5)
# Escape for JSON
ISSUES_ESCAPED=$(echo "$ISSUES" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
cat << EOF
{
"decision": "block",
"reason": "QA still has issues:\n\n$ISSUES_ESCAPED\n\nPlease fix these before stopping."
}
EOF
else
# QA passed, allow stop
exit 0
fi