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
apps/cli/
├── bin/
│ └── cli.cjs # CommonJS CLI wrapper
├── scripts/
│ └── install.cjs # Installation script
├── tests/
│ └── integration/
│ └── cross-platform.test.ts # Integration tests
├── package.json # Updated configuration
└── README.md # User documentation
Implementation Details
The CLI intelligently detects the target platform and architecture:
const platformMap = { win32: 'win32' , darwin: 'darwin' , linux: 'linux' };
const archMap = { x64: 'x64' , arm64: 'arm64' };
// Linux-specific: Detect musl vs glibc
if ( platform === 'linux' ) {
if ( fs . existsSync ( '/lib/ld-musl-x86_64.so.1' ) ||
fs . existsSync ( '/lib/ld-musl-aarch64.so.1' )) {
targetArch = ` ${ arch } -musl` ;
}
}
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
Problem : Users behind corporate firewalls or with poor connectivity
Solution :
Respect HTTP_PROXY
, HTTPS_PROXY
environment variables
30-second timeout with clear error messages
Graceful fallback with manual install instructions
request . setTimeout ( 30000 , () => {
console . error ( '❌ Download timeout: The download took too long. Please try again.' );
process . exit ( 1 );
});
Problem : Users without write permissions to home directory
Solution :
Clear error messages with specific instructions
Platform-specific guidance (sudo on Linux/macOS, admin on Windows)
Alternative installation paths suggested
Security (Gatekeeper) :
// Remove quarantine attribute
execSync ( `xattr -d com.apple.quarantine " ${ binPath } "` , { stdio: 'ignore' });
Code Signing : macOS binaries are signed and notarized during CI
Security (Gatekeeper) :
// Remove quarantine attribute
execSync ( `xattr -d com.apple.quarantine " ${ binPath } "` , { stdio: 'ignore' });
Code Signing : macOS binaries are signed and notarized during CI
Libc Detection :
// Detect musl by checking for loader
if ( fs . existsSync ( '/lib/ld-musl-x86_64.so.1' )) {
targetArch = ` ${ arch } -musl` ;
}
Variants : Support both glibc and musl variants for Alpine Linux compatibility
Executable Extensions :
const ext = os . platform () === 'win32' ? '.exe' : '' ;
Permission Handling : Windows-specific permission management
CI/CD Environments
Problem : CI systems shouldn’t download binaries during installation
Solution :
// Skip installation in CI
if ( require ( 'is-ci' )) {
process . exit ( 0 );
}
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
# Run all integration tests
bun test tests/integration/cross-platform.test.ts
# Run with coverage
bun test --coverage tests/integration/
Troubleshooting
"Binary not found" errors
# Force reinstall
npm install @unhook/cli --force
# Manual install
node ./node_modules/@unhook/cli/scripts/install.cjs
Permission denied on Linux/macOS
chmod +x ~/.unhook/bin/ * /unhook- *
xattr -d com.apple.quarantine ~/.unhook/bin/ * /unhook-darwin- *
export HTTP_PROXY = http :// proxy . company . com : 8080
export HTTPS_PROXY = http :// proxy . company . com : 8080
npm install @unhook/cli
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
References
Responses are generated using AI and may contain mistakes.