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

1

Package Installation

User runs npm install @unhook/cli

2

Postinstall Hook

scripts/install.cjs executes automatically

3

Platform Detection

Detects OS, architecture, and libc variant (musl vs glibc)

4

Binary Download

Downloads appropriate binary from GitHub releases

5

Installation

Stores binary in ~/.unhook/bin/{version}/ with proper permissions

Runtime Flow

1

Command Execution

User runs unhook [command]

2

Wrapper Execution

bin/cli.cjs wrapper script executes

3

Binary Location

Wrapper detects platform and locates downloaded binary

4

Transparent Execution

Spawns platform-specific binary with user arguments

5

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

Platform Detection

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

Platform-Specific Handling

Security (Gatekeeper):

// Remove quarantine attribute
execSync(`xattr -d com.apple.quarantine "${binPath}"`, { stdio: 'ignore' });

Code Signing: macOS binaries are signed and notarized during CI

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:

  1. Platform Detection: Verify correct platform/arch identification
  2. URL Construction: Ensure proper download URLs
  3. Error Handling: Test failure scenarios
  4. Package Configuration: Validate package.json settings
  5. 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

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

  1. Checksum Verification: Verify binary integrity using SHA checksums
  2. Delta Updates: Only download changed parts of binaries
  3. Mirror Support: Allow alternative download sources
  4. Offline Mode: Bundle common binaries with the package
  5. Auto-updates: Automatic binary updates when package is updated

Contributing

When adding support for new platforms:

1

Update CI

Update the GitHub Actions workflow (.github/workflows/cli-github-release.yml)

2

Add Platform Mapping

Add platform mapping in both install.cjs and cli.cjs

3

Update Documentation

Update documentation and tests

4

Test on Platform

Test on the target platform before releasing

References