$npx -y skills add Soul-Brews-Studio/arra-oracle-skills-cli --skill releaseAutomated release flow — bump version, changelog, tag, push, GitHub release. Use when user says "release", "ship", "bump version", "tag", or "publish".
| 1 | # /release — Automated Release Flow |
| 2 | |
| 3 | > Ship sharp. Ship clean. Ship now. |
| 4 | |
| 5 | Automates the full release cycle: version bump, changelog generation, git tag, push, and GitHub release creation. No more manual copy-paste release rituals. |
| 6 | |
| 7 | ## Usage |
| 8 | |
| 9 | ``` |
| 10 | /release patch # Bump patch (1.2.3 → 1.2.4), tag, push, release |
| 11 | /release minor # Bump minor (1.2.3 → 1.3.0) |
| 12 | /release major # Bump major (1.2.3 → 2.0.0) |
| 13 | /release patch --alpha # Pre-release (1.2.3 → 1.2.4-alpha.1) |
| 14 | /release patch --dry-run # Show what would happen, don't do it |
| 15 | /release patch --no-push # Tag locally, skip push + GH release |
| 16 | /release status # Show current version + unreleased changes |
| 17 | ``` |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ## Step 0: Preflight |
| 22 | |
| 23 | ### Checks |
| 24 | |
| 25 | ```bash |
| 26 | date "+🕐 %H:%M %Z (%A %d %B %Y)" && BRANCH=$(git branch --show-current) |
| 27 | if [ "$BRANCH" != "main" ]; then |
| 28 | echo "⚠️ On branch '$BRANCH' — releases should be from main" |
| 29 | echo "Continue anyway? [y/N]" |
| 30 | # WAIT for user confirmation |
| 31 | fi |
| 32 | |
| 33 | # Must be clean working tree |
| 34 | if [ -n "$(git status --porcelain | grep -v '^?? ψ/')" ]; then |
| 35 | echo "❌ Uncommitted changes (excluding ψ/ vault files):" |
| 36 | git status --short | grep -v '^?? ψ/' |
| 37 | echo "" |
| 38 | echo "Commit or stash first." |
| 39 | exit 1 |
| 40 | fi |
| 41 | |
| 42 | # Must be up to date with remote |
| 43 | git fetch origin main --quiet 2>/dev/null |
| 44 | LOCAL=$(git rev-parse HEAD) |
| 45 | REMOTE=$(git rev-parse origin/main 2>/dev/null) |
| 46 | if [ "$LOCAL" != "$REMOTE" ]; then |
| 47 | echo "⚠️ Local is not in sync with origin/main" |
| 48 | echo " Local: $LOCAL" |
| 49 | echo " Remote: $REMOTE" |
| 50 | echo "Pull first? [Y/n]" |
| 51 | fi |
| 52 | ``` |
| 53 | |
| 54 | --- |
| 55 | |
| 56 | ## Step 1: Detect Current Version |
| 57 | |
| 58 | ```bash |
| 59 | # Try package.json first |
| 60 | if [ -f package.json ]; then |
| 61 | CURRENT=$(python3 -c "import json; print(json.load(open('package.json'))['version'])") |
| 62 | VERSION_FILE="package.json" |
| 63 | # Try Cargo.toml |
| 64 | elif [ -f Cargo.toml ]; then |
| 65 | CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') |
| 66 | VERSION_FILE="Cargo.toml" |
| 67 | # Try VERSION file |
| 68 | elif [ -f VERSION ]; then |
| 69 | CURRENT=$(cat VERSION) |
| 70 | VERSION_FILE="VERSION" |
| 71 | else |
| 72 | echo "❌ Can't find version. Supported: package.json, Cargo.toml, VERSION" |
| 73 | exit 1 |
| 74 | fi |
| 75 | |
| 76 | echo "📦 Current version: v$CURRENT ($VERSION_FILE)" |
| 77 | ``` |
| 78 | |
| 79 | --- |
| 80 | |
| 81 | ## Step 2: Calculate Next Version |
| 82 | |
| 83 | Parse current version and bump: |
| 84 | |
| 85 | ```bash |
| 86 | IFS='.' read -r MAJOR MINOR PATCH <<< "${CURRENT%-*}" |
| 87 | |
| 88 | case "$BUMP_TYPE" in |
| 89 | patch) PATCH=$((PATCH + 1)) ;; |
| 90 | minor) MINOR=$((MINOR + 1)); PATCH=0 ;; |
| 91 | major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; |
| 92 | esac |
| 93 | |
| 94 | NEXT="$MAJOR.$MINOR.$PATCH" |
| 95 | |
| 96 | # Alpha suffix |
| 97 | if [ "$ALPHA" = true ]; then |
| 98 | # Check existing alpha tags |
| 99 | ALPHA_NUM=$(git tag -l "v${NEXT}-alpha.*" | wc -l) |
| 100 | ALPHA_NUM=$((ALPHA_NUM + 1)) |
| 101 | NEXT="${NEXT}-alpha.${ALPHA_NUM}" |
| 102 | fi |
| 103 | |
| 104 | echo "🚀 Next version: v$NEXT" |
| 105 | ``` |
| 106 | |
| 107 | --- |
| 108 | |
| 109 | ## Step 3: Generate Changelog |
| 110 | |
| 111 | Collect commits since last tag: |
| 112 | |
| 113 | ```bash |
| 114 | LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") |
| 115 | |
| 116 | if [ -n "$LAST_TAG" ]; then |
| 117 | echo "📝 Changes since $LAST_TAG:" |
| 118 | echo "" |
| 119 | git log "$LAST_TAG"..HEAD --oneline --no-merges | while read hash msg; do |
| 120 | # Categorize by conventional commit prefix |
| 121 | case "$msg" in |
| 122 | feat*) echo " ✨ $msg" ;; |
| 123 | fix*) echo " 🐛 $msg" ;; |
| 124 | docs*) echo " 📚 $msg" ;; |
| 125 | soul*) echo " 🧬 $msg" ;; |
| 126 | chore*) echo " 🔧 $msg" ;; |
| 127 | *) echo " · $msg" ;; |
| 128 | esac |
| 129 | done |
| 130 | else |
| 131 | echo "📝 First release — all commits included" |
| 132 | git log --oneline -20 --no-merges |
| 133 | fi |
| 134 | ``` |
| 135 | |
| 136 | --- |
| 137 | |
| 138 | ## Step 4: Confirm |
| 139 | |
| 140 | **ALWAYS wait for user confirmation before proceeding.** |
| 141 | |
| 142 | ``` |
| 143 | 🚀 Release Plan |
| 144 | |
| 145 | Version: v$CURRENT → v$NEXT |
| 146 | Branch: $BRANCH |
| 147 | Changes: N commits since $LAST_TAG |
| 148 | |
| 149 | Actions: |
| 150 | 1. Update version in $VERSION_FILE |
| 151 | 2. Create git tag v$NEXT |
| 152 | 3. Push to origin (main + tag) |
| 153 | 4. Create GitHub release with changelog |
| 154 | |
| 155 | Proceed? [Y/n] |
| 156 | ``` |
| 157 | |
| 158 | If `--dry-run`, show the plan and stop here. |
| 159 | |
| 160 | --- |
| 161 | |
| 162 | ## Step 5: Execute Release |
| 163 | |
| 164 | ### Bump Version |
| 165 | |
| 166 | ```bash |
| 167 | # package.json |
| 168 | if [ "$VERSION_FILE" = "package.json" ]; then |
| 169 | python3 -c " |
| 170 | import json |
| 171 | data = json.load(open('package.json')) |
| 172 | data['version'] = '$NEXT' |
| 173 | json.dump(data, open('package.json', 'w'), indent=2) |
| 174 | print('✅ package.json updated') |
| 175 | " |
| 176 | fi |
| 177 | |
| 178 | # Cargo.toml |
| 179 | if [ "$VERSION_FILE" = "Cargo.toml" ]; then |
| 180 | sed -i "0,/^version = .*/s//version = \"$NEXT\"/" Cargo.toml |
| 181 | echo "✅ Cargo.toml updated" |
| 182 | fi |
| 183 | |
| 184 | # VERSION file |
| 185 | if [ "$VERSION_FILE" = "VERSION" ]; then |
| 186 | echo "$NEXT" > VERSION |
| 187 | echo "✅ VERSION updated" |
| 188 | fi |
| 189 | ``` |
| 190 | |
| 191 | ### Commit & Tag |
| 192 | |
| 193 | ```bash |
| 194 | git add "$VERSION_FILE" |
| 195 | git commit -m "release: v$NEXT |
| 196 | |
| 197 | Co-Authored-By: Oracle <noreply@soulbrews.studio>" |
| 198 | |
| 199 | git tag -a "v$NEXT" -m "v$NEXT |
| 200 | |
| 201 | $(git log "$LAST_T |