66#
77# Options:
88# --dry-run Run all steps except creating the GitHub release
9+ # --local Build for local testing only (no GitHub checks, no changelog prompts)
10+ # --install Install locally after building (only with --local)
11+ # --skip-verify Skip end-to-end verification tests (faster local builds)
912#
1013# Examples:
1114# ./apps/cli/scripts/release.sh # Use version from package.json
1215# ./apps/cli/scripts/release.sh 0.1.0 # Specify version
1316# ./apps/cli/scripts/release.sh --dry-run # Test the release flow without pushing
1417# ./apps/cli/scripts/release.sh --dry-run 0.1.0 # Dry run with specific version
18+ # ./apps/cli/scripts/release.sh --local # Build for local testing
19+ # ./apps/cli/scripts/release.sh --local --install # Build and install locally
20+ # ./apps/cli/scripts/release.sh --local --skip-verify # Fast local build
1521#
1622# This script:
1723# 1. Builds the extension and CLI
1824# 2. Creates a tarball for the current platform
19- # 3. Creates a GitHub release and uploads the tarball (unless --dry-run)
25+ # 3. Creates a GitHub release and uploads the tarball (unless --dry-run or --local )
2026#
2127# Prerequisites:
22- # - GitHub CLI (gh) installed and authenticated
28+ # - GitHub CLI (gh) installed and authenticated (not needed for --local)
2329# - pnpm installed
2430# - Run from the monorepo root directory
2531
2632set -e
2733
2834# Parse arguments
2935DRY_RUN=false
36+ LOCAL_BUILD=false
37+ LOCAL_INSTALL=false
38+ SKIP_VERIFY=false
3039VERSION_ARG=" "
3140
3241while [[ $# -gt 0 ]]; do
@@ -35,6 +44,18 @@ while [[ $# -gt 0 ]]; do
3544 DRY_RUN=true
3645 shift
3746 ;;
47+ --local)
48+ LOCAL_BUILD=true
49+ shift
50+ ;;
51+ --install)
52+ LOCAL_INSTALL=true
53+ shift
54+ ;;
55+ --skip-verify)
56+ SKIP_VERIFY=true
57+ shift
58+ ;;
3859 -* )
3960 echo " Unknown option: $1 " >&2
4061 exit 1
@@ -46,6 +67,12 @@ while [[ $# -gt 0 ]]; do
4667 esac
4768done
4869
70+ # Validate option combinations
71+ if [ " $LOCAL_INSTALL " = true ] && [ " $LOCAL_BUILD " = false ]; then
72+ echo " Error: --install can only be used with --local" >&2
73+ exit 1
74+ fi
75+
4976# Colors
5077RED=' \033[0;31m'
5178GREEN=' \033[0;32m'
@@ -88,12 +115,15 @@ detect_platform() {
88115check_prerequisites () {
89116 step " 1/8" " Checking prerequisites..."
90117
91- if ! command -v gh & > /dev/null; then
92- error " GitHub CLI (gh) is not installed. Install it with: brew install gh"
93- fi
94-
95- if ! gh auth status & > /dev/null; then
96- error " GitHub CLI is not authenticated. Run: gh auth login"
118+ # Skip GitHub CLI checks for local builds
119+ if [ " $LOCAL_BUILD " = false ]; then
120+ if ! command -v gh & > /dev/null; then
121+ error " GitHub CLI (gh) is not installed. Install it with: brew install gh"
122+ fi
123+
124+ if ! gh auth status & > /dev/null; then
125+ error " GitHub CLI is not authenticated. Run: gh auth login"
126+ fi
97127 fi
98128
99129 if ! command -v pnpm & > /dev/null; then
@@ -115,7 +145,17 @@ get_version() {
115145 VERSION=$( node -p " require('$CLI_DIR /package.json').version" )
116146 fi
117147
118- # Validate semver format
148+ # For local builds, append a local suffix with git short hash
149+ # This creates versions like: 0.1.0-local.abc1234
150+ if [ " $LOCAL_BUILD " = true ]; then
151+ GIT_SHORT_HASH=$( git rev-parse --short HEAD 2> /dev/null || echo " unknown" )
152+ # Only append suffix if not already a local version
153+ if ! echo " $VERSION " | grep -qE ' \-local\.' ; then
154+ VERSION=" ${VERSION} -local.${GIT_SHORT_HASH} "
155+ fi
156+ fi
157+
158+ # Validate semver format (allow -local.hash suffix)
119159 if ! echo " $VERSION " | grep -qE ' ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$' ; then
120160 error " Invalid version format: $VERSION (expected semver like 0.1.0)"
121161 fi
@@ -142,6 +182,12 @@ get_changelog_content() {
142182 # Check if the version exists in the changelog
143183 if ! grep -qE " $VERSION_PATTERN " " $CHANGELOG_FILE " ; then
144184 warn " No changelog entry found for version $VERSION "
185+ # Skip prompts for local builds
186+ if [ " $LOCAL_BUILD " = true ]; then
187+ info " Skipping changelog prompt for local build"
188+ CHANGELOG_CONTENT=" "
189+ return
190+ fi
145191 warn " Please add an entry to $CHANGELOG_FILE before releasing"
146192 echo " "
147193 echo " Expected format:"
@@ -220,7 +266,7 @@ create_tarball() {
220266 const pkg = require('$CLI_DIR /package.json');
221267 const newPkg = {
222268 name: '@roo-code/cli',
223- version: pkg.version ,
269+ version: ' $VERSION ' ,
224270 type: 'module',
225271 dependencies: {
226272 '@inkjs/ui': pkg.dependencies['@inkjs/ui'],
@@ -287,8 +333,8 @@ WRAPPER_EOF
287333
288334 chmod +x " $RELEASE_DIR /bin/roo"
289335
290- # Create version file
291- echo " $VERSION " > " $ RELEASE_DIR /VERSION "
336+ # Create empty .env file to suppress dotenvx warnings
337+ touch " $RELEASE_DIR /.env "
292338
293339 # Create empty .env file to suppress dotenvx warnings
294340 touch " $RELEASE_DIR /.env"
@@ -309,6 +355,11 @@ WRAPPER_EOF
309355
310356# Verify local installation
311357verify_local_install () {
358+ if [ " $SKIP_VERIFY " = true ]; then
359+ step " 5/8" " Skipping verification (--skip-verify)"
360+ return
361+ fi
362+
312363 step " 5/8" " Verifying local installation..."
313364
314365 VERIFY_DIR=" $REPO_ROOT /.verify-release"
@@ -566,6 +617,54 @@ print_dry_run_summary() {
566617 echo " "
567618}
568619
620+ # Print local build summary
621+ print_local_summary () {
622+ echo " "
623+ printf " ${GREEN}${BOLD} ✓ Local build complete for v$VERSION ${NC} \n"
624+ echo " "
625+ echo " Tarball: $REPO_ROOT /$TARBALL "
626+ if [ -f " ${TARBALL} .sha256" ]; then
627+ echo " Checksum: $REPO_ROOT /${TARBALL} .sha256"
628+ fi
629+ echo " "
630+ echo " To install manually:"
631+ echo " ROO_LOCAL_TARBALL=$REPO_ROOT /$TARBALL ./apps/cli/install.sh"
632+ echo " "
633+ echo " Or re-run with --install to install automatically:"
634+ echo " ./apps/cli/scripts/release.sh --local --install"
635+ echo " "
636+ }
637+
638+ # Install locally using the install script
639+ install_local () {
640+ step " 7/8" " Installing locally..."
641+
642+ TARBALL_PATH=" $REPO_ROOT /$TARBALL "
643+
644+ ROO_LOCAL_TARBALL=" $TARBALL_PATH " \
645+ ROO_VERSION=" $VERSION " \
646+ " $CLI_DIR /install.sh" || {
647+ error " Local installation failed!"
648+ }
649+
650+ info " Local installation complete!"
651+ }
652+
653+ # Print local install summary
654+ print_local_install_summary () {
655+ echo " "
656+ printf " ${GREEN}${BOLD} ✓ Local build installed for v$VERSION ${NC} \n"
657+ echo " "
658+ echo " Tarball: $REPO_ROOT /$TARBALL "
659+ echo " Installed to: ~/.roo/cli"
660+ echo " Binary: ~/.local/bin/roo"
661+ echo " "
662+ echo " Test it out:"
663+ echo " roo --version"
664+ echo " roo --help"
665+ echo " "
666+ }
667+
569668# Main
570669main () {
571670 echo " "
@@ -576,7 +675,9 @@ main() {
576675 printf " ${NC} "
577676
578677 if [ " $DRY_RUN " = true ]; then
579- printf " ${YELLOW} │ (DRY RUN MODE) │${NC} \n"
678+ printf " ${YELLOW} (DRY RUN MODE)${NC} \n"
679+ elif [ " $LOCAL_BUILD " = true ]; then
680+ printf " ${YELLOW} (LOCAL BUILD MODE)${NC} \n"
580681 fi
581682 echo " "
582683
@@ -589,7 +690,16 @@ main() {
589690 verify_local_install
590691 create_checksum
591692
592- if [ " $DRY_RUN " = true ]; then
693+ if [ " $LOCAL_BUILD " = true ]; then
694+ step " 7/8" " Skipping GitHub checks (local build)"
695+ if [ " $LOCAL_INSTALL " = true ]; then
696+ install_local
697+ print_local_install_summary
698+ else
699+ step " 8/8" " Skipping installation (use --install to auto-install)"
700+ print_local_summary
701+ fi
702+ elif [ " $DRY_RUN " = true ]; then
593703 step " 7/8" " Skipping existing release check (dry run)"
594704 step " 8/8" " Skipping GitHub release creation (dry run)"
595705 print_dry_run_summary
0 commit comments