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.
- package/.claude/agents/business/workers/lead-research-assistant.md +199 -0
- package/.claude/agents/database/workers/api-builder.md +8 -0
- package/.claude/agents/database/workers/database-architect.md +11 -3
- package/.claude/agents/database/workers/supabase-auditor.md +7 -7
- package/.claude/agents/database/workers/supabase-fixer.md +825 -0
- package/.claude/agents/database/workers/supabase-realtime-optimizer.md +1086 -0
- package/.claude/agents/database/workers/supabase-storage-optimizer.md +1187 -0
- package/.claude/agents/development/workers/code-reviewer.md +17 -2
- package/.claude/agents/development/workers/code-structure-refactorer.md +771 -0
- package/.claude/agents/development/workers/judge-specialist.md +3275 -0
- package/.claude/agents/development/workers/langgraph-specialist.md +1343 -0
- package/.claude/agents/development/workers/stage-pipeline-specialist.md +1173 -0
- package/.claude/agents/frontend/workers/fullstack-nextjs-specialist.md +10 -0
- package/.claude/agents/frontend/workers/nextjs-ui-designer.md +30 -0
- package/.claude/agents/health/workers/bug-fixer.md +31 -3
- package/.claude/agents/health/workers/bug-hunter.md +0 -1
- package/.claude/agents/health/workers/dead-code-hunter.md +167 -75
- package/.claude/agents/health/workers/dead-code-remover.md +217 -66
- package/.claude/agents/health/workers/dependency-auditor.md +83 -24
- package/.claude/agents/health/workers/dependency-updater.md +0 -1
- package/.claude/agents/health/workers/security-scanner.md +0 -1
- package/.claude/agents/infrastructure/workers/bullmq-worker-specialist.md +748 -0
- package/.claude/agents/infrastructure/workers/deployment-engineer.md +446 -0
- package/.claude/agents/infrastructure/workers/infrastructure-specialist.md +2 -2
- package/.claude/agents/infrastructure/workers/rag-specialist.md +799 -0
- package/.claude/agents/infrastructure/workers/server-hardening-specialist.md +1128 -0
- package/.claude/agents/integrations/workers/lms-integration-specialist.md +866 -0
- package/.claude/agents/meta/workers/meta-agent-v3.md +22 -0
- package/.claude/agents/testing/workers/integration-tester.md +1 -1
- package/.claude/agents/testing/workers/test-writer.md +16 -0
- package/.claude/commands/health-bugs.md +14 -281
- package/.claude/commands/health-cleanup.md +14 -281
- package/.claude/commands/health-deps.md +14 -281
- package/.claude/commands/health-metrics.md +51 -709
- package/.claude/commands/health-reuse.md +14 -311
- package/.claude/commands/health-security.md +14 -281
- package/.claude/commands/push.md +17 -3
- package/.claude/commands/speckit.implement.md +0 -11
- package/.claude/commands/supabase-performance-optimizer.md +73 -0
- package/.claude/commands/ultra-think.md +158 -0
- package/.claude/commands/worktree.md +150 -0
- package/.claude/scripts/gates/check-bundle-size.sh +0 -0
- package/.claude/scripts/gates/check-coverage.sh +0 -0
- package/.claude/scripts/gates/check-security.sh +0 -0
- package/.claude/scripts/release.sh +469 -94
- package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
- package/.claude/skills/algorithmic-art/SKILL.md +405 -0
- package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
- package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
- package/.claude/skills/artifacts-builder/LICENSE.txt +202 -0
- package/.claude/skills/artifacts-builder/SKILL.md +74 -0
- package/.claude/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/.claude/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
- package/.claude/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/.claude/skills/bug-health-inline/SKILL.md +221 -0
- package/.claude/skills/bug-health-inline/references/worker-prompts.md +182 -0
- package/.claude/skills/canvas-design/LICENSE.txt +202 -0
- package/.claude/skills/canvas-design/SKILL.md +130 -0
- package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/.claude/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/.claude/skills/changelog-generator/SKILL.md +104 -0
- package/.claude/skills/cleanup-health-inline/SKILL.md +224 -0
- package/.claude/skills/code-reviewer/SKILL.md +209 -0
- package/.claude/skills/code-reviewer/references/code_review_checklist.md +103 -0
- package/.claude/skills/code-reviewer/references/coding_standards.md +103 -0
- package/.claude/skills/code-reviewer/references/common_antipatterns.md +103 -0
- package/.claude/skills/code-reviewer/scripts/code_quality_checker.py +114 -0
- package/.claude/skills/code-reviewer/scripts/pr_analyzer.py +114 -0
- package/.claude/skills/code-reviewer/scripts/review_report_generator.py +114 -0
- package/.claude/skills/content-research-writer/SKILL.md +538 -0
- package/.claude/skills/deps-health-inline/SKILL.md +227 -0
- package/.claude/skills/frontend-aesthetics/SKILL.md +51 -396
- package/.claude/skills/git-commit-helper/SKILL.md +203 -0
- package/.claude/skills/lead-research-assistant/SKILL.md +199 -0
- package/.claude/skills/reuse-health-inline/SKILL.md +248 -0
- package/.claude/skills/rollback-changes/SKILL.md +50 -524
- package/.claude/skills/run-quality-gate/SKILL.md +36 -346
- package/.claude/skills/security-health-inline/SKILL.md +224 -0
- package/.claude/skills/senior-architect/SKILL.md +209 -0
- package/.claude/skills/senior-architect/references/architecture_patterns.md +755 -0
- package/.claude/skills/senior-architect/references/system_design_workflows.md +749 -0
- package/.claude/skills/senior-architect/references/tech_decision_guide.md +612 -0
- package/.claude/skills/senior-architect/scripts/architecture_diagram_generator.py +114 -0
- package/.claude/skills/senior-architect/scripts/dependency_analyzer.py +114 -0
- package/.claude/skills/senior-architect/scripts/project_architect.py +114 -0
- package/.claude/skills/senior-devops/SKILL.md +209 -0
- package/.claude/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
- package/.claude/skills/senior-devops/references/deployment_strategies.md +103 -0
- package/.claude/skills/senior-devops/references/infrastructure_as_code.md +103 -0
- package/.claude/skills/senior-devops/scripts/deployment_manager.py +114 -0
- package/.claude/skills/senior-devops/scripts/pipeline_generator.py +114 -0
- package/.claude/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
- package/.claude/skills/senior-prompt-engineer/SKILL.md +226 -0
- package/.claude/skills/senior-prompt-engineer/references/agentic_system_design.md +80 -0
- package/.claude/skills/senior-prompt-engineer/references/llm_evaluation_frameworks.md +80 -0
- package/.claude/skills/senior-prompt-engineer/references/prompt_engineering_patterns.md +80 -0
- package/.claude/skills/senior-prompt-engineer/scripts/agent_orchestrator.py +100 -0
- package/.claude/skills/senior-prompt-engineer/scripts/prompt_optimizer.py +100 -0
- package/.claude/skills/senior-prompt-engineer/scripts/rag_evaluator.py +100 -0
- package/.claude/skills/setup-knip/SKILL.md +372 -0
- package/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/.claude/skills/systematic-debugging/SKILL.md +296 -0
- package/.claude/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/.claude/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/.claude/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/.claude/skills/systematic-debugging/find-polluter.sh +63 -0
- package/.claude/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/.claude/skills/systematic-debugging/test-academic.md +14 -0
- package/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/.claude/skills/theme-factory/LICENSE.txt +202 -0
- package/.claude/skills/theme-factory/SKILL.md +59 -0
- package/.claude/skills/theme-factory/theme-showcase.pdf +0 -0
- package/.claude/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/.claude/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/.claude/skills/theme-factory/themes/desert-rose.md +19 -0
- package/.claude/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/.claude/skills/theme-factory/themes/golden-hour.md +19 -0
- package/.claude/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/.claude/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/.claude/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/.claude/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/.claude/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/.claude/skills/ui-design-system/SKILL.md +32 -0
- package/.claude/skills/ui-design-system/scripts/design_token_generator.py +529 -0
- package/.claude/skills/ux-researcher-designer/SKILL.md +30 -0
- package/.claude/skills/ux-researcher-designer/scripts/persona_generator.py +508 -0
- package/.claude/skills/webapp-testing/LICENSE.txt +202 -0
- package/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
- package/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
- package/.gitignore +4 -0
- package/README.md +492 -1093
- package/README.ru.md +719 -0
- package/docs/Agents Ecosystem/AGENT-ORCHESTRATION.md +2 -2
- package/docs/COMMANDS-GUIDE.md +0 -15
- package/docs/reports/skills/new-skills-analysis-2025-12.md +331 -0
- package/package.json +11 -3
- package/.claude/agents/health/orchestrators/bug-orchestrator.md +0 -1084
- package/.claude/agents/health/orchestrators/dead-code-orchestrator.md +0 -1064
- package/.claude/agents/health/orchestrators/dependency-orchestrator.md +0 -1064
- package/.claude/agents/health/orchestrators/reuse-orchestrator.md +0 -1112
- package/.claude/agents/health/orchestrators/security-orchestrator.md +0 -1064
- package/.claude/commands/worktree-cleanup.md +0 -382
- package/.claude/commands/worktree-create.md +0 -287
- package/.claude/commands/worktree-list.md +0 -239
- package/.claude/commands/worktree-remove.md +0 -339
- package/.claude/project-index.md +0 -75
- package/.claude/skills/load-project-context/SKILL.md +0 -89
- package/.claude/skills/resume-session/SKILL.md +0 -164
- package/.claude/skills/save-session-context/SKILL.md +0 -123
- package/.claude/templates/project-index.template.md +0 -67
- package/.claude/templates/session/context.template.md +0 -40
- package/.claude/templates/session/log.template.md +0 -72
- package/.github/BRANCH_PROTECTION.md +0 -137
- package/.github/workflows/build.yml +0 -70
- package/.github/workflows/deploy-staging.yml +0 -90
- 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
|
|
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
|
-
#
|
|
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
|
-
#
|
|
224
|
-
if [ "$
|
|
343
|
+
# New source files = feature
|
|
344
|
+
if [ "$new_source" -gt 0 ]; then
|
|
225
345
|
commit_type="feat"
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
#
|
|
248
|
-
|
|
249
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
#
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
#
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
#
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
commit_type="docs"
|
|
292
|
-
commit_desc="update documentation"
|
|
293
|
-
fi
|
|
398
|
+
Files changed:
|
|
399
|
+
${FILE_LIST}
|
|
294
400
|
|
|
295
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
350
|
-
COMMITS_RANGE
|
|
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
|
|
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
|
-
|
|
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 < <(
|
|
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
|
-
|
|
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" |
|
|
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" |
|
|
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 |
|
|
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
|
-
|
|
913
|
-
case "$
|
|
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="$
|
|
1283
|
+
bump_arg="$1"
|
|
1284
|
+
shift
|
|
919
1285
|
;;
|
|
920
1286
|
*)
|
|
921
|
-
log_error "Unknown argument: $
|
|
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
|
}
|