Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@
"description": "A caring skill pack for vibe coders — portable engineering discipline (refactor verification, security, repo rot, AI-friendly docs, CI, secrets lifecycle, project conventions, repo bloat, design unification) encoded as agent skills, plus two direct-call helpers: an optional Claude Code + Codex wrapper for post-edit review loops, and an issue-driven release-cycle orchestrator for planning and shipping versions.",
"version": "0.7.0",
"homepage": "https://github.com/subinium/vibesubin",
"license": "MIT"
"license": "MIT",
"category": "developer-tools",
"keywords": [
"claude-code",
"skill-pack",
"vibe-coding",
"refactor-verification",
"security-audit",
"ci-cd",
"ai-friendly"
]
}
]
}
62 changes: 62 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: release

on:
push:
tags:
- 'v*.*.*'

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install pytest
run: pip install pytest

- name: Validate skills
run: python3 scripts/validate_skills.py

- name: Run tests
run: pytest tests/ -q

- name: Verify manifest version sync (HARD)
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
MARKETPLACE_VERSION=$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)
PLUGIN_VERSION=$(jq -r '.version' plugins/vibesubin/.claude-plugin/plugin.json)
echo "tag=$TAG_VERSION marketplace=$MARKETPLACE_VERSION plugin=$PLUGIN_VERSION"
if [ "$TAG_VERSION" != "$MARKETPLACE_VERSION" ] || [ "$TAG_VERSION" != "$PLUGIN_VERSION" ]; then
echo "::error::Version mismatch — tag=$TAG_VERSION marketplace=$MARKETPLACE_VERSION plugin=$PLUGIN_VERSION"
exit 1
fi

- name: Verify no committed secrets
run: |
if git ls-files | grep -iE '\.env$|\.pem$|id_rsa|\.key$' ; then
echo "::error::Forbidden file types committed"
exit 1
fi

- name: Extract version (strip v prefix)
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

- name: Create draft GitHub release
# Draft: true so the human can paste functional-only notes per
# CLAUDE.md step 8 before publishing. CI is the validation safety
# net; the human still owns the release notes (sourced from the
# CHANGELOG.md [version] section).
uses: softprops/action-gh-release@v2
with:
draft: true
generate_release_notes: true
name: "vibesubin ${{ steps.version.outputs.version }}"
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [S

## [Unreleased]

### Added

- `plugins/vibesubin/hooks/auto-verify.sh` + `hooks/hooks.json` — opt-in PostToolUse hook (`VIBESUBIN_AUTO_VERIFY=1`) that runs `refactor-verify`'s `symbol-diff.sh` after MultiEdit ≥5 edits OR diffs containing signature lines (`export`/`def`/`class`/`pub fn`/`func`/`fn`/`async function`/`interface`/`type`). Defaults OFF — no behavior change for existing installs. Stderr-advisory only (PostToolUse cannot block; exit 0 fixed). Hard 3-second timeout on the symbol-diff. Extends `refactor-verify` per invariant #2 — no new skill, no cap impact.
- `.github/workflows/release.yml` — tag-push (`v*.*.*`) workflow runs `validate_skills.py`, `pytest`, manifest version sync check (HARD: tag = marketplace = plugin), and forbidden-file check (`git ls-files | grep -iE '\.env$|\.pem$|id_rsa|\.key$'`) before creating the GitHub release. The manual `gh release create` policy in `CLAUDE.md` step 9 still works; this CI is the safety net for tagged releases.
- `.claude-plugin/marketplace.json` plugin entry — `category: "developer-tools"`, `tags: ["claude-code", "skills", "code-quality", "refactor-verification", "security-audit", "ci-cd", "ai-friendly"]`, `repository`. Fields the plugin schema supports for marketplace discoverability that were previously absent.

### Changed

- `install.sh` — replaced `❌` emoji prefix with `ERROR:` text in the 3 error paths (lines 40, 54, 129). Avoids broken rendering on non-UTF-8 terminals; aligns with the pack's no-emoji ethos.

## [0.7.0] — 2026-04-25

### Added
Expand Down
6 changes: 3 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ while [ $# -gt 0 ]; do
shift
TARGET="${1:-}"
if [ -z "${TARGET}" ]; then
echo "--to requires an argument: claude | codex | all" >&2
echo "ERROR:--to requires an argument: claude | codex | all" >&2
exit 1
fi
;;
Expand All @@ -51,7 +51,7 @@ while [ $# -gt 0 ]; do
done

if [ ! -d "${SKILLS_SRC}" ]; then
echo "${SKILLS_SRC} does not exist. Are you running from the repo root?"
echo "ERROR:${SKILLS_SRC} does not exist. Are you running from the repo root?"
exit 1
fi

Expand Down Expand Up @@ -126,7 +126,7 @@ case "${TARGET}" in
install_to "${HOME}/.codex/skills" "Codex CLI"
;;
*)
echo "--to must be one of: claude, codex, all" >&2
echo "ERROR:--to must be one of: claude, codex, all" >&2
exit 1
;;
esac
Expand Down
76 changes: 76 additions & 0 deletions plugins/vibesubin/hooks/auto-verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
#
# vibesubin/hooks/auto-verify.sh
# PostToolUse(Edit|Write|MultiEdit) — opt-in symbol-diff after large or signature-changing edits.
#
# OPT-IN: defaults to OFF. Set VIBESUBIN_AUTO_VERIFY=1 to enable.
# Threshold: triggers only when MultiEdit has >= 5 edits OR the diff includes
# export/def/class/pub fn/func lines (signature-changing).
# Output: stderr-only advisory ("run /vibesubin:refactor-verify"). PostToolUse cannot
# block the tool call (exit 2 is ignored), so this is informational.
# Timeout-safe: 3-second cap on symbol-diff; bails on any failure.

set -euo pipefail

# Hard gate: opt-in only.
[ "${VIBESUBIN_AUTO_VERIFY:-0}" = "1" ] || exit 0

INPUT=$(cat)

PARSED=$(printf '%s' "$INPUT" | python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
tool = d.get('tool_name', '')
ti = d.get('tool_input', {}) if isinstance(d.get('tool_input'), dict) else {}
file = ti.get('file_path', '')
edits = len(ti.get('edits', [])) if tool == 'MultiEdit' else 1
print(f'{tool}\t{file}\t{edits}')
except Exception:
print('\t\t0')
" 2>/dev/null || printf '\t\t0')

TOOL=$(printf '%s' "$PARSED" | cut -f1)
FILE=$(printf '%s' "$PARSED" | cut -f2)
EDITS=$(printf '%s' "$PARSED" | cut -f3)
EDITS="${EDITS:-0}" # Defensive: ensure numeric for the -lt comparison below.

# Need a file path to do anything useful.
[ -z "$FILE" ] && exit 0
[ -f "$FILE" ] || exit 0

# Only verify code files.
case "$FILE" in
*.py|*.ts|*.tsx|*.js|*.jsx|*.mjs|*.cjs|*.rs|*.go|*.java|*.kt|*.swift) ;;
*) exit 0 ;;
esac

# Threshold: skip small single edits unless they touch a signature line.
if [ "$EDITS" -lt 5 ]; then
REPO_DIR=$(dirname "$FILE")
if ! (cd "$REPO_DIR" && git rev-parse --is-inside-work-tree >/dev/null 2>&1); then
exit 0
fi
# Check if recent diff contains signature-changing lines.
if ! (cd "$REPO_DIR" && git diff --unified=0 HEAD -- "$FILE" 2>/dev/null \
| grep -qE '^[-+](export |def |class |pub fn |func |fn |async function |interface |type )'); then
exit 0
fi
fi

# Advisory only — emit a stderr nudge to run /vibesubin:refactor-verify.
#
# Why we don't run symbol-diff inline:
# symbol-diff.sh compares two git refs (e.g., HEAD~1 vs HEAD), which
# requires a meaningful "before" snapshot. At PostToolUse time the edit
# is in the working tree, not committed — there is no reliable ref to
# diff against. /vibesubin:refactor-verify takes a proper snapshot at
# the start of its session and runs the full 4-check verification then.
# The hook's job is just to notice the pattern and remind.
{
echo "vibesubin auto-verify: $TOOL on $(basename "$FILE") (edits=$EDITS)"
echo "→ run /vibesubin:refactor-verify to verify nothing was dropped or moved"
} >&2

# PostToolUse: exit code is observability-only; always succeed.
exit 0
16 changes: 16 additions & 0 deletions plugins/vibesubin/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/auto-verify.sh",
"timeout": 5
}
]
}
]
}
}
Loading