Skip to content

fix: installer and banner improvements#37

Merged
maxritter merged 3 commits intomainfrom
dev
Jan 25, 2026
Merged

fix: installer and banner improvements#37
maxritter merged 3 commits intomainfrom
dev

Conversation

@maxritter
Copy link
Copy Markdown
Owner

@maxritter maxritter commented Jan 25, 2026

Summary

  • Verify CCP binary works before running installer (handles macOS Gatekeeper)
  • Auto-trigger dev release on push to dev branch
  • Keep only latest dev pre-release (cleanup old ones)
  • Show actual CCP binary version instead of installer version
  • Reduce verbose installer output (remove "Clearing old..." messages)
  • Simplify trial banner design
  • Add discount messaging to expiration prompts

Test plan

  • All unit tests pass
  • Tested installer on macOS with Gatekeeper
  • Dev pre-release pipeline triggers on push

Summary by CodeRabbit

  • New Features

    • Detects and displays the installed CCP version during finalization; shows “Verifying CCP binary…” and a ready (vX) message.
  • Bug Fixes

    • Improved installer reliability with pre-download cleanup and clearer verification/gatekeeper warning flow on macOS.
    • Shows subscription info and promo code when a trial was already used.
  • Chores

    • Reduced verbose status messages for a cleaner install output.
  • Tests

    • Added unit tests for CCP version detection.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
claude-codepro Ready Ready Preview, Comment Jan 25, 2026 0:16am

@claude
Copy link
Copy Markdown

claude bot commented Jan 25, 2026

Claude finished @maxritter's task in 1m 58s —— View job


Code Review Complete

  • Gather context and read changed files
  • Review workflow changes (.github/workflows/release-dev.yml)
  • Review installer script changes (install.sh)
  • Review Python module changes (ccp/, installer/)
  • Review test changes
  • Provide comprehensive feedback

Summary

This PR improves the installer experience, particularly for macOS users facing Gatekeeper issues, and streamlines the dev release workflow. Overall the changes are well-structured and the test coverage for the new _get_ccp_version function is good.


Workflow Changes (.github/workflows/release-dev.yml)

✅ Good:

  • Adding push trigger on dev branch enables automatic pre-releases
  • Concurrency group with cancel-in-progress: true prevents duplicate runs
  • Keeping only the latest pre-release reduces clutter

⚠️ Minor Consideration:

  • Line 222: The jq expression .[1:] keeps only the latest release. This is aggressive - if a pre-release build fails, there's no fallback. Consider keeping 2-3 recent releases for debugging purposes.

Install Script Changes (install.sh)

✅ Good:

  • Moving Gatekeeper verification earlier (before running installer) is a good UX improvement - fail fast
  • Using spctl --add to whitelist binaries is appropriate
  • Extracting the actual CCP version from the binary output is more accurate than showing installer version

⚠️ Observations:

  1. Lines 372-377 - Binary verification logic:
ccp_version=$("$wrapper_path" --version 2>/dev/null) || true

if [ -z "$ccp_version" ] && [ "$(uname -s)" = "Darwin" ]; then
    echo "  [..] Removing macOS quarantine attributes..."

The || true swallows errors, which is fine, but the empty check then triggers quarantine removal. This is good defensive coding.

  1. Lines 378-380 - Using both xattr -cr and spctl --add:
xattr -cr "$bin_dir" 2>/dev/null || true
spctl --add "$wrapper_path" 2>/dev/null || true
spctl --add "$so_path" 2>/dev/null || true

Both approaches have different effects - xattr removes quarantine, spctl adds to approved list. Having both is belt-and-suspenders, which is appropriate for user experience.

  1. Lines 52-53 - Minor: The trailing \ removed from pipe continuation:
echo "$releases" | tr ',' '\n' | grep -E '"(tag_name|created_at)"' | paste - - |
    grep 'dev-' | sed 's/.*"created_at"[^"]*"\([^"]*\)".*"tag_name"[^"]*"\([^"]*\)".*/\1|\2/' |

Using | at end of line for continuation is valid but less common than \. Both work, just a style note.

  1. Lines 327-329 - Cleaning bin directory before download:
if [ -d "$bin_dir" ]; then
    rm -rf "$bin_dir"
fi

Good - ensures clean state on reinstall.


Python Changes

installer/cli.py

✅ Good:
Adding discount messaging to the trial-already-used error is good for conversion:

console.print("  [cyan]Subscribe at: https://license.claude-code.pro[/cyan]")
console.print("  [bold green]Use code TRIAL50OFF for 50% off your first month![/bold green]")

installer/steps/claude_files.py

✅ Good:
Removing verbose "Clearing old..." status messages reduces noise. The operations still happen, just silently.

installer/steps/finalize.py

✅ Good:

  • The _get_ccp_version() function is well-structured with proper fallback
  • Timeout of 5 seconds is reasonable
  • Regex r"CodePro v(.+)$" correctly captures the version suffix

Minor observation:

  • Line 29: Catching bare Exception is broad but acceptable here since this is a best-effort version extraction with fallback behavior.

installer/steps/shell_config.py

✅ Good:
Removing "already configured" info messages reduces noise. The logic is preserved, just silent when no action needed.


Test Changes (installer/tests/unit/steps/test_finalize.py)

✅ Excellent:

  • Tests cover the three main scenarios: normal version, dev version, fallback
  • Proper mocking of subprocess.run and Path.cwd
  • Creating actual file structure in temp directory for realistic tests

Minor observation:

  • Tests create a fake ccp binary file but the content is irrelevant since subprocess.run is mocked. The file existence check happens before the mock takes effect. This works correctly but the file content could be empty.

Encrypted Files

The following files are git-crypt encrypted and cannot be reviewed:

  • ccp/banner.py
  • ccp/cli.py
  • ccp/wrapper.py
  • ccp/tests/unit/test_wrapper.py

Based on the PR description mentioning "Simplify trial banner design" and "Add discount messaging to expiration prompts", I trust these changes align with the stated goals.


Overall Assessment

Approve - The changes are well-implemented and improve the user experience, particularly for macOS users. The test coverage for new functionality is adequate. The workflow changes will streamline the dev release process.

Suggestions (non-blocking):

  1. Consider keeping 2-3 recent pre-releases instead of just 1 for debugging fallback
  2. Consider adding a test case for _get_ccp_version when subprocess times out

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 25, 2026

📝 Walkthrough

Walkthrough

Moves macOS Gatekeeper remediation into the CCP binary verification path, adds runtime CCP version detection, tightens prerelease cleanup to keep only the newest prerelease, and removes several redundant user-facing status messages across installer steps.

Changes

Cohort / File(s) Summary
Workflow release pipeline
/.github/workflows/release-dev.yml
Adds a push trigger for the dev branch, introduces a dev-prerelease concurrency group with cancel-in-progress: true, updates messaging to state only the latest prerelease is kept, and changes jq cleanup to delete all prereleases except the newest.
Installer shell script
install.sh
Renames show_macos_gatekeeper_helpshow_macos_gatekeeper_warning; moves Gatekeeper/quarantine handling into CCP verification; adds pre-download bin cleanup; introduces explicit "Verifying CCP binary…" and "ready (vX)" messages; changes download/build URL selection for dev tags; removes final post-install Gatekeeper invocation.
Finalize step / version detection
installer/steps/finalize.py
Adds _get_ccp_version() using subprocess, re, and Path to extract CCP version from the installed binary and falls back to the package __version__; FinalizeStep._display_success now uses this detected version.
CLI messaging
installer/cli.py
In _run_trial_start(), when trial_already_used is returned, prints a subscription URL and TRIAL50OFF promo code.
Installer step UI trimming
installer/steps/claude_files.py, installer/steps/shell_config.py
Removes several idempotent-status user messages (clearing/migrating directories, fzf/dotenv/bun/zsh "already configured" notices) while preserving underlying behavior and return values; some messages now gated by quiet.
Tests
installer/tests/unit/steps/test_finalize.py
Adds TestGetCcpVersion suite (3 tests) covering version extraction from CCP binary (normal and dev strings) and fallback to package version when binary is absent; adds MagicMock usage.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(200,200,255,0.5)
    actor User
    participant InstallerScript as Installer
    participant Downloader as Downloader
    participant CCPBinary as "CCP Binary"
    participant Gatekeeper as Gatekeeper/spctl
  end

  User->>InstallerScript: run install.sh
  InstallerScript->>Downloader: prepare bin dir and download wrapper
  Downloader-->>InstallerScript: wrapper downloaded
  InstallerScript->>CCPBinary: execute wrapper to detect version
  alt version extracted
    CCPBinary-->>InstallerScript: prints "CodePro vX.Y.Z" or dev tag
    InstallerScript->>User: "Verifying CCP binary…" and "ready (vX.Y.Z)"
  else extraction fails on macOS
    InstallerScript->>Gatekeeper: display Gatekeeper/quarantine warning
    Gatekeeper-->>User: remediation instructions (user action)
    InstallerScript->>InstallerScript: exit with failure
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through install logs bright and merry,

Gatekeeper nudged, I gave a small worry,
I checked the CCP, its version I found,
Quieted messages left the logs sound,
One prerelease kept — and I twitched my whiskery!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is partially related to the changeset. While it mentions 'installer improvements,' the changes encompass much broader modifications: workflow automation, CCP binary verification, version display updates, and message reduction across multiple components. The title does not capture the main aspects like dev release automation or Gatekeeper handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown

claude bot commented Jan 25, 2026

Claude finished @maxritter's task in 1m 19s —— View job


Code Review Complete

  • Gather context and read changed files
  • Review workflow changes (.github/workflows/release-dev.yml)
  • Review installer script changes (install.sh)
  • Review Python module changes (installer/)
  • Review test changes
  • Provide comprehensive feedback

Summary

This PR improves the installer experience, particularly for macOS users facing Gatekeeper issues, and streamlines the dev release workflow. The changes are well-structured with good test coverage for the new _get_ccp_version function.


Workflow Changes (.github/workflows/release-dev.yml)

✅ Good:

  • Adding push trigger on dev branch enables automatic pre-releases
  • Concurrency group with cancel-in-progress: true prevents duplicate runs
  • Keeping only the latest pre-release reduces clutter

⚠️ Minor Consideration:

  • Line 222: The jq expression .[1:] keeps only the latest release. This is aggressive - if a pre-release build fails, there's no fallback. Consider keeping 2-3 recent releases for debugging purposes:
    # Keep latest 3 instead of just 1
    --jq '[...] | .[3:] | .[].tag_name'

Install Script Changes (install.sh)

✅ Good:

  • Moving Gatekeeper verification earlier (before running installer) is a good UX improvement - fail fast
  • Using both xattr -cr and spctl --add is belt-and-suspenders approach appropriate for user experience
  • Extracting actual CCP version from binary output is more accurate than showing installer version
  • Cleaning bin directory before download (rm -rf "$bin_dir" at lines 322-324) ensures clean state

Observations:

  1. Lines 366-375 - Binary verification logic is well-structured:

    ccp_version=$("$wrapper_path" --version 2>/dev/null) || true
    if [ -z "$ccp_version" ] && [ "$(uname -s)" = "Darwin" ]; then
        # Try quarantine removal, then retry
    fi

    The || true prevents script exit on failure while still detecting empty output.

  2. Lines 387-396 - Version extraction:

    installed_version=$(echo "$ccp_version" | sed -n 's/.*CodePro v\(.*\)/\1/p')

    Handles both v5.2.3 and vdev-xxx formats correctly.


Python Changes

installer/cli.py (Lines 124-125)

✅ Good:
Adding discount messaging to the trial-already-used error improves conversion:

console.print("  [cyan]Subscribe at: https://license.claude-code.pro[/cyan]")
console.print("  [bold green]Use code TRIAL50OFF for 50% off your first month![/bold green]")

installer/steps/finalize.py (Lines 14-31)

✅ Good:

  • The _get_ccp_version() function is well-structured with proper fallback
  • Timeout of 5 seconds is reasonable
  • Regex r"CodePro v(.+)$" correctly captures the version suffix

Minor observation:

  • Line 29: Catching bare Exception is broad but acceptable here since this is a best-effort version extraction with defined fallback behavior.

installer/steps/claude_files.py & installer/steps/shell_config.py

✅ Good:
Removing verbose "Clearing old..." and "already configured" status messages reduces noise while preserving the actual operations.


Test Changes (installer/tests/unit/steps/test_finalize.py)

✅ Excellent:

  • Tests cover the three main scenarios: normal version, dev version, fallback
  • Proper mocking of subprocess.run and Path.cwd
  • Creating actual file structure in temp directory for realistic tests

Suggestions (non-blocking):

  1. Consider adding a test case for _get_ccp_version when subprocess times out
  2. Consider adding a test for malformed output (when regex doesn't match)

Encrypted Files

The following files are git-crypt encrypted and cannot be reviewed:

  • ccp/banner.py
  • ccp/cli.py
  • ccp/wrapper.py
  • ccp/utils.py
  • ccp/tests/unit/test_wrapper.py

Based on the PR description mentioning "Simplify trial banner design" and "Add discount messaging to expiration prompts", I trust these changes align with the stated goals.


Overall Assessment

Approve

The changes are well-implemented and improve the user experience, particularly for macOS users. The test coverage for new functionality is adequate. The workflow changes will streamline the dev release process.

Summary of Suggestions (all non-blocking):

  1. Consider keeping 2-3 recent pre-releases instead of just 1 for debugging fallback
  2. Consider adding timeout test case for _get_ccp_version
  3. Consider adding malformed output test case

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@install.sh`:
- Around line 53-55: The current pipeline that extracts the latest dev
prerelease assumes "created_at" precedes "tag_name" in the pasted pairs (the sed
call in the pipeline), which fails because GitHub returns "tag_name" first;
update the parsing step (the sed expression after paste - -) to handle either
ordering (e.g., match "tag_name" and "created_at" in any order or use an
order-agnostic extractor such as an awk/while-read pair that extracts the values
by key) so the pipeline reliably produces VERSION; specifically modify the
sed/parse logic used right after paste - - (the sed 's/.*"created_at"...' part)
to extract both tag_name and created_at regardless of which appears first.

- Verify CCP binary before running installer
- Auto-trigger dev release on push, keep only latest pre-release
- Show CCP binary version instead of installer version
- Reduce verbose installer output
- Improve banner design for trial users
- Add discount messaging to expiration prompts
@claude
Copy link
Copy Markdown

claude bot commented Jan 25, 2026

Claude finished @maxritter's task in 1m 16s —— View job


Code Review Complete

  • Read changed files and gather context
  • Review workflow changes (.github/workflows/release-dev.yml)
  • Review installer script (install.sh)
  • Review Python changes (installer/)
  • Review test changes
  • Address CodeRabbit's finding on sed parsing order
  • Provide comprehensive feedback

Summary

This PR improves installer reliability and UX. The changes are well-structured with good test coverage. However, there's a critical bug in the dev prerelease parsing that must be fixed before merging.


🔴 Critical Issue: Sed Parsing Bug in install.sh

File: install.sh:53-55

CodeRabbit correctly identified that the sed expression assumes created_at precedes tag_name in the pasted pairs, but GitHub's API returns tag_name first.

# Current (broken):
sed 's/.*"created_at"[^"]*"\([^"]*\)".*"tag_name"[^"]*"\([^"]*\)".*/\1|\2/'

# Fixed (handles actual field order):
sed -n 's/.*"tag_name"[^"]*"\([^"]*\)".*"created_at"[^"]*"\([^"]*\)".*/\2|\1/p'

This will cause --dev installs to fail silently with an empty VERSION variable.

Fix this →


Workflow Changes (.github/workflows/release-dev.yml)

✅ Good:

  • Push trigger on dev branch enables automatic pre-releases
  • Concurrency group with cancel-in-progress: true prevents duplicate runs

⚠️ Minor Consideration (Line 222):
The jq expression .[1:] keeps only the latest release. If a pre-release build fails, there's no fallback. Consider keeping 2-3 recent releases:

# Keep latest 3 instead of just 1
--jq '[...] | .[3:] | .[].tag_name'

Install Script (install.sh)

✅ Good:

  • Lines 365-385: Moving Gatekeeper verification earlier is excellent UX - fail fast before running the installer
  • Lines 371-373: Belt-and-suspenders approach using both xattr -cr and spctl --add is appropriate
  • Lines 322-324: Cleaning bin directory before download ensures clean reinstall state
  • Lines 387-396: Version extraction correctly handles both v5.2.3 and vdev-xxx formats

Clean implementation of macOS security handling:

ccp_version=$("$wrapper_path" --version 2>/dev/null) || true
if [ -z "$ccp_version" ] && [ "$(uname -s)" = "Darwin" ]; then
    # Remediation then retry
fi

Python Changes

installer/steps/finalize.py (Lines 14-31)

✅ Good:

  • Well-structured _get_ccp_version() with proper fallback
  • Timeout of 5 seconds is reasonable
  • Regex r"CodePro v(.+)$" correctly captures version suffix

Minor observation: Line 29 catches bare Exception but this is acceptable for best-effort version extraction with defined fallback.

installer/cli.py (Lines 124-125)

✅ Good: Adding discount messaging improves conversion:

console.print("  [cyan]Subscribe at: https://license.claude-code.pro[/cyan]")
console.print("  [bold green]Use code TRIAL50OFF for 50% off your first month![/bold green]")

installer/steps/claude_files.py & installer/steps/shell_config.py

✅ Good: Removing verbose "Clearing old..." and "already configured" messages reduces noise while preserving functionality.


Test Changes (installer/tests/unit/steps/test_finalize.py)

✅ Excellent:

  • Tests cover three scenarios: normal version, dev version, fallback
  • Proper mocking of subprocess.run and Path.cwd
  • Creates actual file structure in temp directory for realistic tests

Suggestions (non-blocking):

  1. Consider adding a timeout test case for _get_ccp_version
  2. Consider adding a malformed output test case (when regex doesn't match)

Encrypted Files

The following files are git-crypt encrypted and cannot be reviewed:

  • ccp/banner.py, ccp/cli.py, ccp/wrapper.py, ccp/utils.py
  • ccp/tests/unit/test_wrapper.py

Based on the PR description, I trust these align with "Simplify trial banner design" and "Add discount messaging to expiration prompts".


Overall Assessment

Approve with required fix

The sed parsing bug must be fixed before merging. Once resolved, this PR is ready.

Summary of required changes:

  1. 🔴 Fix sed parsing order in install.sh:53-55 (critical)

Summary of suggestions (non-blocking):

  1. Consider keeping 2-3 recent pre-releases instead of just 1
  2. Consider adding timeout/malformed output test cases

- ASCII art now shows for all tiers with orange/cyan colors
- Added tagline and subtitle below banner
- Added 50ms delay after clear_terminal for terminal sync
- Fixed test_build.py to mock reset_build_timestamp (was writing to real file)
@claude
Copy link
Copy Markdown

claude bot commented Jan 25, 2026

Claude finished @maxritter's task in 1m 20s —— View job


Code Review Complete

  • Gather context and read changed files
  • Review workflow changes (.github/workflows/release-dev.yml)
  • Review installer script changes (install.sh)
  • Review Python module changes (installer/)
  • Review test changes
  • Verify CodeRabbit's sed parsing issue
  • Provide comprehensive feedback

Summary

This PR improves the installer experience with better macOS Gatekeeper handling, version detection, and streamlined dev release workflow. The changes are well-structured with good test coverage. However, there is a critical bug that must be fixed before merging.


🔴 Critical Issue: Sed Parsing Order in install.sh

File: install.sh:53-55

CodeRabbit correctly identified that the sed expression assumes created_at precedes tag_name, but GitHub's API returns tag_name first:

# Current (broken) - expects created_at before tag_name:
sed 's/.*"created_at"[^"]*"\([^"]*\)".*"tag_name"[^"]*"\([^"]*\)".*/\1|\2/'

# Fixed - handles actual field order:
sed -n 's/.*"tag_name"[^"]*"\([^"]*\)".*"created_at"[^"]*"\([^"]*\)".*/\2|\1/p'

This will cause --dev installs to fail silently with an empty VERSION variable.

Fix this →


Workflow Changes (.github/workflows/release-dev.yml)

✅ Good:

  • Push trigger on dev branch enables automatic pre-releases (lines 5-7)
  • Concurrency group with cancel-in-progress: true prevents duplicate runs (lines 10-12)
  • Keeping only the latest pre-release reduces clutter

⚠️ Minor Consideration (Line 222):
The jq expression .[1:] keeps only the latest release. If a pre-release build fails, there's no fallback. Consider keeping 2-3 recent releases:

# Keep latest 3 instead of just 1
--jq '[...] | .[3:] | .[].tag_name'

Install Script (install.sh)

✅ Good:

  • Lines 322-324: Cleaning bin directory before download ensures clean reinstall state
  • Lines 365-385: Moving Gatekeeper verification earlier (before running installer) is excellent UX - fail fast
  • Lines 371-373: Belt-and-suspenders approach using both xattr -cr and spctl --add is appropriate
  • Lines 387-396: Version extraction correctly handles both v5.2.3 and vdev-xxx formats

Clean implementation of macOS security handling (lines 366-385):

ccp_version=$("$wrapper_path" --version 2>/dev/null) || true
if [ -z "$ccp_version" ] && [ "$(uname -s)" = "Darwin" ]; then
    # Remediation then retry
fi

Python Changes

installer/steps/finalize.py (Lines 14-31)

✅ Good:

  • Well-structured _get_ccp_version() with proper fallback to __version__
  • Timeout of 5 seconds is reasonable for subprocess call
  • Regex r"CodePro v(.+)$" correctly captures version suffix

Minor observation: Line 29 catches bare Exception but this is acceptable for best-effort version extraction with defined fallback.

installer/cli.py (Lines 124-125)

✅ Good: Adding discount messaging improves conversion:

console.print("  [cyan]Subscribe at: https://license.claude-code.pro[/cyan]")
console.print("  [bold green]Use code TRIAL50OFF for 50% off your first month![/bold green]")

installer/steps/claude_files.py & installer/steps/shell_config.py

✅ Good: Removing verbose "Clearing old..." and "already configured" messages reduces noise while preserving functionality.


Test Changes (installer/tests/unit/steps/test_finalize.py)

✅ Excellent:

  • Tests cover three scenarios: normal version, dev version, fallback (lines 16-65)
  • Proper mocking of subprocess.run and Path.cwd
  • Creates actual file structure in temp directory for realistic tests

Suggestions (non-blocking):

  1. Consider adding a timeout test case for _get_ccp_version
  2. Consider adding a malformed output test case (when regex doesn't match)

Encrypted Files

The following files are git-crypt encrypted and cannot be reviewed:

  • ccp/banner.py, ccp/cli.py, ccp/wrapper.py, ccp/utils.py
  • ccp/tests/unit/test_wrapper.py

Based on the PR description, I trust these align with "Simplify trial banner design" and "Add discount messaging to expiration prompts".


Overall Assessment

Approve with required fix

The sed parsing bug must be fixed before merging. Once resolved, this PR is ready.

Required:

  1. 🔴 Fix sed parsing order in install.sh:53-55

Suggestions (non-blocking):

  1. Consider keeping 2-3 recent pre-releases instead of just 1
  2. Consider adding timeout/malformed output test cases for _get_ccp_version

@claude
Copy link
Copy Markdown

claude bot commented Jan 25, 2026

Claude finished @maxritter's task in 1m 5s —— View job


Code Review Complete

  • Gather context and read changed files
  • Review workflow changes (.github/workflows/release-dev.yml)
  • Review installer script changes (install.sh)
  • Review Python module changes (installer/)
  • Review test changes
  • Verify sed parsing fix (commit 37bf0a1)
  • Provide comprehensive feedback

Summary

This PR improves the installer experience with better macOS Gatekeeper handling, version detection, and streamlined dev release workflow. The changes are well-structured with good test coverage.


✅ Sed Parsing Fix Verified

Commit 37bf0a1 correctly addresses the field order issue identified by CodeRabbit. The sed expression now matches GitHub's actual field order where tag_name comes before created_at:

# Fixed (install.sh:54):
sed 's/.*"tag_name"[^"]*"\([^"]*\)".*"created_at"[^"]*"\([^"]*\)".*/\2|\1/'

Workflow Changes (.github/workflows/release-dev.yml)

✅ Good:

  • Push trigger on dev branch enables automatic pre-releases (lines 5-7)
  • Concurrency group with cancel-in-progress: true prevents duplicate runs (lines 10-12)
  • Keeping only the latest pre-release reduces clutter

⚠️ Minor Consideration (Line 222):
The jq expression .[1:] keeps only the latest release. If a pre-release build fails, there's no fallback. Consider keeping 2-3 recent releases:

# Keep latest 3 instead of just 1
--jq '[...] | .[3:] | .[].tag_name'

Install Script (install.sh)

✅ Good:

  • Lines 322-324: Cleaning bin directory before download ensures clean reinstall state
  • Lines 365-385: Moving Gatekeeper verification earlier (before running installer) is excellent UX - fail fast
  • Lines 371-373: Belt-and-suspenders approach using both xattr -cr and spctl --add is appropriate
  • Lines 387-396: Version extraction correctly handles both v5.2.3 and vdev-xxx formats

Clean implementation of macOS security handling (lines 366-385):

ccp_version=$("$wrapper_path" --version 2>/dev/null) || true
if [ -z "$ccp_version" ] && [ "$(uname -s)" = "Darwin" ]; then
    # Remediation then retry
fi

Python Changes

installer/steps/finalize.py (Lines 14-31)

✅ Good:

  • Well-structured _get_ccp_version() with proper fallback to __version__
  • Timeout of 5 seconds is reasonable for subprocess call
  • Regex r"CodePro v(.+)$" correctly captures version suffix

Minor observation: Line 29 catches bare Exception but this is acceptable for best-effort version extraction with defined fallback.

installer/cli.py (Lines 124-125)

✅ Good: Adding discount messaging improves conversion:

console.print("  [cyan]Subscribe at: https://license.claude-code.pro[/cyan]")
console.print("  [bold green]Use code TRIAL50OFF for 50% off your first month![/bold green]")

Test Changes (installer/tests/unit/steps/test_finalize.py)

✅ Excellent:

  • Tests cover three scenarios: normal version, dev version, fallback (lines 16-65)
  • Proper mocking of subprocess.run and Path.cwd
  • Creates actual file structure in temp directory for realistic tests

Suggestions (non-blocking):

  1. Consider adding a timeout test case for _get_ccp_version
  2. Consider adding a malformed output test case (when regex doesn't match)

Encrypted Files

The following files are git-crypt encrypted and cannot be reviewed:

  • ccp/banner.py, ccp/cli.py, ccp/wrapper.py, ccp/utils.py
  • ccp/tests/unit/test_wrapper.py

Based on the PR description, I trust these align with "Simplify trial banner design" and "Add discount messaging to expiration prompts".


Overall Assessment

Approve

All changes are well-implemented. The critical sed parsing bug has been fixed. The test coverage for new functionality is adequate.

Summary of suggestions (non-blocking):

  1. Consider keeping 2-3 recent pre-releases instead of just 1 for debugging fallback
  2. Consider adding timeout/malformed output test cases for _get_ccp_version

@maxritter maxritter merged commit f740ad2 into main Jan 25, 2026
8 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 5.2.4 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant