Cross-Platform CLI Setup
Implementation guide for cross-platform CLI binary distribution and installation
Overview
The @unhook/cli
package has been enhanced to work seamlessly across all major platforms (macOS, Windows, Linux, ARM/x64) using a hybrid approach that downloads platform-specific binaries during installation.
Architecture
Build System
- GitHub Actions: Builds binaries for all supported platforms
- Release Assets: Uploads binaries to GitHub releases with standardized naming
- Platforms Supported:
linux-x64
(glibc)linux-arm64
(glibc)linux-x64-musl
(Alpine Linux)linux-arm64-musl
(Alpine Linux ARM64)darwin-x64
(macOS Intel)darwin-arm64
(macOS Apple Silicon)win32-x64
(Windows 64-bit)
Installation Flow
Package Installation
User runs npm install @unhook/cli
Postinstall Hook
scripts/install.cjs
executes automatically
Platform Detection
Detects OS, architecture, and libc variant (musl vs glibc)
Binary Download
Downloads appropriate binary from GitHub releases
Installation
Stores binary in ~/.unhook/bin/{version}/
with proper permissions
Runtime Flow
Command Execution
User runs unhook [command]
Wrapper Execution
bin/cli.cjs
wrapper script executes
Binary Location
Wrapper detects platform and locates downloaded binary
Transparent Execution
Spawns platform-specific binary with user arguments
Result Return
Returns binary exit code transparently to user
File Structure
Implementation Details
Platform Detection
The CLI intelligently detects the target platform and architecture:
Binary Naming Convention
Binaries follow this pattern: unhook-{platform}-{arch}[.exe]
macOS Examples
unhook-darwin-arm64
(Apple Silicon)unhook-darwin-x64
(Intel)
Linux Examples
unhook-linux-x64
(glibc)unhook-linux-x64-musl
(Alpine)unhook-linux-arm64
(ARM64 glibc)unhook-linux-arm64-musl
(ARM64 Alpine)
Windows Examples
unhook-win32-x64.exe
(64-bit)
Version Management
- Binaries are stored in versioned directories:
~/.unhook/bin/{version}/
- Old versions are automatically cleaned up during installation
- Multiple versions can coexist temporarily during upgrades
Edge Cases & Robustness
Network Issues
Platform-Specific Handling
Security (Gatekeeper):
Code Signing: macOS binaries are signed and notarized during CI
Security (Gatekeeper):
Code Signing: macOS binaries are signed and notarized during CI
Libc Detection:
Variants: Support both glibc and musl variants for Alpine Linux compatibility
Executable Extensions:
Permission Handling: Windows-specific permission management
CI/CD Environments
Problem: CI systems shouldn’t download binaries during installation
Solution:
Testing Strategy
Integration Tests
Comprehensive test suite covering:
- Platform Detection: Verify correct platform/arch identification
- URL Construction: Ensure proper download URLs
- Error Handling: Test failure scenarios
- Package Configuration: Validate package.json settings
- Platform-Specific Behavior: Test OS-specific features
Test Execution
Troubleshooting
Performance Considerations
One-time Download
Binaries are cached locally after first install
Version Management
Only current version kept, old versions cleaned up
Efficient Detection
Fast platform/arch detection using Node.js APIs
Minimal Overhead
CLI wrapper adds ~10ms startup time
Security Considerations
All security measures are implemented to ensure safe binary distribution:
- Verified Downloads: Binaries downloaded from official GitHub releases only
- Code Signing: macOS binaries are signed and notarized
- No Build Tools Required: Users don’t need compilers or build chains
- Quarantine Removal: Automatic handling of macOS security restrictions
Future Enhancements
- Checksum Verification: Verify binary integrity using SHA checksums
- Delta Updates: Only download changed parts of binaries
- Mirror Support: Allow alternative download sources
- Offline Mode: Bundle common binaries with the package
- Auto-updates: Automatic binary updates when package is updated
Contributing
When adding support for new platforms:
Update CI
Update the GitHub Actions workflow (.github/workflows/cli-github-release.yml
)
Add Platform Mapping
Add platform mapping in both install.cjs
and cli.cjs
Update Documentation
Update documentation and tests
Test on Platform
Test on the target platform before releasing