claude-code-orchestrator-kit 1.4.1 → 1.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/.claude/agents/business/workers/lead-research-assistant.md +199 -0
  2. package/.claude/agents/database/workers/api-builder.md +8 -0
  3. package/.claude/agents/database/workers/database-architect.md +11 -3
  4. package/.claude/agents/database/workers/supabase-auditor.md +7 -7
  5. package/.claude/agents/database/workers/supabase-fixer.md +825 -0
  6. package/.claude/agents/database/workers/supabase-realtime-optimizer.md +1086 -0
  7. package/.claude/agents/database/workers/supabase-storage-optimizer.md +1187 -0
  8. package/.claude/agents/development/workers/code-reviewer.md +17 -2
  9. package/.claude/agents/development/workers/code-structure-refactorer.md +771 -0
  10. package/.claude/agents/development/workers/judge-specialist.md +3275 -0
  11. package/.claude/agents/development/workers/langgraph-specialist.md +1343 -0
  12. package/.claude/agents/development/workers/stage-pipeline-specialist.md +1173 -0
  13. package/.claude/agents/frontend/workers/fullstack-nextjs-specialist.md +10 -0
  14. package/.claude/agents/frontend/workers/nextjs-ui-designer.md +30 -0
  15. package/.claude/agents/health/workers/bug-fixer.md +31 -3
  16. package/.claude/agents/health/workers/bug-hunter.md +0 -1
  17. package/.claude/agents/health/workers/dead-code-hunter.md +167 -75
  18. package/.claude/agents/health/workers/dead-code-remover.md +217 -66
  19. package/.claude/agents/health/workers/dependency-auditor.md +83 -24
  20. package/.claude/agents/health/workers/dependency-updater.md +0 -1
  21. package/.claude/agents/health/workers/security-scanner.md +0 -1
  22. package/.claude/agents/infrastructure/workers/bullmq-worker-specialist.md +748 -0
  23. package/.claude/agents/infrastructure/workers/deployment-engineer.md +446 -0
  24. package/.claude/agents/infrastructure/workers/infrastructure-specialist.md +2 -2
  25. package/.claude/agents/infrastructure/workers/rag-specialist.md +799 -0
  26. package/.claude/agents/infrastructure/workers/server-hardening-specialist.md +1128 -0
  27. package/.claude/agents/integrations/workers/lms-integration-specialist.md +866 -0
  28. package/.claude/agents/meta/workers/meta-agent-v3.md +22 -0
  29. package/.claude/agents/testing/workers/integration-tester.md +1 -1
  30. package/.claude/agents/testing/workers/test-writer.md +16 -0
  31. package/.claude/commands/health-bugs.md +14 -281
  32. package/.claude/commands/health-cleanup.md +14 -281
  33. package/.claude/commands/health-deps.md +14 -281
  34. package/.claude/commands/health-metrics.md +51 -709
  35. package/.claude/commands/health-reuse.md +14 -311
  36. package/.claude/commands/health-security.md +14 -281
  37. package/.claude/commands/push.md +17 -3
  38. package/.claude/commands/speckit.implement.md +0 -11
  39. package/.claude/commands/supabase-performance-optimizer.md +73 -0
  40. package/.claude/commands/ultra-think.md +158 -0
  41. package/.claude/commands/worktree.md +150 -0
  42. package/.claude/scripts/gates/check-bundle-size.sh +0 -0
  43. package/.claude/scripts/gates/check-coverage.sh +0 -0
  44. package/.claude/scripts/gates/check-security.sh +0 -0
  45. package/.claude/scripts/release.sh +469 -94
  46. package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
  47. package/.claude/skills/algorithmic-art/SKILL.md +405 -0
  48. package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
  49. package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
  50. package/.claude/skills/artifacts-builder/LICENSE.txt +202 -0
  51. package/.claude/skills/artifacts-builder/SKILL.md +74 -0
  52. package/.claude/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
  53. package/.claude/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
  54. package/.claude/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  55. package/.claude/skills/bug-health-inline/SKILL.md +221 -0
  56. package/.claude/skills/bug-health-inline/references/worker-prompts.md +182 -0
  57. package/.claude/skills/canvas-design/LICENSE.txt +202 -0
  58. package/.claude/skills/canvas-design/SKILL.md +130 -0
  59. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  60. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  61. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  62. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  63. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  64. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  65. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  66. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  67. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  68. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  69. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  70. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  71. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  72. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  73. package/.claude/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  74. package/.claude/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  75. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  76. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  77. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  78. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  79. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  80. package/.claude/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  81. package/.claude/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  82. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  83. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  84. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  85. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  86. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  87. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  88. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  89. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  90. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  91. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  92. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  93. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  94. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  95. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  96. package/.claude/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  97. package/.claude/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  98. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  99. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  100. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  101. package/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  102. package/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  103. package/.claude/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  104. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  105. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  106. package/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  107. package/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  108. package/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  109. package/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  110. package/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  111. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  112. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  113. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  114. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  115. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  116. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  117. package/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  118. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  119. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  120. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  121. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  122. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  123. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  124. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  125. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  126. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  127. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  128. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  129. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  130. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  131. package/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  132. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  133. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  134. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  135. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  136. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  137. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  138. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  139. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  140. package/.claude/skills/changelog-generator/SKILL.md +104 -0
  141. package/.claude/skills/cleanup-health-inline/SKILL.md +224 -0
  142. package/.claude/skills/code-reviewer/SKILL.md +209 -0
  143. package/.claude/skills/code-reviewer/references/code_review_checklist.md +103 -0
  144. package/.claude/skills/code-reviewer/references/coding_standards.md +103 -0
  145. package/.claude/skills/code-reviewer/references/common_antipatterns.md +103 -0
  146. package/.claude/skills/code-reviewer/scripts/code_quality_checker.py +114 -0
  147. package/.claude/skills/code-reviewer/scripts/pr_analyzer.py +114 -0
  148. package/.claude/skills/code-reviewer/scripts/review_report_generator.py +114 -0
  149. package/.claude/skills/content-research-writer/SKILL.md +538 -0
  150. package/.claude/skills/deps-health-inline/SKILL.md +227 -0
  151. package/.claude/skills/frontend-aesthetics/SKILL.md +51 -396
  152. package/.claude/skills/git-commit-helper/SKILL.md +203 -0
  153. package/.claude/skills/lead-research-assistant/SKILL.md +199 -0
  154. package/.claude/skills/reuse-health-inline/SKILL.md +248 -0
  155. package/.claude/skills/rollback-changes/SKILL.md +50 -524
  156. package/.claude/skills/run-quality-gate/SKILL.md +36 -346
  157. package/.claude/skills/security-health-inline/SKILL.md +224 -0
  158. package/.claude/skills/senior-architect/SKILL.md +209 -0
  159. package/.claude/skills/senior-architect/references/architecture_patterns.md +755 -0
  160. package/.claude/skills/senior-architect/references/system_design_workflows.md +749 -0
  161. package/.claude/skills/senior-architect/references/tech_decision_guide.md +612 -0
  162. package/.claude/skills/senior-architect/scripts/architecture_diagram_generator.py +114 -0
  163. package/.claude/skills/senior-architect/scripts/dependency_analyzer.py +114 -0
  164. package/.claude/skills/senior-architect/scripts/project_architect.py +114 -0
  165. package/.claude/skills/senior-devops/SKILL.md +209 -0
  166. package/.claude/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
  167. package/.claude/skills/senior-devops/references/deployment_strategies.md +103 -0
  168. package/.claude/skills/senior-devops/references/infrastructure_as_code.md +103 -0
  169. package/.claude/skills/senior-devops/scripts/deployment_manager.py +114 -0
  170. package/.claude/skills/senior-devops/scripts/pipeline_generator.py +114 -0
  171. package/.claude/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
  172. package/.claude/skills/senior-prompt-engineer/SKILL.md +226 -0
  173. package/.claude/skills/senior-prompt-engineer/references/agentic_system_design.md +80 -0
  174. package/.claude/skills/senior-prompt-engineer/references/llm_evaluation_frameworks.md +80 -0
  175. package/.claude/skills/senior-prompt-engineer/references/prompt_engineering_patterns.md +80 -0
  176. package/.claude/skills/senior-prompt-engineer/scripts/agent_orchestrator.py +100 -0
  177. package/.claude/skills/senior-prompt-engineer/scripts/prompt_optimizer.py +100 -0
  178. package/.claude/skills/senior-prompt-engineer/scripts/rag_evaluator.py +100 -0
  179. package/.claude/skills/setup-knip/SKILL.md +372 -0
  180. package/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
  181. package/.claude/skills/systematic-debugging/SKILL.md +296 -0
  182. package/.claude/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  183. package/.claude/skills/systematic-debugging/condition-based-waiting.md +115 -0
  184. package/.claude/skills/systematic-debugging/defense-in-depth.md +122 -0
  185. package/.claude/skills/systematic-debugging/find-polluter.sh +63 -0
  186. package/.claude/skills/systematic-debugging/root-cause-tracing.md +169 -0
  187. package/.claude/skills/systematic-debugging/test-academic.md +14 -0
  188. package/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
  189. package/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
  190. package/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
  191. package/.claude/skills/theme-factory/LICENSE.txt +202 -0
  192. package/.claude/skills/theme-factory/SKILL.md +59 -0
  193. package/.claude/skills/theme-factory/theme-showcase.pdf +0 -0
  194. package/.claude/skills/theme-factory/themes/arctic-frost.md +19 -0
  195. package/.claude/skills/theme-factory/themes/botanical-garden.md +19 -0
  196. package/.claude/skills/theme-factory/themes/desert-rose.md +19 -0
  197. package/.claude/skills/theme-factory/themes/forest-canopy.md +19 -0
  198. package/.claude/skills/theme-factory/themes/golden-hour.md +19 -0
  199. package/.claude/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  200. package/.claude/skills/theme-factory/themes/modern-minimalist.md +19 -0
  201. package/.claude/skills/theme-factory/themes/ocean-depths.md +19 -0
  202. package/.claude/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  203. package/.claude/skills/theme-factory/themes/tech-innovation.md +19 -0
  204. package/.claude/skills/ui-design-system/SKILL.md +32 -0
  205. package/.claude/skills/ui-design-system/scripts/design_token_generator.py +529 -0
  206. package/.claude/skills/ux-researcher-designer/SKILL.md +30 -0
  207. package/.claude/skills/ux-researcher-designer/scripts/persona_generator.py +508 -0
  208. package/.claude/skills/webapp-testing/LICENSE.txt +202 -0
  209. package/.claude/skills/webapp-testing/SKILL.md +96 -0
  210. package/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
  211. package/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  212. package/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  213. package/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
  214. package/.gitignore +4 -0
  215. package/README.md +492 -1093
  216. package/README.ru.md +719 -0
  217. package/docs/Agents Ecosystem/AGENT-ORCHESTRATION.md +2 -2
  218. package/docs/COMMANDS-GUIDE.md +0 -15
  219. package/docs/reports/skills/new-skills-analysis-2025-12.md +331 -0
  220. package/package.json +11 -3
  221. package/.claude/agents/health/orchestrators/bug-orchestrator.md +0 -1084
  222. package/.claude/agents/health/orchestrators/dead-code-orchestrator.md +0 -1064
  223. package/.claude/agents/health/orchestrators/dependency-orchestrator.md +0 -1064
  224. package/.claude/agents/health/orchestrators/reuse-orchestrator.md +0 -1112
  225. package/.claude/agents/health/orchestrators/security-orchestrator.md +0 -1064
  226. package/.claude/commands/worktree-cleanup.md +0 -382
  227. package/.claude/commands/worktree-create.md +0 -287
  228. package/.claude/commands/worktree-list.md +0 -239
  229. package/.claude/commands/worktree-remove.md +0 -339
  230. package/.claude/project-index.md +0 -75
  231. package/.claude/skills/load-project-context/SKILL.md +0 -89
  232. package/.claude/skills/resume-session/SKILL.md +0 -164
  233. package/.claude/skills/save-session-context/SKILL.md +0 -123
  234. package/.claude/templates/project-index.template.md +0 -67
  235. package/.claude/templates/session/context.template.md +0 -40
  236. package/.claude/templates/session/log.template.md +0 -72
  237. package/.github/BRANCH_PROTECTION.md +0 -137
  238. package/.github/workflows/build.yml +0 -70
  239. package/.github/workflows/deploy-staging.yml +0 -90
  240. package/.github/workflows/test.yml +0 -104
@@ -11,9 +11,10 @@
11
11
  # - Safe rollback with file backups (no data loss on errors)
12
12
  # - Rollback support for failed releases
13
13
  #
14
- # Usage: ./release.sh [patch|minor|major] [--yes]
14
+ # Usage: ./release.sh [patch|minor|major] [--yes] [--message "commit message"]
15
15
  # Leave empty for auto-detection from conventional commits
16
16
  # --yes: Skip confirmation prompt (for automation)
17
+ # --message, -m: Custom commit message for auto-committing uncommitted changes
17
18
  #
18
19
  # Supported conventional commit types:
19
20
  # security: → Security section (patch version)
@@ -42,6 +43,7 @@ readonly NC='\033[0m' # No Color
42
43
  # State tracking for rollback
43
44
  CREATED_COMMIT=""
44
45
  CREATED_TAG=""
46
+ CUSTOM_COMMIT_MSG="" # Custom message for auto-commit (set via --message flag)
45
47
  declare -a MODIFIED_FILES=()
46
48
  declare -a BACKUP_FILES=() # Track backup files for safe rollback
47
49
 
@@ -57,6 +59,38 @@ declare -a DEPRECATIONS=() # Deprecated features
57
59
  declare -a REMOVALS=() # Removed features
58
60
  declare -a OTHER_CHANGES=()
59
61
 
62
+ # === SIGPIPE-SAFE UTILITIES ===
63
+ # These functions replace head to avoid SIGPIPE errors with pipefail in bash 3.2+
64
+ # When head closes the pipe early, the writing process receives SIGPIPE (exit 141)
65
+ # awk reads only needed lines and exits cleanly without triggering SIGPIPE
66
+
67
+ # Safe replacement for head -n N
68
+ # Usage: command | safe_head 5
69
+ safe_head() {
70
+ local n="${1:-1}"
71
+ awk -v n="$n" 'NR <= n {print} NR > n {exit}'
72
+ }
73
+
74
+ # Optimized version for getting first line only
75
+ # Usage: command | safe_first
76
+ safe_first() {
77
+ awk 'NR==1 {print; exit}'
78
+ }
79
+
80
+ # Get commits range handling first release edge case
81
+ # Usage: get_commits_range "$LAST_TAG"
82
+ get_commits_range() {
83
+ local last_tag="$1"
84
+
85
+ if [ -z "$last_tag" ]; then
86
+ # First release - use special marker to include all commits
87
+ # We can't use ${first_commit}^..HEAD because the first commit has no parent
88
+ echo "__ALL_COMMITS__"
89
+ else
90
+ echo "${last_tag}..HEAD"
91
+ fi
92
+ }
93
+
60
94
  # === UTILITY FUNCTIONS ===
61
95
 
62
96
  log_info() {
@@ -163,6 +197,48 @@ trap cleanup EXIT
163
197
 
164
198
  # === PRE-FLIGHT CHECKS ===
165
199
 
200
+ # Check if remote is ahead of local to prevent push conflicts
201
+ check_remote_status() {
202
+ local branch="$1"
203
+ local skip_check="${RELEASE_SKIP_REMOTE_CHECK:-false}"
204
+
205
+ if [ "$skip_check" = "true" ]; then
206
+ log_warning "Skipping remote status check (RELEASE_SKIP_REMOTE_CHECK=true)"
207
+ return 0
208
+ fi
209
+
210
+ log_info "Checking remote status..."
211
+
212
+ # Fetch latest from remote (without merging)
213
+ if ! git fetch origin "$branch" --quiet 2>/dev/null; then
214
+ log_warning "Could not fetch from remote (offline mode or no upstream)"
215
+ return 0
216
+ fi
217
+
218
+ # Check if remote branch exists
219
+ if ! git rev-parse "origin/$branch" >/dev/null 2>&1; then
220
+ log_info "Remote branch origin/$branch does not exist yet (new branch)"
221
+ return 0
222
+ fi
223
+
224
+ # Check if remote is ahead
225
+ local behind
226
+ behind=$(git rev-list --count "HEAD..origin/$branch" 2>/dev/null || echo "0")
227
+
228
+ if [ "$behind" -gt 0 ]; then
229
+ log_error "Remote is $behind commit(s) ahead of local"
230
+ echo ""
231
+ log_info "Please pull changes first:"
232
+ echo " git pull origin $branch"
233
+ echo ""
234
+ log_info "Or skip this check with:"
235
+ echo " RELEASE_SKIP_REMOTE_CHECK=true ./release.sh"
236
+ exit 1
237
+ fi
238
+
239
+ log_success "Local branch is up to date with remote"
240
+ }
241
+
166
242
  run_preflight_checks() {
167
243
  log_info "Running pre-flight checks..."
168
244
  echo ""
@@ -199,15 +275,11 @@ run_preflight_checks() {
199
275
  # Get detailed file list for commit body
200
276
  FILE_LIST=$(git diff --cached --name-status | sed 's/^/ /')
201
277
 
202
- # Detect commit type based on changed files
203
- local commit_type="chore"
204
- local commit_scope=""
205
- local commit_desc="update project files"
206
-
207
278
  # Get file changes with status (A=added, M=modified, D=deleted)
208
279
  local file_status=$(git diff --cached --name-status)
209
280
 
210
- # Count different types of changes
281
+ # Count ALL types of changes (added, modified, deleted)
282
+ # Claude/project tooling
211
283
  local new_agents=$(echo "$file_status" | grep "^A.*\.claude/agents/.*\.md$" | wc -l)
212
284
  local new_skills=$(echo "$file_status" | grep "^A.*\.claude/skills/.*/SKILL\.md$" | wc -l)
213
285
  local new_commands=$(echo "$file_status" | grep "^A.*\.claude/commands/.*\.md$" | wc -l)
@@ -217,90 +289,124 @@ run_preflight_checks() {
217
289
  local modified_commands=$(echo "$file_status" | grep "^M.*\.claude/commands/.*\.md$" | wc -l)
218
290
  local modified_docs=$(echo "$file_status" | grep "\.md$" | grep -v "\.claude/" | wc -l)
219
291
  local modified_mcp=$(echo "$file_status" | grep "mcp/.*\.json$" | wc -l)
292
+ local deleted_skills=$(echo "$file_status" | grep "^D.*\.claude/skills/.*/SKILL\.md$" | wc -l)
293
+ local deleted_templates=$(echo "$file_status" | grep "^D.*\.claude/templates/.*\.md$" | wc -l)
294
+ local deleted_other=$(echo "$file_status" | grep "^D" | grep -v "\.claude/skills/" | grep -v "\.claude/templates/" | wc -l)
295
+
296
+ # Source code changes (TypeScript, JavaScript, Python, etc.)
297
+ local new_source=$(echo "$file_status" | grep "^A" | grep -E "\.(ts|tsx|js|jsx|py|go|rs)$" | grep -v "\.test\." | grep -v "\.spec\." | wc -l)
298
+ local modified_source=$(echo "$file_status" | grep "^M" | grep -E "\.(ts|tsx|js|jsx|py|go|rs)$" | grep -v "\.test\." | grep -v "\.spec\." | wc -l)
299
+ local new_tests=$(echo "$file_status" | grep "^A" | grep -E "\.(test|spec)\.(ts|tsx|js|jsx)$" | wc -l)
300
+ local modified_tests=$(echo "$file_status" | grep "^M" | grep -E "\.(test|spec)\.(ts|tsx|js|jsx)$" | wc -l)
301
+
302
+ # Try to detect scope from file paths (packages/xxx/, src/xxx/, lib/xxx/, app/xxx/)
303
+ local detected_scope=""
304
+ local scope_candidates=$(echo "$file_status" | grep -E "^[AM]" | grep -E "\.(ts|tsx|js|jsx)$" | \
305
+ sed -E 's/^[AM]\s+//' | \
306
+ sed -E 's|^packages/([^/]+)/.*|\1|; s|^src/([^/]+)/.*|\1|; s|^lib/([^/]+)/.*|\1|; s|^app/([^/]+)/.*|\1|' | \
307
+ sort | uniq -c | sort -rn | head -1 | awk '{print $2}')
308
+ if [ -n "$scope_candidates" ] && [ "$scope_candidates" != "." ]; then
309
+ detected_scope="$scope_candidates"
310
+ fi
220
311
 
221
- # Priority-based commit type detection (most specific first)
312
+ # Build change summary array
313
+ local changes=()
314
+
315
+ # Source code features (new files = new functionality)
316
+ [ "$new_source" -gt 0 ] && changes+=("add ${new_source} source file(s)")
317
+ [ "$modified_source" -gt 0 ] && changes+=("update ${modified_source} source file(s)")
318
+ [ "$new_tests" -gt 0 ] && changes+=("add ${new_tests} test(s)")
319
+ [ "$modified_tests" -gt 0 ] && changes+=("update ${modified_tests} test(s)")
320
+
321
+ # Claude tooling
322
+ [ "$new_agents" -gt 0 ] && changes+=("add ${new_agents} agent(s)")
323
+ [ "$new_skills" -gt 0 ] && changes+=("add ${new_skills} skill(s)")
324
+ [ "$new_commands" -gt 0 ] && changes+=("add ${new_commands} command(s)")
325
+
326
+ # Updates
327
+ [ "$modified_scripts" -gt 0 ] && changes+=("update scripts")
328
+ [ "$modified_agents" -gt 0 ] && changes+=("update ${modified_agents} agent(s)")
329
+ [ "$modified_skills" -gt 0 ] && changes+=("update ${modified_skills} skill(s)")
330
+ [ "$modified_commands" -gt 0 ] && changes+=("update ${modified_commands} command(s)")
331
+ [ "$modified_mcp" -gt 0 ] && changes+=("update MCP configs")
332
+ [ "$modified_docs" -gt 0 ] && changes+=("update docs")
333
+
334
+ # Deletions
335
+ [ "$deleted_skills" -gt 0 ] && changes+=("remove ${deleted_skills} skill(s)")
336
+ [ "$deleted_templates" -gt 0 ] && changes+=("remove templates")
337
+ [ "$deleted_other" -gt 0 ] && changes+=("cleanup ${deleted_other} file(s)")
338
+
339
+ # Determine commit type based on what changed (prioritize source code)
340
+ local commit_type="chore"
341
+ local has_feat=false
222
342
 
223
- # 1. New agents (highest priority for features)
224
- if [ "$new_agents" -gt 0 ]; then
343
+ # New source files = feature
344
+ if [ "$new_source" -gt 0 ]; then
225
345
  commit_type="feat"
226
- commit_scope="agents"
227
- local agent_file=$(echo "$file_status" | grep "^A.*\.claude/agents/.*\.md$" | head -1 | awk '{print $2}')
228
- local agent_name=$(basename "$agent_file" .md)
229
- if [ "$new_agents" -eq 1 ]; then
230
- commit_desc="add ${agent_name} agent"
231
- else
232
- commit_desc="add ${new_agents} new agents (${agent_name}, ...)"
233
- fi
234
-
235
- # 2. New skills
236
- elif [ "$new_skills" -gt 0 ]; then
346
+ has_feat=true
347
+ # Modified source files = fix (improvements/bug fixes)
348
+ elif [ "$modified_source" -gt 0 ]; then
349
+ commit_type="fix"
350
+ # New agents/skills/commands = feature
351
+ elif [ "$new_agents" -gt 0 ] || [ "$new_skills" -gt 0 ] || [ "$new_commands" -gt 0 ]; then
237
352
  commit_type="feat"
238
- commit_scope="skills"
239
- local skill_file=$(echo "$file_status" | grep "^A.*\.claude/skills/.*/SKILL\.md$" | head -1 | awk '{print $2}')
240
- local skill_name=$(echo "$skill_file" | cut -d'/' -f4)
241
- if [ "$new_skills" -eq 1 ]; then
242
- commit_desc="add ${skill_name} skill"
243
- else
244
- commit_desc="add ${new_skills} new skills (${skill_name}, ...)"
245
- fi
353
+ has_feat=true
354
+ # New tests only = test
355
+ elif [ "$new_tests" -gt 0 ] || [ "$modified_tests" -gt 0 ]; then
356
+ commit_type="test"
357
+ # Only scripts modified = chore
358
+ elif [ "$modified_scripts" -gt 0 ] && [ "$modified_scripts" -eq "$TOTAL_COUNT" ]; then
359
+ commit_type="chore"
360
+ # Only docs modified = docs
361
+ elif [ "$modified_docs" -gt 0 ] && [ "$modified_docs" -eq "$TOTAL_COUNT" ]; then
362
+ commit_type="docs"
363
+ fi
246
364
 
247
- # 3. New commands
248
- elif [ "$new_commands" -gt 0 ]; then
249
- commit_type="feat"
250
- commit_scope="commands"
251
- local cmd_file=$(echo "$file_status" | grep "^A.*\.claude/commands/.*\.md$" | head -1 | awk '{print $2}')
252
- local cmd_name=$(basename "$cmd_file" .md)
253
- if [ "$new_commands" -eq 1 ]; then
254
- commit_desc="add ${cmd_name} command"
255
- else
256
- commit_desc="add ${new_commands} new commands"
257
- fi
365
+ # Build commit message summary
366
+ local commit_desc=""
367
+ local change_count=${#changes[@]}
258
368
 
259
- # 4. Modified skills (features)
260
- elif [ "$modified_skills" -gt 0 ]; then
261
- commit_type="feat"
262
- commit_scope="skills"
263
- commit_desc="update skill implementations"
369
+ if [ "$change_count" -eq 0 ]; then
370
+ commit_desc="update project files"
371
+ elif [ "$change_count" -eq 1 ]; then
372
+ commit_desc="${changes[0]}"
373
+ elif [ "$change_count" -eq 2 ]; then
374
+ commit_desc="${changes[0]}, ${changes[1]}"
375
+ else
376
+ # Multiple changes - create summary
377
+ commit_desc="${changes[0]}, ${changes[1]}, +$((change_count - 2)) more"
378
+ fi
264
379
 
265
- # 5. Modified commands (features)
266
- elif [ "$modified_commands" -gt 0 ]; then
267
- commit_type="feat"
268
- commit_scope="commands"
269
- commit_desc="update slash commands"
380
+ # Build detailed body with all changes
381
+ local changes_body=""
382
+ for change in "${changes[@]}"; do
383
+ changes_body="${changes_body}- ${change}\n"
384
+ done
270
385
 
271
- # 6. Modified scripts (chore)
272
- elif [ "$modified_scripts" -gt 0 ]; then
273
- commit_type="chore"
274
- commit_scope="scripts"
275
- commit_desc="update automation scripts"
386
+ # Build commit prefix with optional scope
387
+ local commit_prefix="${commit_type}"
388
+ if [ -n "$detected_scope" ]; then
389
+ commit_prefix="${commit_type}(${detected_scope})"
390
+ fi
276
391
 
277
- # 7. Modified agents (chore)
278
- elif [ "$modified_agents" -gt 0 ]; then
279
- commit_type="chore"
280
- commit_scope="agents"
281
- commit_desc="update agent configurations"
392
+ # Use custom message if provided, otherwise auto-generate
393
+ if [ -n "${CUSTOM_COMMIT_MSG:-}" ]; then
394
+ COMMIT_MSG="${CUSTOM_COMMIT_MSG}
282
395
 
283
- # 8. Modified MCP configs (chore)
284
- elif [ "$modified_mcp" -gt 0 ]; then
285
- commit_type="chore"
286
- commit_scope="mcp"
287
- commit_desc="update MCP server configurations"
396
+ Auto-committed ${TOTAL_COUNT} file(s) before creating release.
288
397
 
289
- # 9. Documentation changes
290
- elif [ "$modified_docs" -gt 0 ]; then
291
- commit_type="docs"
292
- commit_desc="update documentation"
293
- fi
398
+ Files changed:
399
+ ${FILE_LIST}
294
400
 
295
- # Generate commit message with detected type
296
- if [ -n "$commit_scope" ]; then
297
- COMMIT_MSG="${commit_type}(${commit_scope}): ${commit_desc}"
298
- else
299
- COMMIT_MSG="${commit_type}: ${commit_desc}"
300
- fi
401
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
301
402
 
302
- COMMIT_MSG="${COMMIT_MSG}
403
+ Co-Authored-By: Claude <noreply@anthropic.com>"
404
+ log_info "Using custom commit message: ${CUSTOM_COMMIT_MSG}"
405
+ else
406
+ COMMIT_MSG="${commit_prefix}: ${commit_desc}
303
407
 
408
+ Changes in this commit:
409
+ $(echo -e "$changes_body")
304
410
  Auto-committed ${TOTAL_COUNT} file(s) before creating release.
305
411
 
306
412
  Files changed:
@@ -309,6 +415,7 @@ ${FILE_LIST}
309
415
  🤖 Generated with [Claude Code](https://claude.com/claude-code)
310
416
 
311
417
  Co-Authored-By: Claude <noreply@anthropic.com>"
418
+ fi
312
419
 
313
420
  # Create commit
314
421
  git commit -m "$COMMIT_MSG" >/dev/null 2>&1 || {
@@ -317,7 +424,7 @@ Co-Authored-By: Claude <noreply@anthropic.com>"
317
424
  }
318
425
 
319
426
  log_success "Changes committed (${TOTAL_COUNT} files)"
320
- log_info "Commit type: ${commit_type}${commit_scope:+(${commit_scope})}: ${commit_desc}"
427
+ log_info "Commit: ${commit_prefix}: ${commit_desc}"
321
428
  fi
322
429
 
323
430
  # Check if remote is configured
@@ -327,6 +434,9 @@ Co-Authored-By: Claude <noreply@anthropic.com>"
327
434
  fi
328
435
  log_success "Remote configured"
329
436
 
437
+ # Check if remote is ahead of local
438
+ check_remote_status "$BRANCH"
439
+
330
440
  # Check for Node.js
331
441
  if ! command -v node &> /dev/null; then
332
442
  log_error "Node.js is not installed"
@@ -343,14 +453,15 @@ Co-Authored-By: Claude <noreply@anthropic.com>"
343
453
  log_success "Current version: $CURRENT_VERSION"
344
454
 
345
455
  # Get last git tag (across all branches using --all)
346
- LAST_TAG=$(git tag --sort=-version:refname | head -n 1 || echo "")
456
+ # Using safe_first instead of head -n 1 to avoid SIGPIPE with pipefail
457
+ LAST_TAG=$(git tag --sort=-version:refname | safe_first || echo "")
347
458
  if [ -z "$LAST_TAG" ]; then
348
459
  log_warning "No previous git tags found (first release)"
349
- LAST_TAG="HEAD~999999" # Get all commits
350
- COMMITS_RANGE="HEAD"
460
+ log_info "Will include all commits from repository start"
461
+ COMMITS_RANGE=$(get_commits_range "")
351
462
  else
352
463
  log_success "Last tag: $LAST_TAG"
353
- COMMITS_RANGE="${LAST_TAG}..HEAD"
464
+ COMMITS_RANGE=$(get_commits_range "$LAST_TAG")
354
465
 
355
466
  # Sync package.json version with git tag if needed
356
467
  TAG_VERSION="${LAST_TAG#v}" # Remove 'v' prefix
@@ -372,7 +483,12 @@ Co-Authored-By: Claude <noreply@anthropic.com>"
372
483
  fi
373
484
 
374
485
  # Check for commits since last tag
375
- COMMITS_COUNT=$(git rev-list $COMMITS_RANGE --count 2>/dev/null || echo "0")
486
+ if [ "$COMMITS_RANGE" = "__ALL_COMMITS__" ]; then
487
+ # First release - count all commits
488
+ COMMITS_COUNT=$(git rev-list HEAD --count 2>/dev/null || echo "0")
489
+ else
490
+ COMMITS_COUNT=$(git rev-list $COMMITS_RANGE --count 2>/dev/null || echo "0")
491
+ fi
376
492
  if [ "$COMMITS_COUNT" -eq 0 ]; then
377
493
  log_error "No commits since last release ($LAST_TAG)"
378
494
  echo "Nothing to release!"
@@ -394,7 +510,13 @@ parse_commits() {
394
510
  if [ -n "$line" ]; then
395
511
  ALL_COMMITS+=("$line")
396
512
  fi
397
- done < <(git log --format="%h %s" $COMMITS_RANGE)
513
+ done < <(
514
+ if [ "$COMMITS_RANGE" = "__ALL_COMMITS__" ]; then
515
+ git log --format="%h %s" HEAD
516
+ else
517
+ git log --format="%h %s" $COMMITS_RANGE
518
+ fi
519
+ )
398
520
 
399
521
  # Parse and categorize each commit
400
522
  # Define regex patterns as variables for proper bash regex matching
@@ -592,6 +714,15 @@ EOF
592
714
  done
593
715
  echo ""
594
716
  fi
717
+
718
+ # Other section (chore, docs, ci, build, test, style, etc.)
719
+ if [ ${#OTHER_CHANGES[@]} -gt 0 ]; then
720
+ echo "### Other"
721
+ for commit in "${OTHER_CHANGES[@]}"; do
722
+ format_changelog_line "$commit"
723
+ done
724
+ echo ""
725
+ fi
595
726
  }
596
727
 
597
728
  format_changelog_line() {
@@ -618,6 +749,141 @@ format_changelog_line() {
618
749
  fi
619
750
  }
620
751
 
752
+ # === USER-FACING RELEASE NOTES ===
753
+
754
+ # Transform technical scope to user-friendly name
755
+ get_friendly_scope_name() {
756
+ local scope="$1"
757
+
758
+ case "$scope" in
759
+ auth|authentication) echo "Authentication" ;;
760
+ api) echo "API" ;;
761
+ ui|frontend) echo "Interface" ;;
762
+ db|database) echo "Database" ;;
763
+ perf|performance) echo "Performance" ;;
764
+ security|sec) echo "Security" ;;
765
+ agents) echo "AI Agents" ;;
766
+ skills) echo "Skills" ;;
767
+ commands) echo "Commands" ;;
768
+ mcp) echo "MCP Servers" ;;
769
+ docs) echo "Documentation" ;;
770
+ ci|cd) echo "CI/CD" ;;
771
+ *) echo "$scope" ;;
772
+ esac
773
+ }
774
+
775
+ # Format a commit message for user-facing notes (no hash, friendly language)
776
+ format_user_facing_line() {
777
+ local commit="$1"
778
+ local message=$(echo "$commit" | cut -d' ' -f2-)
779
+
780
+ # Extract scope and message: "type(scope): message" -> friendly format
781
+ local scope_pattern='^[a-z]+(\(([^)]+)\))?!?:[ ]+(.+)$'
782
+ if [[ "$message" =~ $scope_pattern ]]; then
783
+ local scope="${BASH_REMATCH[2]}"
784
+ local msg="${BASH_REMATCH[3]}"
785
+
786
+ # Capitalize first letter of message
787
+ msg="$(echo "${msg:0:1}" | tr '[:lower:]' '[:upper:]')${msg:1}"
788
+
789
+ if [ -n "$scope" ]; then
790
+ local friendly_scope=$(get_friendly_scope_name "$scope")
791
+ echo "- **${friendly_scope}**: ${msg}"
792
+ else
793
+ echo "- ${msg}"
794
+ fi
795
+ else
796
+ # Not a conventional commit, capitalize and use as-is
797
+ local capitalized="$(echo "${message:0:1}" | tr '[:lower:]' '[:upper:]')${message:1}"
798
+ echo "- ${capitalized}"
799
+ fi
800
+ }
801
+
802
+ # Generate user-facing release notes (marketing format)
803
+ generate_user_facing_notes_entry() {
804
+ local version="$1"
805
+ local date="$2"
806
+
807
+ cat << EOF
808
+ ## v${version}
809
+
810
+ _Released on ${date}_
811
+
812
+ EOF
813
+
814
+ # New Features (from feat commits)
815
+ if [ ${#FEATURES[@]} -gt 0 ]; then
816
+ echo "### ✨ New Features"
817
+ echo ""
818
+ for commit in "${FEATURES[@]}"; do
819
+ format_user_facing_line "$commit"
820
+ done
821
+ echo ""
822
+ fi
823
+
824
+ # Improvements (from refactor + perf)
825
+ if [ ${#REFACTORS[@]} -gt 0 ] || [ ${#PERF[@]} -gt 0 ]; then
826
+ echo "### 🔧 Improvements"
827
+ echo ""
828
+ for commit in "${PERF[@]}"; do
829
+ format_user_facing_line "$commit"
830
+ done
831
+ for commit in "${REFACTORS[@]}"; do
832
+ format_user_facing_line "$commit"
833
+ done
834
+ echo ""
835
+ fi
836
+
837
+ # Security (from security commits)
838
+ if [ ${#SECURITY_FIXES[@]} -gt 0 ]; then
839
+ echo "### 🔒 Security"
840
+ echo ""
841
+ for commit in "${SECURITY_FIXES[@]}"; do
842
+ format_user_facing_line "$commit"
843
+ done
844
+ echo ""
845
+ fi
846
+
847
+ # Bug Fixes
848
+ if [ ${#FIXES[@]} -gt 0 ]; then
849
+ echo "### 🐛 Bug Fixes"
850
+ echo ""
851
+ for commit in "${FIXES[@]}"; do
852
+ format_user_facing_line "$commit"
853
+ done
854
+ echo ""
855
+ fi
856
+
857
+ # Breaking Changes (important for users!)
858
+ if [ ${#BREAKING_CHANGES[@]} -gt 0 ]; then
859
+ echo "### ⚠️ Breaking Changes"
860
+ echo ""
861
+ for commit in "${BREAKING_CHANGES[@]}"; do
862
+ format_user_facing_line "$commit"
863
+ done
864
+ echo ""
865
+ fi
866
+
867
+ # Deprecations
868
+ if [ ${#DEPRECATIONS[@]} -gt 0 ]; then
869
+ echo "### 📦 Deprecated"
870
+ echo ""
871
+ for commit in "${DEPRECATIONS[@]}"; do
872
+ format_user_facing_line "$commit"
873
+ done
874
+ echo ""
875
+ fi
876
+
877
+ # Note: We intentionally skip OTHER_CHANGES (chore, ci, docs, etc.)
878
+ # as they are not relevant to end users
879
+
880
+ cat << EOF
881
+ ---
882
+
883
+ _This release was automatically generated from ${#ALL_COMMITS[@]} commits._
884
+ EOF
885
+ }
886
+
621
887
  # === PACKAGE.JSON UPDATES ===
622
888
 
623
889
  update_package_files() {
@@ -689,11 +955,12 @@ update_changelog() {
689
955
  # Insert new entry after [Unreleased] section
690
956
  if echo "$existing_content" | grep -q "## \[Unreleased\]"; then
691
957
  # Find the line number of [Unreleased]
692
- local unreleased_line=$(echo "$existing_content" | grep -n "## \[Unreleased\]" | head -1 | cut -d: -f1)
958
+ # Using safe_first instead of head -1 to avoid SIGPIPE
959
+ local unreleased_line=$(echo "$existing_content" | grep -n "## \[Unreleased\]" | safe_first | cut -d: -f1)
693
960
 
694
961
  # Insert after [Unreleased] and its blank line
695
962
  {
696
- echo "$existing_content" | head -n $((unreleased_line))
963
+ echo "$existing_content" | safe_head "$((unreleased_line))"
697
964
  echo ""
698
965
  echo "$new_entry"
699
966
  echo "$existing_content" | tail -n +$((unreleased_line + 1))
@@ -701,7 +968,7 @@ update_changelog() {
701
968
  else
702
969
  # No [Unreleased] section, insert at the beginning after header
703
970
  {
704
- echo "$existing_content" | head -n 6
971
+ echo "$existing_content" | safe_head 6
705
972
  echo ""
706
973
  echo "$new_entry"
707
974
  echo "$existing_content" | tail -n +7
@@ -727,6 +994,88 @@ EOF
727
994
  echo ""
728
995
  }
729
996
 
997
+ # === RELEASE NOTES UPDATE ===
998
+
999
+ update_release_notes() {
1000
+ local version="$1"
1001
+ local date="$2"
1002
+
1003
+ log_info "Generating RELEASE_NOTES.md..."
1004
+
1005
+ local release_notes_file="$PROJECT_ROOT/RELEASE_NOTES.md"
1006
+
1007
+ # Create backup BEFORE modifying (if exists)
1008
+ if [ -f "$release_notes_file" ]; then
1009
+ create_backup "$release_notes_file"
1010
+ fi
1011
+
1012
+ # Track for rollback
1013
+ MODIFIED_FILES+=("$release_notes_file")
1014
+
1015
+ # Generate new entry
1016
+ local new_entry=$(generate_user_facing_notes_entry "$version" "$date")
1017
+
1018
+ # Read existing release notes and prepend new entry
1019
+ if [ -f "$release_notes_file" ]; then
1020
+ local existing_content=$(<"$release_notes_file")
1021
+
1022
+ # Check if file has header "# Release Notes"
1023
+ if echo "$existing_content" | grep -q "^# Release Notes"; then
1024
+ # Find the first ## section (first release) to insert before it
1025
+ local first_release_line=$(echo "$existing_content" | grep -n "^## v" | safe_first | cut -d: -f1)
1026
+
1027
+ if [ -n "$first_release_line" ] && [ "$first_release_line" -gt 0 ]; then
1028
+ # Insert new entry before the first release
1029
+ {
1030
+ echo "$existing_content" | safe_head "$((first_release_line - 1))"
1031
+ echo "$new_entry"
1032
+ echo ""
1033
+ echo "$existing_content" | tail -n +"$first_release_line"
1034
+ } > "$release_notes_file"
1035
+ else
1036
+ # No releases yet, append after header
1037
+ {
1038
+ echo "$existing_content" | safe_head 4
1039
+ echo ""
1040
+ echo "$new_entry"
1041
+ } > "$release_notes_file"
1042
+ fi
1043
+ else
1044
+ # Old format or missing header - recreate with new structure
1045
+ {
1046
+ cat << EOF
1047
+ # Release Notes
1048
+
1049
+ User-facing release notes for all versions.
1050
+
1051
+ EOF
1052
+ echo "$new_entry"
1053
+ echo ""
1054
+ # Keep old content after separator
1055
+ echo "---"
1056
+ echo ""
1057
+ echo "## Previous Releases"
1058
+ echo ""
1059
+ echo "$existing_content"
1060
+ } > "$release_notes_file"
1061
+ fi
1062
+ else
1063
+ # Create new RELEASE_NOTES.md with header
1064
+ {
1065
+ cat << EOF
1066
+ # Release Notes
1067
+
1068
+ User-facing release notes for all versions.
1069
+
1070
+ EOF
1071
+ echo "$new_entry"
1072
+ } > "$release_notes_file"
1073
+ fi
1074
+
1075
+ log_success "RELEASE_NOTES.md updated"
1076
+ echo ""
1077
+ }
1078
+
730
1079
  # === PREVIEW ===
731
1080
 
732
1081
  show_preview() {
@@ -768,10 +1117,14 @@ EOF
768
1117
 
769
1118
  cat << EOF
770
1119
 
771
- 📄 CHANGELOG.md Entry:
1120
+ 📄 CHANGELOG.md Entry (Technical):
772
1121
  ───────────────────────────────────────────────────────────
773
1122
  $(generate_changelog_entry "$NEW_VERSION" "$DATE")───────────────────────────────────────────────────────────
774
1123
 
1124
+ 📣 RELEASE_NOTES.md (User-Facing):
1125
+ ───────────────────────────────────────────────────────────
1126
+ $(generate_user_facing_notes_entry "$NEW_VERSION" "$DATE")───────────────────────────────────────────────────────────
1127
+
775
1128
  💬 Git Commit Message:
776
1129
  ───────────────────────────────────────────────────────────
777
1130
  chore(release): v$NEW_VERSION
@@ -854,7 +1207,7 @@ Co-Authored-By: Claude <noreply@anthropic.com>" || {
854
1207
  log_error "Tag v$NEW_VERSION already exists!"
855
1208
  echo ""
856
1209
  log_info "Existing tags:"
857
- git tag --sort=-version:refname | head -n 10
1210
+ git tag --sort=-version:refname | safe_head 10
858
1211
  echo ""
859
1212
  log_info "Suggested actions:"
860
1213
  echo " 1. Delete existing tag: git tag -d v$NEW_VERSION && git push origin :refs/tags/v$NEW_VERSION"
@@ -908,23 +1261,39 @@ main() {
908
1261
  # Parse arguments
909
1262
  local bump_arg=""
910
1263
  local auto_confirm="false"
1264
+ local custom_commit_msg=""
911
1265
 
912
- for arg in "$@"; do
913
- case "$arg" in
1266
+ while [[ $# -gt 0 ]]; do
1267
+ case "$1" in
914
1268
  --yes|-y)
915
1269
  auto_confirm="true"
1270
+ shift
1271
+ ;;
1272
+ --message|-m)
1273
+ if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
1274
+ custom_commit_msg="$2"
1275
+ shift 2
1276
+ else
1277
+ log_error "--message requires an argument"
1278
+ echo "Usage: $0 [patch|minor|major] [--yes] [--message \"commit message\"]"
1279
+ exit 1
1280
+ fi
916
1281
  ;;
917
1282
  patch|minor|major)
918
- bump_arg="$arg"
1283
+ bump_arg="$1"
1284
+ shift
919
1285
  ;;
920
1286
  *)
921
- log_error "Unknown argument: $arg"
922
- echo "Usage: $0 [patch|minor|major] [--yes]"
1287
+ log_error "Unknown argument: $1"
1288
+ echo "Usage: $0 [patch|minor|major] [--yes] [--message \"commit message\"]"
923
1289
  exit 1
924
1290
  ;;
925
1291
  esac
926
1292
  done
927
1293
 
1294
+ # Export custom_commit_msg for use in run_preflight_checks
1295
+ CUSTOM_COMMIT_MSG="$custom_commit_msg"
1296
+
928
1297
  # Run workflow
929
1298
  run_preflight_checks
930
1299
  parse_commits
@@ -938,6 +1307,7 @@ main() {
938
1307
  # Execute release
939
1308
  update_package_files "$NEW_VERSION"
940
1309
  update_changelog "$NEW_VERSION" "$DATE"
1310
+ update_release_notes "$NEW_VERSION" "$DATE"
941
1311
  execute_release
942
1312
 
943
1313
  echo ""
@@ -949,9 +1319,14 @@ main() {
949
1319
  log_success "Tag: v$NEW_VERSION"
950
1320
  log_success "Branch: $BRANCH"
951
1321
  echo ""
1322
+ log_info "Generated files:"
1323
+ echo " • CHANGELOG.md (technical, for developers)"
1324
+ echo " • RELEASE_NOTES.md (user-facing, for marketing)"
1325
+ echo ""
952
1326
  log_info "Next steps:"
953
1327
  echo " • Verify release on GitHub: git remote -v"
954
1328
  echo " • Create GitHub Release from tag (optional)"
1329
+ echo " • Copy RELEASE_NOTES.md content for announcements"
955
1330
  echo " • Notify team if applicable"
956
1331
  echo ""
957
1332
  }