native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Use Claude to generate user-facing release notes in release script

onevcat 64d09282 624eb37a

+117 -5
+117 -5
doc-onevcat/scripts/release.sh
··· 121 121 NOTES_FILE="build/release-notes.md" 122 122 mkdir -p build 123 123 PREV_TAG="$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true)" 124 + 125 + generate_llm_notes() { 126 + local range="$1" 127 + local raw_context 128 + raw_context="$(mktemp)" 129 + 130 + # Gather commit messages 131 + { 132 + echo "=== Commits ($range) ===" 133 + git log --pretty=format:'%s' "$range" 134 + echo "" 135 + } > "$raw_context" 136 + 137 + # Gather merged PR details (title + body) 138 + { 139 + echo "" 140 + echo "=== Merged Pull Requests ===" 141 + local pr_numbers 142 + pr_numbers="$(git log --pretty=format:'%s' "$range" | grep -oE '#[0-9]+' | tr -d '#' | sort -u)" 143 + for pr in $pr_numbers; do 144 + local pr_json 145 + pr_json="$(gh pr view "$pr" --repo "$REPO" --json title,body 2>/dev/null || true)" 146 + if [[ -n "$pr_json" ]]; then 147 + echo "--- PR #$pr ---" 148 + echo "$pr_json" | jq -r '"Title: \(.title)\nBody:\n\(.body)"' 149 + echo "" 150 + fi 151 + done 152 + } >> "$raw_context" 153 + 154 + # Gather diff stats 155 + { 156 + echo "" 157 + echo "=== Diff Stats ===" 158 + git diff --stat "$range" 159 + } >> "$raw_context" 160 + 161 + local prompt 162 + prompt="$(cat <<'PROMPT' 163 + You are writing release notes for **Prowl**, a macOS app that runs multiple 164 + coding agents in parallel, each in its own terminal tab. 165 + 166 + Given the raw context below (commits, PR descriptions, diff stats), produce a 167 + concise, user-facing changelog in Markdown. 168 + 169 + ## Rules 170 + 171 + 1. **Audience**: Prowl end-users (developers). They care about what changed in 172 + their day-to-day experience, not internal code structure. 173 + 2. **Include only user-visible changes**: new features, behavior changes, UX 174 + improvements, notable bug fixes. Skip pure refactors, test-only changes, 175 + CI tweaks, dependency bumps, and code-style changes unless they affect 176 + the user. 177 + 3. **Teach naturally**: when a change introduces a new shortcut, workflow, or 178 + setting, briefly explain how to use it (e.g. "Press ⌥⌘↩ to toggle 179 + Canvas view"). 180 + 4. **Tone**: clear, professional, friendly. No marketing fluff, no emoji, no 181 + exclamation marks, no "we're excited". 182 + 5. **Format**: 183 + - Start with a one-line summary sentence of the release theme if there is a 184 + clear one; otherwise jump straight to the list. 185 + - Use a flat bullet list (`-`). Group related items under a single bullet. 186 + - Each bullet should be one or two sentences maximum. 187 + - If a change is a bug fix, start the bullet with "Fixed: …". 188 + - End with nothing — no sign-off, no footer. 189 + 6. **Length**: aim for 3-8 bullets. Merge trivial items. Omit if truly nothing 190 + is user-facing (output a single bullet: "- Internal improvements and 191 + stability fixes."). 192 + 7. **Language**: English only. 193 + 8. Output **only** the Markdown content. No preamble, no code fences. 194 + PROMPT 195 + )" 196 + 197 + local notes 198 + notes="$(claude -p \ 199 + --model sonnet \ 200 + --allowedTools "" \ 201 + --output-format text \ 202 + "$prompt 203 + 204 + --- RAW CONTEXT --- 205 + $(cat "$raw_context") 206 + --- END ---" 2>/dev/null || true)" 207 + rm -f "$raw_context" 208 + 209 + if [[ -n "$notes" ]] && [[ "$(echo "$notes" | wc -l)" -ge 2 ]]; then 210 + echo "$notes" 211 + return 0 212 + fi 213 + return 1 214 + } 215 + 216 + generate_fallback_notes() { 217 + local range="$1" 218 + if [[ -n "$range" ]]; then 219 + gh api "repos/$REPO/releases/generate-notes" \ 220 + -f tag_name="$TAG" -f previous_tag_name="$PREV_TAG" \ 221 + --jq '.body' 2>/dev/null || \ 222 + git log --pretty=format:'- %s' "$range" 223 + else 224 + git log --pretty=format:'- %s' -20 225 + fi 226 + } 227 + 124 228 if [[ -n "$PREV_TAG" ]]; then 125 - gh api "repos/$REPO/releases/generate-notes" \ 126 - -f tag_name="$TAG" -f previous_tag_name="$PREV_TAG" \ 127 - --jq '.body' > "$NOTES_FILE" 2>/dev/null || \ 128 - git log --pretty=format:'- %s' "$PREV_TAG..$TAG" > "$NOTES_FILE" 229 + RANGE="$PREV_TAG..$TAG" 230 + if command -v claude >/dev/null 2>&1; then 231 + log "generating release notes with LLM..." 232 + if generate_llm_notes "$RANGE" > "$NOTES_FILE"; then 233 + log "release notes generated by LLM" 234 + else 235 + log "LLM generation failed, falling back to GitHub auto-notes..." 236 + generate_fallback_notes "$RANGE" > "$NOTES_FILE" 237 + fi 238 + else 239 + generate_fallback_notes "$RANGE" > "$NOTES_FILE" 240 + fi 129 241 else 130 - git log --pretty=format:'- %s' -20 > "$NOTES_FILE" 242 + generate_fallback_notes "" > "$NOTES_FILE" 131 243 fi 132 244 log "release notes written to $NOTES_FILE" 133 245