claude-code-orchestrator-kit 1.0.0

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 (130) hide show
  1. package/.claude/agents/database/workers/api-builder.md +155 -0
  2. package/.claude/agents/database/workers/database-architect.md +193 -0
  3. package/.claude/agents/database/workers/supabase-auditor.md +1070 -0
  4. package/.claude/agents/development/workers/code-reviewer.md +968 -0
  5. package/.claude/agents/development/workers/cost-calculator-specialist.md +683 -0
  6. package/.claude/agents/development/workers/llm-service-specialist.md +999 -0
  7. package/.claude/agents/development/workers/skill-builder-v2.md +480 -0
  8. package/.claude/agents/development/workers/typescript-types-specialist.md +649 -0
  9. package/.claude/agents/development/workers/utility-builder.md +582 -0
  10. package/.claude/agents/documentation/workers/technical-writer.md +152 -0
  11. package/.claude/agents/frontend/workers/fullstack-nextjs-specialist.md +206 -0
  12. package/.claude/agents/frontend/workers/visual-effects-creator.md +159 -0
  13. package/.claude/agents/health/orchestrators/bug-orchestrator.md +1045 -0
  14. package/.claude/agents/health/orchestrators/dead-code-orchestrator.md +1045 -0
  15. package/.claude/agents/health/orchestrators/dependency-orchestrator.md +1045 -0
  16. package/.claude/agents/health/orchestrators/security-orchestrator.md +1045 -0
  17. package/.claude/agents/health/workers/bug-fixer.md +525 -0
  18. package/.claude/agents/health/workers/bug-hunter.md +649 -0
  19. package/.claude/agents/health/workers/dead-code-hunter.md +446 -0
  20. package/.claude/agents/health/workers/dead-code-remover.md +437 -0
  21. package/.claude/agents/health/workers/dependency-auditor.md +379 -0
  22. package/.claude/agents/health/workers/dependency-updater.md +436 -0
  23. package/.claude/agents/health/workers/security-scanner.md +700 -0
  24. package/.claude/agents/health/workers/vulnerability-fixer.md +524 -0
  25. package/.claude/agents/infrastructure/workers/infrastructure-specialist.md +156 -0
  26. package/.claude/agents/infrastructure/workers/orchestration-logic-specialist.md +1260 -0
  27. package/.claude/agents/infrastructure/workers/qdrant-specialist.md +503 -0
  28. package/.claude/agents/infrastructure/workers/quality-validator-specialist.md +984 -0
  29. package/.claude/agents/meta/workers/meta-agent-v3.md +503 -0
  30. package/.claude/agents/research/workers/problem-investigator.md +507 -0
  31. package/.claude/agents/research/workers/research-specialist.md +423 -0
  32. package/.claude/agents/testing/workers/accessibility-tester.md +813 -0
  33. package/.claude/agents/testing/workers/integration-tester.md +188 -0
  34. package/.claude/agents/testing/workers/mobile-fixes-implementer.md +252 -0
  35. package/.claude/agents/testing/workers/mobile-responsiveness-tester.md +180 -0
  36. package/.claude/agents/testing/workers/performance-optimizer.md +262 -0
  37. package/.claude/agents/testing/workers/test-writer.md +800 -0
  38. package/.claude/commands/health-bugs.md +297 -0
  39. package/.claude/commands/health-cleanup.md +297 -0
  40. package/.claude/commands/health-deps.md +297 -0
  41. package/.claude/commands/health-metrics.md +747 -0
  42. package/.claude/commands/health-security.md +297 -0
  43. package/.claude/commands/push.md +21 -0
  44. package/.claude/commands/speckit.analyze.md +184 -0
  45. package/.claude/commands/speckit.checklist.md +294 -0
  46. package/.claude/commands/speckit.clarify.md +178 -0
  47. package/.claude/commands/speckit.constitution.md +78 -0
  48. package/.claude/commands/speckit.implement.md +182 -0
  49. package/.claude/commands/speckit.plan.md +87 -0
  50. package/.claude/commands/speckit.specify.md +250 -0
  51. package/.claude/commands/speckit.tasks.md +137 -0
  52. package/.claude/commands/translate-doc.md +95 -0
  53. package/.claude/commands/worktree-cleanup.md +382 -0
  54. package/.claude/commands/worktree-create.md +287 -0
  55. package/.claude/commands/worktree-list.md +239 -0
  56. package/.claude/commands/worktree-remove.md +339 -0
  57. package/.claude/schemas/base-plan.schema.json +82 -0
  58. package/.claude/schemas/bug-plan.schema.json +71 -0
  59. package/.claude/schemas/dead-code-plan.schema.json +71 -0
  60. package/.claude/schemas/dependency-plan.schema.json +74 -0
  61. package/.claude/schemas/security-plan.schema.json +71 -0
  62. package/.claude/scripts/gates/check-bundle-size.sh +47 -0
  63. package/.claude/scripts/gates/check-coverage.sh +67 -0
  64. package/.claude/scripts/gates/check-security.sh +46 -0
  65. package/.claude/scripts/release.sh +740 -0
  66. package/.claude/settings.local.json +21 -0
  67. package/.claude/settings.local.json.example +20 -0
  68. package/.claude/skills/calculate-priority-score/SKILL.md +229 -0
  69. package/.claude/skills/calculate-priority-score/scoring-matrix.json +83 -0
  70. package/.claude/skills/extract-version/SKILL.md +228 -0
  71. package/.claude/skills/format-commit-message/SKILL.md +189 -0
  72. package/.claude/skills/format-commit-message/template.md +64 -0
  73. package/.claude/skills/format-markdown-table/SKILL.md +202 -0
  74. package/.claude/skills/format-markdown-table/examples.md +84 -0
  75. package/.claude/skills/format-todo-list/SKILL.md +222 -0
  76. package/.claude/skills/format-todo-list/template.json +30 -0
  77. package/.claude/skills/generate-changelog/SKILL.md +258 -0
  78. package/.claude/skills/generate-changelog/commit-mapping.json +47 -0
  79. package/.claude/skills/generate-report-header/SKILL.md +228 -0
  80. package/.claude/skills/generate-report-header/template.md +66 -0
  81. package/.claude/skills/parse-error-logs/SKILL.md +286 -0
  82. package/.claude/skills/parse-error-logs/patterns.json +26 -0
  83. package/.claude/skills/parse-git-status/SKILL.md +164 -0
  84. package/.claude/skills/parse-package-json/SKILL.md +151 -0
  85. package/.claude/skills/parse-package-json/schema.json +43 -0
  86. package/.claude/skills/render-template/SKILL.md +245 -0
  87. package/.claude/skills/rollback-changes/SKILL.md +582 -0
  88. package/.claude/skills/rollback-changes/changes-log-schema.json +101 -0
  89. package/.claude/skills/run-quality-gate/SKILL.md +404 -0
  90. package/.claude/skills/run-quality-gate/gate-mappings.json +97 -0
  91. package/.claude/skills/validate-plan-file/SKILL.md +327 -0
  92. package/.claude/skills/validate-plan-file/schema.json +35 -0
  93. package/.claude/skills/validate-report-file/SKILL.md +256 -0
  94. package/.claude/skills/validate-report-file/schema.json +67 -0
  95. package/.env.example +49 -0
  96. package/.github/BRANCH_PROTECTION.md +137 -0
  97. package/.github/workflows/build.yml +70 -0
  98. package/.github/workflows/claude-code-review.yml +255 -0
  99. package/.github/workflows/claude.yml +79 -0
  100. package/.github/workflows/deploy-staging.yml +90 -0
  101. package/.github/workflows/test.yml +104 -0
  102. package/.gitignore +116 -0
  103. package/CLAUDE.md +137 -0
  104. package/LICENSE +72 -0
  105. package/README.md +1098 -0
  106. package/docs/ARCHITECTURE.md +746 -0
  107. package/docs/Agents Ecosystem/AGENT-ORCHESTRATION.md +568 -0
  108. package/docs/Agents Ecosystem/AI-AGENT-ECOSYSTEM-README.md +658 -0
  109. package/docs/Agents Ecosystem/ARCHITECTURE.md +606 -0
  110. package/docs/Agents Ecosystem/QUALITY-GATES-SPECIFICATION.md +1315 -0
  111. package/docs/Agents Ecosystem/REPORT-TEMPLATE-STANDARD.md +1324 -0
  112. package/docs/Agents Ecosystem/spec-kit-comprehensive-updates.md +478 -0
  113. package/docs/FAQ.md +572 -0
  114. package/docs/MIGRATION-GUIDE.md +542 -0
  115. package/docs/PERFORMANCE-OPTIMIZATION.md +494 -0
  116. package/docs/ROADMAP.md +439 -0
  117. package/docs/TUTORIAL-CUSTOM-AGENTS.md +2041 -0
  118. package/docs/USE-CASES.md +706 -0
  119. package/index.js +96 -0
  120. package/mcp/.mcp.base.json +21 -0
  121. package/mcp/.mcp.frontend.json +29 -0
  122. package/mcp/.mcp.full.json +67 -0
  123. package/mcp/.mcp.local.example.json +7 -0
  124. package/mcp/.mcp.local.json +7 -0
  125. package/mcp/.mcp.n8n.json +45 -0
  126. package/mcp/.mcp.supabase-full.json +35 -0
  127. package/mcp/.mcp.supabase-only.json +28 -0
  128. package/package.json +78 -0
  129. package/postinstall.js +71 -0
  130. package/switch-mcp.sh +101 -0
@@ -0,0 +1,740 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Release Automation Script
4
+ # Automated release management with version bumping and changelog generation
5
+ #
6
+ # Features:
7
+ # - Auto-syncs package.json versions with latest git tag (prevents version conflicts)
8
+ # - Auto-detects version bump from conventional commits
9
+ # - Generates CHANGELOG.md entries
10
+ # - Rollback support for failed releases
11
+ #
12
+ # Usage: ./release.sh [patch|minor|major] [--yes]
13
+ # Leave empty for auto-detection from conventional commits
14
+ # --yes: Skip confirmation prompt (for automation)
15
+
16
+ set -euo pipefail
17
+
18
+ # === CONFIGURATION ===
19
+ readonly DATE=$(date +%Y-%m-%d)
20
+ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
22
+
23
+ # Colors for output
24
+ readonly RED='\033[0;31m'
25
+ readonly GREEN='\033[0;32m'
26
+ readonly YELLOW='\033[1;33m'
27
+ readonly BLUE='\033[0;34m'
28
+ readonly NC='\033[0m' # No Color
29
+
30
+ # State tracking for rollback
31
+ CREATED_COMMIT=""
32
+ CREATED_TAG=""
33
+ STASH_CREATED=""
34
+ declare -a MODIFIED_FILES=()
35
+
36
+ # Commit categorization arrays
37
+ declare -a ALL_COMMITS=()
38
+ declare -a FEATURES=()
39
+ declare -a FIXES=()
40
+ declare -a BREAKING_CHANGES=()
41
+ declare -a REFACTORS=()
42
+ declare -a PERF=()
43
+ declare -a OTHER_CHANGES=()
44
+
45
+ # === UTILITY FUNCTIONS ===
46
+
47
+ log_info() {
48
+ echo -e "${BLUE}ℹ️ $*${NC}"
49
+ }
50
+
51
+ log_success() {
52
+ echo -e "${GREEN}✅ $*${NC}"
53
+ }
54
+
55
+ log_warning() {
56
+ echo -e "${YELLOW}⚠️ $*${NC}"
57
+ }
58
+
59
+ log_error() {
60
+ echo -e "${RED}❌ $*${NC}" >&2
61
+ }
62
+
63
+ # === CLEANUP AND ROLLBACK ===
64
+
65
+ cleanup() {
66
+ local exit_code=$?
67
+
68
+ if [ $exit_code -ne 0 ]; then
69
+ echo ""
70
+ log_error "Error occurred during release process"
71
+ echo ""
72
+ log_warning "Rolling back changes..."
73
+
74
+ # Delete tag if created
75
+ if [ -n "$CREATED_TAG" ]; then
76
+ git tag -d "$CREATED_TAG" 2>/dev/null || true
77
+ log_success "Deleted tag $CREATED_TAG"
78
+ fi
79
+
80
+ # Rollback commit using reset --soft to preserve working directory
81
+ if [ -n "$CREATED_COMMIT" ]; then
82
+ git reset --soft HEAD~1 2>/dev/null || true
83
+ log_success "Rolled back commit (working directory preserved)"
84
+ fi
85
+
86
+ # Restore modified files only (not untracked files)
87
+ if [ ${#MODIFIED_FILES[@]} -gt 0 ]; then
88
+ git restore --staged "${MODIFIED_FILES[@]}" 2>/dev/null || true
89
+ git restore "${MODIFIED_FILES[@]}" 2>/dev/null || true
90
+ log_success "Restored modified package.json files"
91
+ fi
92
+
93
+ # Restore stash if we created one
94
+ if [ -n "$STASH_CREATED" ]; then
95
+ if git stash list | grep -q "release.sh: temporary stash"; then
96
+ git stash pop >/dev/null 2>&1 || {
97
+ log_warning "Stash pop failed with conflicts. Use 'git stash list' to see stashes."
98
+ log_info "Manually restore with: git stash pop"
99
+ }
100
+ fi
101
+ log_success "Stashed changes restored (or available in stash list)"
102
+ fi
103
+
104
+ echo ""
105
+ log_info "Rollback complete. Repository state restored."
106
+ echo ""
107
+ exit $exit_code
108
+ fi
109
+ }
110
+
111
+ trap cleanup EXIT
112
+
113
+ # === PRE-FLIGHT CHECKS ===
114
+
115
+ run_preflight_checks() {
116
+ log_info "Running pre-flight checks..."
117
+ echo ""
118
+
119
+ # Check if we're in the project root
120
+ if [ ! -f "$PROJECT_ROOT/package.json" ]; then
121
+ log_error "Not in project root. Could not find package.json"
122
+ exit 1
123
+ fi
124
+
125
+ # Check if on a branch (not detached HEAD)
126
+ BRANCH=$(git branch --show-current)
127
+ if [ -z "$BRANCH" ]; then
128
+ log_error "You are in detached HEAD state"
129
+ echo "Checkout a branch first:"
130
+ echo " git checkout main"
131
+ exit 1
132
+ fi
133
+ log_success "On branch: $BRANCH"
134
+
135
+ # Stash uncommitted changes to preserve user work
136
+ if ! git diff-index --quiet HEAD -- 2>/dev/null; then
137
+ log_warning "Uncommitted changes detected. Stashing for safety..."
138
+ git stash push -m "release.sh: temporary stash $(date +%Y%m%d-%H%M%S)" >/dev/null 2>&1 || {
139
+ log_error "Failed to stash changes. Please commit or stash manually."
140
+ exit 1
141
+ }
142
+ STASH_CREATED="true"
143
+ log_success "Changes stashed (will be restored on exit)"
144
+ fi
145
+
146
+ # Check if remote is configured
147
+ if ! git remote -v | grep -q origin; then
148
+ log_error "No remote 'origin' configured"
149
+ exit 1
150
+ fi
151
+ log_success "Remote configured"
152
+
153
+ # Check for Node.js
154
+ if ! command -v node &> /dev/null; then
155
+ log_error "Node.js is not installed"
156
+ exit 1
157
+ fi
158
+ log_success "Node.js available"
159
+
160
+ # Get current version
161
+ CURRENT_VERSION=$(node -p "require('$PROJECT_ROOT/package.json').version")
162
+ if [ -z "$CURRENT_VERSION" ]; then
163
+ log_error "Could not read current version from package.json"
164
+ exit 1
165
+ fi
166
+ log_success "Current version: $CURRENT_VERSION"
167
+
168
+ # Get last git tag (across all branches using --all)
169
+ LAST_TAG=$(git tag --sort=-version:refname | head -n 1 || echo "")
170
+ if [ -z "$LAST_TAG" ]; then
171
+ log_warning "No previous git tags found (first release)"
172
+ LAST_TAG="HEAD~999999" # Get all commits
173
+ COMMITS_RANGE="HEAD"
174
+ else
175
+ log_success "Last tag: $LAST_TAG"
176
+ COMMITS_RANGE="${LAST_TAG}..HEAD"
177
+
178
+ # Sync package.json version with git tag if needed
179
+ TAG_VERSION="${LAST_TAG#v}" # Remove 'v' prefix
180
+ if [ "$CURRENT_VERSION" != "$TAG_VERSION" ]; then
181
+ log_warning "Version mismatch: package.json ($CURRENT_VERSION) != tag ($TAG_VERSION)"
182
+ log_info "Syncing package.json versions to $TAG_VERSION..."
183
+
184
+ # Find and update all package.json files
185
+ find "$PROJECT_ROOT" -name "package.json" -not -path "*/node_modules/*" -print0 | while IFS= read -r -d '' pkg_file; do
186
+ if grep -q "\"version\"" "$pkg_file"; then
187
+ sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$TAG_VERSION\"/" "$pkg_file"
188
+ MODIFIED_FILES+=("$pkg_file")
189
+ fi
190
+ done
191
+
192
+ CURRENT_VERSION="$TAG_VERSION"
193
+ log_success "Synced all package.json files to version $TAG_VERSION"
194
+ fi
195
+ fi
196
+
197
+ # Check for commits since last tag
198
+ COMMITS_COUNT=$(git rev-list $COMMITS_RANGE --count 2>/dev/null || echo "0")
199
+ if [ "$COMMITS_COUNT" -eq 0 ]; then
200
+ log_error "No commits since last release ($LAST_TAG)"
201
+ echo "Nothing to release!"
202
+ exit 1
203
+ fi
204
+ log_success "Found $COMMITS_COUNT commits since last release"
205
+
206
+ echo ""
207
+ }
208
+
209
+ # === COMMIT PARSING ===
210
+
211
+ parse_commits() {
212
+ log_info "Analyzing commits since ${LAST_TAG:-start}..."
213
+ echo ""
214
+
215
+ # Get all commits with hash
216
+ while IFS= read -r line; do
217
+ if [ -n "$line" ]; then
218
+ ALL_COMMITS+=("$line")
219
+ fi
220
+ done < <(git log --format="%h %s" $COMMITS_RANGE)
221
+
222
+ # Parse and categorize each commit
223
+ # Define regex patterns as variables for proper bash regex matching
224
+ local breaking_pattern='^[a-z]+(\([^)]+\))?!:'
225
+ local feat_pattern='^feat(\([^)]+\))?:'
226
+ local fix_pattern='^fix(\([^)]+\))?:'
227
+ local refactor_pattern='^refactor(\([^)]+\))?:'
228
+ local perf_pattern='^perf(\([^)]+\))?:'
229
+
230
+ for commit in "${ALL_COMMITS[@]}"; do
231
+ local hash=$(echo "$commit" | awk '{print $1}')
232
+ local message=$(echo "$commit" | cut -d' ' -f2-)
233
+
234
+ # Check for breaking changes
235
+ if [[ "$message" =~ $breaking_pattern ]] || echo "$message" | grep -q "BREAKING CHANGE:"; then
236
+ BREAKING_CHANGES+=("$commit")
237
+ # Check for features
238
+ elif [[ "$message" =~ $feat_pattern ]]; then
239
+ FEATURES+=("$commit")
240
+ # Check for fixes
241
+ elif [[ "$message" =~ $fix_pattern ]]; then
242
+ FIXES+=("$commit")
243
+ # Check for refactors
244
+ elif [[ "$message" =~ $refactor_pattern ]]; then
245
+ REFACTORS+=("$commit")
246
+ # Check for performance improvements
247
+ elif [[ "$message" =~ $perf_pattern ]]; then
248
+ PERF+=("$commit")
249
+ # Everything else
250
+ else
251
+ OTHER_CHANGES+=("$commit")
252
+ fi
253
+ done
254
+
255
+ # Display commit summary
256
+ log_info "Commit summary:"
257
+ [ ${#BREAKING_CHANGES[@]} -gt 0 ] && echo " 🔥 ${#BREAKING_CHANGES[@]} breaking changes"
258
+ [ ${#FEATURES[@]} -gt 0 ] && echo " ✨ ${#FEATURES[@]} features"
259
+ [ ${#FIXES[@]} -gt 0 ] && echo " 🐛 ${#FIXES[@]} bug fixes"
260
+ [ ${#REFACTORS[@]} -gt 0 ] && echo " ♻️ ${#REFACTORS[@]} refactors"
261
+ [ ${#PERF[@]} -gt 0 ] && echo " ⚡ ${#PERF[@]} performance improvements"
262
+ [ ${#OTHER_CHANGES[@]} -gt 0 ] && echo " 📝 ${#OTHER_CHANGES[@]} other changes"
263
+ echo ""
264
+ }
265
+
266
+ # === VERSION BUMP DETECTION ===
267
+
268
+ detect_version_bump() {
269
+ local provided_bump="$1"
270
+
271
+ # If bump type provided, validate and use it
272
+ if [ -n "$provided_bump" ]; then
273
+ if [[ ! "$provided_bump" =~ ^(patch|minor|major)$ ]]; then
274
+ log_error "Invalid version bump type: $provided_bump"
275
+ echo "Usage: ./release.sh [patch|minor|major]"
276
+ exit 1
277
+ fi
278
+ BUMP_TYPE="$provided_bump"
279
+ AUTO_DETECT_REASON="Manually specified"
280
+ log_info "Using manual version bump: $BUMP_TYPE"
281
+ else
282
+ # Auto-detect from commits
283
+ if [ ${#BREAKING_CHANGES[@]} -gt 0 ]; then
284
+ BUMP_TYPE="major"
285
+ AUTO_DETECT_REASON="Found ${#BREAKING_CHANGES[@]} breaking change(s)"
286
+ elif [ ${#FEATURES[@]} -gt 0 ]; then
287
+ BUMP_TYPE="minor"
288
+ AUTO_DETECT_REASON="Found ${#FEATURES[@]} new feature(s)"
289
+ elif [ ${#FIXES[@]} -gt 0 ]; then
290
+ BUMP_TYPE="patch"
291
+ AUTO_DETECT_REASON="Found ${#FIXES[@]} bug fix(es)"
292
+ else
293
+ BUMP_TYPE="patch"
294
+ AUTO_DETECT_REASON="Default (no conventional commits detected)"
295
+ fi
296
+ log_success "Auto-detected version bump: $BUMP_TYPE ($AUTO_DETECT_REASON)"
297
+ fi
298
+ echo ""
299
+ }
300
+
301
+ # === VERSION CALCULATION ===
302
+
303
+ calculate_new_version() {
304
+ local current="$CURRENT_VERSION"
305
+ local IFS='.'
306
+ read -ra parts <<< "$current"
307
+
308
+ local major="${parts[0]}"
309
+ local minor="${parts[1]}"
310
+ local patch="${parts[2]}"
311
+
312
+ case "$BUMP_TYPE" in
313
+ major)
314
+ major=$((major + 1))
315
+ minor=0
316
+ patch=0
317
+ ;;
318
+ minor)
319
+ minor=$((minor + 1))
320
+ patch=0
321
+ ;;
322
+ patch)
323
+ patch=$((patch + 1))
324
+ ;;
325
+ esac
326
+
327
+ NEW_VERSION="$major.$minor.$patch"
328
+ }
329
+
330
+ # === CHANGELOG GENERATION ===
331
+
332
+ generate_changelog_entry() {
333
+ local version="$1"
334
+ local date="$2"
335
+
336
+ cat << EOF
337
+ ## [$version] - $date
338
+
339
+ EOF
340
+
341
+ # Added section (features)
342
+ if [ ${#FEATURES[@]} -gt 0 ]; then
343
+ echo "### Added"
344
+ for commit in "${FEATURES[@]}"; do
345
+ format_changelog_line "$commit"
346
+ done
347
+ echo ""
348
+ fi
349
+
350
+ # Changed section (breaking, refactor, perf)
351
+ if [ ${#BREAKING_CHANGES[@]} -gt 0 ] || [ ${#REFACTORS[@]} -gt 0 ] || [ ${#PERF[@]} -gt 0 ]; then
352
+ echo "### Changed"
353
+ for commit in "${BREAKING_CHANGES[@]}"; do
354
+ format_changelog_line "$commit" "⚠️ BREAKING: "
355
+ done
356
+ for commit in "${REFACTORS[@]}"; do
357
+ format_changelog_line "$commit"
358
+ done
359
+ for commit in "${PERF[@]}"; do
360
+ format_changelog_line "$commit"
361
+ done
362
+ echo ""
363
+ fi
364
+
365
+ # Fixed section
366
+ if [ ${#FIXES[@]} -gt 0 ]; then
367
+ echo "### Fixed"
368
+ for commit in "${FIXES[@]}"; do
369
+ format_changelog_line "$commit"
370
+ done
371
+ echo ""
372
+ fi
373
+ }
374
+
375
+ format_changelog_line() {
376
+ local commit="$1"
377
+ local prefix="${2:-}"
378
+
379
+ local hash=$(echo "$commit" | awk '{print $1}')
380
+ local message=$(echo "$commit" | cut -d' ' -f2-)
381
+
382
+ # Extract scope if present: "type(scope): message" -> "**scope**: message"
383
+ local scope_pattern='^[a-z]+(\(([^)]+)\))?!?:[ ]+(.+)$'
384
+ if [[ "$message" =~ $scope_pattern ]]; then
385
+ local scope="${BASH_REMATCH[2]}"
386
+ local msg="${BASH_REMATCH[3]}"
387
+
388
+ if [ -n "$scope" ]; then
389
+ echo "- ${prefix}**${scope}**: ${msg} (${hash})"
390
+ else
391
+ echo "- ${prefix}${msg} (${hash})"
392
+ fi
393
+ else
394
+ # Not a conventional commit, use as-is
395
+ echo "- ${prefix}${message} (${hash})"
396
+ fi
397
+ }
398
+
399
+ # === PACKAGE.JSON UPDATES ===
400
+
401
+ update_package_files() {
402
+ local version="$1"
403
+
404
+ log_info "Updating package.json files..."
405
+ echo ""
406
+
407
+ # Find all package.json files
408
+ local package_files=$(find "$PROJECT_ROOT" -name "package.json" \
409
+ -not -path "*/node_modules/*" \
410
+ -not -path "*/.next/*" \
411
+ -not -path "*/dist/*" \
412
+ -not -path "*/.turbo/*" \
413
+ -not -path "*/build/*")
414
+
415
+ while IFS= read -r pkg; do
416
+ if [ -n "$pkg" ]; then
417
+ # Track for rollback
418
+ MODIFIED_FILES+=("$pkg")
419
+
420
+ # Update version using Node.js for proper JSON handling
421
+ node -e "
422
+ const fs = require('fs');
423
+ const path = '$pkg';
424
+ const data = JSON.parse(fs.readFileSync(path, 'utf-8'));
425
+ data.version = '$version';
426
+ fs.writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
427
+ " || {
428
+ log_error "Failed to update $pkg"
429
+ exit 1
430
+ }
431
+
432
+ # Show relative path
433
+ local rel_path="${pkg#$PROJECT_ROOT/}"
434
+ echo " ✓ $rel_path"
435
+ fi
436
+ done <<< "$package_files"
437
+
438
+ echo ""
439
+ }
440
+
441
+ # === CHANGELOG UPDATE ===
442
+
443
+ update_changelog() {
444
+ local version="$1"
445
+ local date="$2"
446
+
447
+ log_info "Updating CHANGELOG.md..."
448
+
449
+ local changelog_file="$PROJECT_ROOT/CHANGELOG.md"
450
+
451
+ # Track for rollback
452
+ MODIFIED_FILES+=("$changelog_file")
453
+
454
+ # Generate new entry
455
+ local new_entry=$(generate_changelog_entry "$version" "$date")
456
+
457
+ # Read existing changelog
458
+ if [ -f "$changelog_file" ]; then
459
+ local existing_content=$(<"$changelog_file")
460
+
461
+ # Insert new entry after [Unreleased] section
462
+ if echo "$existing_content" | grep -q "## \[Unreleased\]"; then
463
+ # Find the line number of [Unreleased]
464
+ local unreleased_line=$(echo "$existing_content" | grep -n "## \[Unreleased\]" | head -1 | cut -d: -f1)
465
+
466
+ # Insert after [Unreleased] and its blank line
467
+ {
468
+ echo "$existing_content" | head -n $((unreleased_line))
469
+ echo ""
470
+ echo "$new_entry"
471
+ echo "$existing_content" | tail -n +$((unreleased_line + 1))
472
+ } > "$changelog_file"
473
+ else
474
+ # No [Unreleased] section, insert at the beginning after header
475
+ {
476
+ echo "$existing_content" | head -n 6
477
+ echo ""
478
+ echo "$new_entry"
479
+ echo "$existing_content" | tail -n +7
480
+ } > "$changelog_file"
481
+ fi
482
+ else
483
+ # Create new CHANGELOG.md
484
+ cat > "$changelog_file" << EOF
485
+ # Changelog
486
+
487
+ All notable changes to this project will be documented in this file.
488
+
489
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
490
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
491
+
492
+ ## [Unreleased]
493
+
494
+ $new_entry
495
+ EOF
496
+ fi
497
+
498
+ log_success "CHANGELOG.md updated"
499
+ echo ""
500
+ }
501
+
502
+ # === PREVIEW ===
503
+
504
+ show_preview() {
505
+ cat << EOF
506
+ ═══════════════════════════════════════════════════════════
507
+ RELEASE PREVIEW
508
+ ═══════════════════════════════════════════════════════════
509
+
510
+ 📌 Version: $CURRENT_VERSION → $NEW_VERSION (${BUMP_TYPE^^})
511
+ Reason: $AUTO_DETECT_REASON
512
+
513
+ 📊 Commits included: ${#ALL_COMMITS[@]}
514
+ EOF
515
+
516
+ [ ${#BREAKING_CHANGES[@]} -gt 0 ] && echo " 🔥 ${#BREAKING_CHANGES[@]} breaking changes"
517
+ [ ${#FEATURES[@]} -gt 0 ] && echo " ✨ ${#FEATURES[@]} features"
518
+ [ ${#FIXES[@]} -gt 0 ] && echo " 🐛 ${#FIXES[@]} bug fixes"
519
+ [ ${#REFACTORS[@]} -gt 0 ] && echo " ♻️ ${#REFACTORS[@]} refactors"
520
+ [ ${#PERF[@]} -gt 0 ] && echo " ⚡ ${#PERF[@]} performance improvements"
521
+ [ ${#OTHER_CHANGES[@]} -gt 0 ] && echo " 📝 ${#OTHER_CHANGES[@]} other changes"
522
+
523
+ cat << EOF
524
+
525
+ 📦 Package Updates:
526
+ EOF
527
+
528
+ find "$PROJECT_ROOT" -name "package.json" \
529
+ -not -path "*/node_modules/*" \
530
+ -not -path "*/.next/*" \
531
+ -not -path "*/dist/*" \
532
+ -not -path "*/.turbo/*" \
533
+ -not -path "*/build/*" | while read -r pkg; do
534
+ local rel_path="${pkg#$PROJECT_ROOT/}"
535
+ echo " ✓ $rel_path"
536
+ done
537
+
538
+ cat << EOF
539
+
540
+ 📄 CHANGELOG.md Entry:
541
+ ───────────────────────────────────────────────────────────
542
+ $(generate_changelog_entry "$NEW_VERSION" "$DATE")───────────────────────────────────────────────────────────
543
+
544
+ 💬 Git Commit Message:
545
+ ───────────────────────────────────────────────────────────
546
+ chore(release): v$NEW_VERSION
547
+
548
+ Release version $NEW_VERSION with ${#FEATURES[@]} features and ${#FIXES[@]} fixes
549
+
550
+ Includes commits from ${LAST_TAG:-start} to HEAD
551
+
552
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
553
+
554
+ Co-Authored-By: Claude <noreply@anthropic.com>
555
+ ───────────────────────────────────────────────────────────
556
+
557
+ 🏷️ Git Tag: v$NEW_VERSION
558
+ 🌿 Branch: $BRANCH
559
+
560
+ ═══════════════════════════════════════════════════════════
561
+ EOF
562
+ }
563
+
564
+ # === USER CONFIRMATION ===
565
+
566
+ get_user_confirmation() {
567
+ local auto_confirm="$1"
568
+
569
+ echo ""
570
+
571
+ # Skip confirmation if --yes flag provided
572
+ if [ "$auto_confirm" = "true" ]; then
573
+ log_info "Auto-confirming release (--yes flag provided)"
574
+ echo ""
575
+ return 0
576
+ fi
577
+
578
+ read -p "Proceed with release? [Y/n]: " confirm
579
+
580
+ if [[ ! "$confirm" =~ ^[Yy]?$ ]]; then
581
+ log_warning "Release cancelled by user"
582
+ exit 0
583
+ fi
584
+
585
+ echo ""
586
+ }
587
+
588
+ # === EXECUTE RELEASE ===
589
+
590
+ execute_release() {
591
+ log_info "Executing release..."
592
+ echo ""
593
+
594
+ # Stage all changes
595
+ log_info "Staging changes..."
596
+ git add -A
597
+
598
+ # Create commit
599
+ log_info "Creating release commit..."
600
+ git commit -m "chore(release): v$NEW_VERSION
601
+
602
+ Release version $NEW_VERSION with ${#FEATURES[@]} features and ${#FIXES[@]} fixes
603
+
604
+ Includes commits from ${LAST_TAG:-start} to HEAD
605
+
606
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
607
+
608
+ Co-Authored-By: Claude <noreply@anthropic.com>" || {
609
+ log_error "Failed to create commit"
610
+ exit 1
611
+ }
612
+ CREATED_COMMIT="true"
613
+ log_success "Commit created"
614
+
615
+ # Create tag (check if exists first)
616
+ log_info "Creating git tag..."
617
+
618
+ # Check if tag already exists
619
+ if git rev-parse "v$NEW_VERSION" >/dev/null 2>&1; then
620
+ log_error "Tag v$NEW_VERSION already exists!"
621
+ echo ""
622
+ log_info "Existing tags:"
623
+ git tag --sort=-version:refname | head -n 10
624
+ echo ""
625
+ log_info "Suggested actions:"
626
+ echo " 1. Delete existing tag: git tag -d v$NEW_VERSION && git push origin :refs/tags/v$NEW_VERSION"
627
+ echo " 2. Use different version: ./release.sh [patch|minor|major]"
628
+ exit 1
629
+ fi
630
+
631
+ local tag_message="Release v$NEW_VERSION
632
+
633
+ $(generate_changelog_entry "$NEW_VERSION" "$DATE")"
634
+
635
+ git tag -a "v$NEW_VERSION" -m "$tag_message" || {
636
+ log_error "Failed to create tag"
637
+ exit 1
638
+ }
639
+ CREATED_TAG="v$NEW_VERSION"
640
+ log_success "Tag v$NEW_VERSION created"
641
+
642
+ # Push to remote
643
+ log_info "Pushing to remote..."
644
+ git push origin "$BRANCH" --follow-tags || {
645
+ log_error "Failed to push to remote"
646
+ echo ""
647
+ log_warning "Your changes are committed locally but push failed."
648
+ echo ""
649
+ echo "To retry push:"
650
+ echo " git push origin $BRANCH --follow-tags"
651
+ echo ""
652
+ echo "To rollback:"
653
+ echo " git reset --hard HEAD~1"
654
+ echo " git tag -d v$NEW_VERSION"
655
+ echo ""
656
+ exit 1
657
+ }
658
+ log_success "Pushed to origin/$BRANCH"
659
+
660
+ echo ""
661
+ }
662
+
663
+ # === MAIN ===
664
+
665
+ main() {
666
+ cd "$PROJECT_ROOT"
667
+
668
+ echo ""
669
+ echo "╔═══════════════════════════════════════════════════════════╗"
670
+ echo "║ Release Automation ║"
671
+ echo "╚═══════════════════════════════════════════════════════════╝"
672
+ echo ""
673
+
674
+ # Parse arguments
675
+ local bump_arg=""
676
+ local auto_confirm="false"
677
+
678
+ for arg in "$@"; do
679
+ case "$arg" in
680
+ --yes|-y)
681
+ auto_confirm="true"
682
+ ;;
683
+ patch|minor|major)
684
+ bump_arg="$arg"
685
+ ;;
686
+ *)
687
+ log_error "Unknown argument: $arg"
688
+ echo "Usage: $0 [patch|minor|major] [--yes]"
689
+ exit 1
690
+ ;;
691
+ esac
692
+ done
693
+
694
+ # Run workflow
695
+ run_preflight_checks
696
+ parse_commits
697
+ detect_version_bump "$bump_arg"
698
+ calculate_new_version
699
+
700
+ # Show preview
701
+ show_preview
702
+ get_user_confirmation "$auto_confirm"
703
+
704
+ # Execute release
705
+ update_package_files "$NEW_VERSION"
706
+ update_changelog "$NEW_VERSION" "$DATE"
707
+ execute_release
708
+
709
+ # Success! Restore stash if created
710
+ if [ -n "$STASH_CREATED" ]; then
711
+ log_info "Restoring stashed changes..."
712
+ if git stash list | grep -q "release.sh: temporary stash"; then
713
+ git stash pop >/dev/null 2>&1 || {
714
+ log_warning "Stash pop had conflicts. Check 'git stash list'"
715
+ log_info "Manually restore with: git stash pop"
716
+ }
717
+ fi
718
+ fi
719
+
720
+ echo ""
721
+ echo "╔═══════════════════════════════════════════════════════════╗"
722
+ echo "║ RELEASE SUCCESSFUL! 🎉 ║"
723
+ echo "╚═══════════════════════════════════════════════════════════╝"
724
+ echo ""
725
+ log_success "Released v$NEW_VERSION"
726
+ log_success "Tag: v$NEW_VERSION"
727
+ log_success "Branch: $BRANCH"
728
+ if [ -n "$STASH_CREATED" ]; then
729
+ log_success "Stashed changes restored"
730
+ fi
731
+ echo ""
732
+ log_info "Next steps:"
733
+ echo " • Verify release on GitHub: git remote -v"
734
+ echo " • Create GitHub Release from tag (optional)"
735
+ echo " • Notify team if applicable"
736
+ echo ""
737
+ }
738
+
739
+ # Run main function
740
+ main "$@"