# VibeTunnel NPM Package Distribution This document explains the npm package build process, native module handling, and prebuild system for VibeTunnel. ## Overview VibeTunnel is distributed as an npm package that includes: - Full web server with terminal sharing capabilities - Native modules for terminal (PTY) and authentication (PAM) support - Cross-platform prebuilt binaries to avoid requiring build tools - Command-line tools (`vibetunnel` and `vt`) ## Package Structure ``` vibetunnel/ ├── dist/ # Compiled server code ├── public/ # Web interface assets ├── bin/ # CLI entry points │ ├── vibetunnel # Main server executable │ └── vt # Terminal wrapper command ├── node-pty/ # Vendored PTY implementation │ ├── lib/ # TypeScript compiled code │ └── package.json # PTY package configuration ├── prebuilds/ # Native module prebuilt binaries │ ├── node-pty-* # PTY binaries for all platforms/Node versions │ └── authenticate-pam-* # PAM binaries for all platforms/Node versions └── README.md # Package documentation ``` ## Native Modules VibeTunnel requires two native modules: ### 1. node-pty (Terminal Support) - **Purpose**: Provides pseudo-terminal (PTY) functionality - **Components**: - `pty.node`: Main Node.js addon for terminal operations - `spawn-helper`: macOS-only C helper binary for process spawning - **Platforms**: All (macOS, Linux) - **Dependencies**: None (vendored implementation) ### 2. authenticate-pam (Authentication) - **Purpose**: PAM (Pluggable Authentication Modules) integration for system authentication - **Components**: - `authenticate_pam.node`: Node.js addon for system authentication - `node_modules/authenticate-pam/`: Full module with package.json, binding.gyp, and source files - **Platforms**: Both macOS and Linux - **Dependencies**: System PAM libraries - **Note**: While macOS uses different authentication mechanisms internally (OpenDirectory), VibeTunnel attempts PAM authentication on both platforms as a fallback after SSH key authentication - **Critical**: The entire authenticate-pam module directory must be included in the npm package, not just the prebuilds ## Prebuild System ### Overview We use `prebuild` and `prebuild-install` to provide precompiled native modules, eliminating the need for users to have build tools installed. ### Coverage - **Node.js versions**: 20, 22, 23, 24 - **Platforms**: macOS (x64, arm64), Linux (x64, arm64) - **Total prebuilds**: 24 binaries - node-pty: 16 binaries (macOS and Linux, all architectures) - authenticate-pam: 8 binaries (Linux only - macOS builds may fail due to PAM differences) ### Prebuild Files ``` prebuilds/ ├── node-pty-v1.0.0-node-v115-darwin-arm64.tar.gz ├── node-pty-v1.0.0-node-v115-darwin-x64.tar.gz ├── node-pty-v1.0.0-node-v115-linux-arm64.tar.gz ├── node-pty-v1.0.0-node-v115-linux-x64.tar.gz ├── authenticate-pam-v1.0.5-node-v115-linux-arm64.tar.gz ├── authenticate-pam-v1.0.5-node-v115-linux-x64.tar.gz └── ... (similar for node versions 22, 23, 24, Linux only) ``` Note: Node version numbers map to internal versions (v115=Node 20, v127=Node 22, v131=Node 23, v134=Node 24) ## Build Process ### Clean Build Approach The npm build process uses a clean distribution directory approach that follows npm best practices: 1. **Creates dist-npm/ directory** - Separate from source files 2. **Generates clean package.json** - Only production fields, no dev dependencies 3. **Bundles dependencies** - node-pty is bundled directly, no symlinks needed 4. **Preserves source integrity** - Never modifies source package.json ### Unified Build (Multi-Platform by Default) ```bash npm run build:npm ``` - Compiles TypeScript and bundles client code - Builds native modules for all supported platforms (macOS x64/arm64, Linux x64/arm64) - Creates comprehensive prebuilds for zero-dependency installation - Generates npm README optimized for package distribution - Creates clean dist-npm/ directory for packaging ### Build Options The unified build script supports flexible targeting: ```bash # Default: All platforms npm run build:npm # Current platform only (faster for development) node scripts/build-npm.js --current-only # Specific platform/architecture node scripts/build-npm.js --platform darwin --arch arm64 node scripts/build-npm.js --platform linux # Skip Docker (Linux builds will be skipped) node scripts/build-npm.js --no-docker ``` ### Docker Requirements For Linux builds, Docker is required: - **Recommended**: [OrbStack](https://orbstack.dev/) - **Alternative**: [Docker Desktop](https://www.docker.com/products/docker-desktop/) The build will fail with helpful error messages if Docker is not available. ## Installation Process ### For End Users 1. **Install package**: `npm install -g vibetunnel` 2. **Postinstall script runs**: Extracts appropriate prebuilt binaries 3. **No compilation needed**: Prebuilds included for all supported platforms 4. **Result**: Working VibeTunnel installation without build tools ### Key Improvements - **No symlinks**: node-pty is bundled directly, avoiding postinstall symlink issues - **Clean package structure**: Only production files in the npm package - **Reliable installation**: Works in restricted environments (Docker, CI) ### Installation Scripts The package uses a simplified postinstall approach: ```json { "scripts": { "postinstall": "node scripts/postinstall.js" } } ``` #### Postinstall Process - **Prebuild extraction**: Extracts the appropriate prebuild for the current platform - **No downloads**: All prebuilds are included in the package - **No compilation**: Everything is pre-built, no build tools required - **Platform detection**: Automatically selects correct binary based on OS and architecture ## Platform-Specific Details ### macOS - **spawn-helper**: Additional C binary needed for proper PTY operations (now prebuilt as universal binary) - **Authentication**: Attempts PAM authentication but may fall back to environment variables or SSH keys - **Architecture**: Supports both Intel (x64) and Apple Silicon (arm64) - **Build tools**: Not required with prebuilds; Xcode Command Line Tools only needed for source compilation fallback ### Linux - **PAM authentication**: Full support via authenticate-pam module - **PAM libraries**: Requires `libpam0g-dev` for authenticate-pam compilation from source - **spawn-helper**: Not used on Linux (macOS-only) - **Build tools**: Not required with prebuilds; `build-essential` only needed for source compilation fallback ### Docker Build Environment Linux prebuilds are created using Docker with: - **Base image**: `node:22-bookworm` - **Dependencies**: `python3 make g++ git libpam0g-dev` - **Package manager**: pnpm (more reliable than npm in Docker) - **Environment**: `CI=true` to avoid interactive prompts ## spawn-helper Binary ### What is spawn-helper? `spawn-helper` is a small C helper binary used by node-pty for proper terminal process spawning on macOS. ### Key Facts - **Size**: ~70KB pure C binary - **Platform**: macOS only (Linux doesn't use it) - **Purpose**: Handles terminal device attachment for spawned processes - **Dependencies**: None (pure C, no Node.js dependencies) - **Architecture**: Platform-specific (x64 vs arm64) ### Source Code ```c // Simplified version of spawn-helper functionality int main (int argc, char** argv) { char *slave_path = ttyname(STDIN_FILENO); close(open(slave_path, O_RDWR)); // Attach to terminal char *cwd = argv[1]; char *file = argv[2]; argv = &argv[2]; if (strlen(cwd) && chdir(cwd) == -1) { _exit(1); } execvp(file, argv); // Execute the target command return 1; } ``` ### Installation Handling - **Current approach**: Universal spawn-helper binary included in prebuilds (macOS only) - **Benefits**: No compilation needed, faster installation, works without build tools - **Fallback path**: If prebuild fails, compilation happens automatically via node-gyp - **Error handling**: Non-fatal if missing (warns but continues) ### Universal Binary Implementation spawn-helper is now shipped as a prebuilt universal binary in all macOS prebuilds: **Implementation**: - Built for both x64 and arm64 architectures using clang++ - Combined into universal binary with `lipo` - Included in every macOS node-pty prebuild automatically **Benefits**: - ✅ Faster installation (no compilation needed) - ✅ Works without build tools (Xcode Command Line Tools) - ✅ Universal compatibility across Intel and Apple Silicon Macs - ✅ Smaller download than compiling during install **Build process**: ```bash # Build for both architectures clang++ -arch x86_64 -o spawn-helper-x64 spawn-helper.cc clang++ -arch arm64 -o spawn-helper-arm64 spawn-helper.cc # Create universal binary lipo -create spawn-helper-x64 spawn-helper-arm64 -output spawn-helper-universal # Include in all macOS prebuilds ``` ## Package Optimization ### File Exclusions Development artifacts are excluded from the final package: - Test files (`public/bundle/test.js`, `public/test/` directory) - Recording files (`*.cast` prevented by .gitignore) - Build artifacts (`dist/` selectively included via package.json `files` field) ### Size Optimization - **Final size**: ~8.5 MB - **File count**: ~275 files - **Prebuilds**: Included for zero-build installation experience - **Source code**: Minimal, compiled assets only ## Development Commands ### Local Development ```bash # Multi-platform build with prebuilds (default) npm run build:npm # Single-platform build for local testing node scripts/build-npm.js --current-only # Test package locally npm pack # Verify package contents tar -tzf vibetunnel-*.tgz | head -20 ``` ### Quality Checks Always run before publishing: ```bash pnpm run lint # Check code style pnpm run typecheck # Verify TypeScript ``` ## Publishing ### Prerequisites 1. Update version in `package.json` 2. Run multi-platform build 3. Test package locally 4. Verify all prebuilds are included ### Publish Command ```bash npm publish ``` ## Usage After Installation ### Installation ```bash # Install globally npm install -g vibetunnel ``` ### Starting the Server ```bash # Start with default settings (port 4020) vibetunnel # Start with custom port vibetunnel --port 8080 # Start without authentication vibetunnel --no-auth ``` Then open http://localhost:4020 in your browser to access the web interface. ### Using the vt Command ```bash # Monitor AI agents with automatic activity tracking vt claude vt claude --dangerously-skip-permissions # Run commands with output visible in VibeTunnel vt npm test vt python script.py vt top # Launch interactive shell vt --shell vt -i # Update session title (inside a session) vt title "My Project" ``` ### Command Forwarding ```bash # Basic usage vibetunnel fwd [args...] # Examples vibetunnel fwd --session-id abc123 ls -la vibetunnel fwd --session-id abc123 npm test vibetunnel fwd --session-id abc123 python script.py ``` ## Coexistence with Mac App The npm package works seamlessly alongside the Mac app: ### Command Routing - The `vt` command from npm automatically detects if the Mac app is installed - If Mac app found at `/Applications/VibeTunnel.app`, npm `vt` defers to it - Ensures you always get the best available implementation ### Installation Behavior - Won't overwrite existing `/usr/local/bin/vt` from other tools - Provides helpful warnings if conflicts exist - Installation always succeeds, even if `vt` symlink can't be created - Use `vibetunnel` or `npx vt` as alternatives ## Build Process Validation ### Ensuring authenticate-pam Module is Included **Critical**: The authenticate-pam module must be copied to the npm package during build. This was missing in beta 14 due to a hardcoded pnpm path issue. #### What to Check Before Publishing 1. **Verify authenticate-pam is installed**: ```bash # Check if the module exists (may be a symlink) ls -la node_modules/authenticate-pam/ ``` 2. **Run the build and check output**: ```bash npm run build:npm # Look for: "✅ authenticate-pam module copied to dist-npm for Linux PAM auth" # If you see: "⚠️ authenticate-pam source not found", the module won't be included ``` 3. **Verify in the built package**: ```bash # Check if authenticate-pam was copied ls -la dist-npm/node_modules/authenticate-pam/ # Should contain: package.json, binding.gyp, authenticate_pam.cc, etc. ``` 4. **Test the package contents**: ```bash # Create package and verify cd dist-npm && npm pack tar -tzf vibetunnel-*.tgz | grep authenticate-pam # Should show: package/node_modules/authenticate-pam/... ``` #### How the Build Script Works The `copyAuthenticatePam()` function in `scripts/build-npm.js`: - Searches multiple possible locations for the module (direct node_modules, pnpm structures) - Uses `fs.statSync()` to properly follow symlinks - Logs which path was found or lists all searched paths if not found - Copies the entire module directory to `dist-npm/node_modules/authenticate-pam/` #### If authenticate-pam is Missing 1. **Ensure it's installed**: Run `pnpm install` to install all dependencies 2. **Check for optional dependency issues**: authenticate-pam is listed as a regular dependency, not optional 3. **Verify pnpm didn't clean it**: Sometimes pnpm removes unused modules during cleanup 4. **Force reinstall if needed**: `pnpm install authenticate-pam` ## Troubleshooting ### Common Issues #### Missing Build Tools **Error**: `gyp ERR! stack Error: not found: make` **Solution**: Install build tools: - **macOS**: `xcode-select --install` - **Linux**: `apt-get install build-essential` #### Missing PAM Development Libraries **Error**: `fatal error: security/pam_appl.h: No such file or directory` **Solution**: Install PAM development libraries: - **Linux**: `apt-get install libpam0g-dev` - **macOS**: Usually available by default #### Docker Not Available **Error**: `Docker is required for multi-platform builds` **Solution**: Install Docker using OrbStack or Docker Desktop #### Prebuild Download Failures **Error**: `prebuild-install warn install No prebuilt binaries found` **Cause**: Network issues or unsupported platform/Node version **Result**: Automatic fallback to source compilation #### npm_config_prefix Conflict with NVM **Error**: Global npm installs fail or install to wrong location when using NVM **Symptoms**: - `npm install -g` installs packages to system location instead of NVM directory - Command not found errors after global install - Permission errors during global installation **Cause**: The `npm_config_prefix` environment variable overrides NVM's per-version npm configuration **Detection**: VibeTunnel's postinstall script will warn if this conflict is detected: ``` ⚠️ Detected npm_config_prefix conflict with NVM npm_config_prefix: /usr/local NVM Node path: /home/user/.nvm/versions/node/v20.19.4/bin/node This may cause npm global installs to fail or install in wrong location. ``` **Solution**: Unset the conflicting environment variable: ```bash unset npm_config_prefix ``` **Permanent fix**: Remove or comment out `npm_config_prefix` settings in: - `~/.bashrc` - `~/.bash_profile` - `~/.profile` - `/etc/profile` - CI/CD environment configurations **Common sources of this issue**: - Previous system-wide npm installations - Docker containers with npm pre-installed - CI/CD environments with global npm configuration - Package managers that set global npm prefix ### Debugging Installation ```bash # Verbose npm install npm install -g vibetunnel --verbose # Check prebuild availability npx prebuild-install --list # Force source compilation npm install -g vibetunnel --build-from-source ``` ## Architecture Decisions ### Why Prebuilds? - **User experience**: No build tools required for most users - **Installation speed**: Pre-compiled binaries install much faster - **Reliability**: Eliminates compilation errors in user environments - **Cross-platform**: Supports all target platforms without user setup ### Why Docker for Linux Builds? - **Cross-compilation**: Build Linux binaries from macOS development machine - **Consistency**: Reproducible build environment - **Dependencies**: Proper PAM library versions for Linux ### Why Vendored node-pty? - **Control**: Custom modifications for VibeTunnel's needs - **Reliability**: Avoid external dependency issues - **Optimization**: Minimal implementation without unnecessary features ## Related Files - `scripts/build-npm.js` - Unified npm build process with multi-platform support - `scripts/postinstall-npm.js` - Fallback compilation logic - `.prebuildrc` - Prebuild configuration for target platforms - `package.json` - Package configuration and file inclusions ## Release Notes ### Version 1.0.0-beta.14.1 (2025-07-21) **Published to npm**: Successfully published as both `vibetunnel@beta` and `vibetunnel@latest` **Critical Fix**: - Fixed missing authenticate-pam module that was excluded from the npm package in beta.14 - The build script now properly detects authenticate-pam in various pnpm directory structures **Package Details**: - Package size: 14.8 MB (34.4 MB unpacked) - Contains 234 files including all prebuilds and web assets - Includes all 24 prebuilds (16 node-pty + 8 authenticate-pam) - authenticate-pam module is now properly bundled in `node_modules/authenticate-pam/` **Installation**: ```bash # Install latest (now 1.0.0-beta.14.1 with the fix) npm install -g vibetunnel # Or install beta specifically npm install -g vibetunnel@beta # Or install specific version npm install -g vibetunnel@1.0.0-beta.14.1 ``` **Build Script Improvements**: - Enhanced `copyAuthenticatePam()` function to search multiple pnpm locations - Added comprehensive logging to track which paths are searched - Properly follows symlinks with `fs.statSync()` for accurate module detection **Verification**: The build now includes clear output confirming authenticate-pam inclusion: ``` ✅ authenticate-pam module copied to dist-npm for Linux PAM auth ``` ### Version 1.0.0-beta.13 (2025-07-19) **Published to npm**: Successfully published as both `vibetunnel@beta` and `vibetunnel@latest` **Key Features**: - All features from previous releases maintained - Updated to match macOS app version 1.0.0-beta.13 - Full cross-platform support with prebuilt binaries - Zero-dependency installation experience **Package Details**: - Package size: 15.5 MB (37.1 MB unpacked) - Contains 235 files including all prebuilds and web assets - Includes prebuilds for Node.js 20, 22, 23, and 24 **Installation**: ```bash # Install latest (now 1.0.0-beta.13) npm install -g vibetunnel # Or install beta specifically npm install -g vibetunnel@beta ``` ### Version 1.0.0-beta.11 (2025-07-16) **Published to npm**: Successfully published as `vibetunnel@beta` **Key Features**: - Cross-platform support for macOS (x64, arm64) and Linux (x64, arm64) - Pre-built native binaries for Node.js versions 20, 22, 23, and 24 - Zero-dependency installation experience (no build tools required) - Comprehensive prebuild system with 24 total binaries included **Release Process Learnings**: 1. **Version Synchronization**: - Must update version in both `web/package.json` and `mac/VibeTunnel/version.xcconfig` - Build process validates version sync to prevent mismatches - Version mismatch will cause build failure with clear error message 2. **NPM Publishing Requirements**: - Beta versions require `--tag beta` flag when publishing - Previously published versions cannot be overwritten (must increment version) - Use `--access public` flag for public package publishing 3. **Package Build Process**: - `pnpm run build:npm` creates the complete package with all prebuilds - Build output filename may show older version in logs but creates correct package - Always verify package version in `dist-npm/package.json` before publishing 4. **Docker Testing Verification**: - Successfully tested on Ubuntu 22.04 (both ARM64 and x64 architectures) - Installation works without any build tools installed - Server starts correctly with all expected functionality - HTTP endpoints respond properly 5. **Package Structure**: - Final package size: 8.3 MB (24.9 MB unpacked) - Contains 198 files including all prebuilds and web assets - Proper postinstall script ensures seamless installation **Installation**: ```bash npm install -g vibetunnel@beta ``` **Testing Commands Used**: ```bash # Build the package cd web && pnpm run build:npm # Verify package contents tar -tzf vibetunnel-1.0.0-beta.11.tgz | head -50 # Test with Docker docker build -t vibetunnel-test . docker run --rm vibetunnel-test # Test cross-platform docker run --rm --platform linux/amd64 vibetunnel-test ``` ### Version History - **1.0.0-beta.14.1** (2025-07-21): Fixed authenticate-pam module missing from npm package (patch release) - **1.0.0-beta.14** (2025-07-21): macOS app release (npm package had missing authenticate-pam module) - **1.0.0-beta.13** (2025-07-19): Synchronized with macOS app version - **1.0.0-beta.12.1** (2025-07-17): Minor updates and fixes - **1.0.0-beta.12** (2025-07-17): Package structure improvements - **1.0.0-beta.11.1** (2025-07-16): Fixed npm installation issues - **1.0.0-beta.11** (2025-07-16): Initial release with full prebuild system - **1.0.0-beta.10** (2025-07-14): Previous version (unpublished) ## NPM Distribution Tags VibeTunnel uses npm dist-tags to manage different release channels: ### Current Tags - **latest**: Points to the most stable release (currently 1.0.0-beta.14.1) - **beta**: Points to the latest beta release (currently 1.0.0-beta.14.1) ### Managing Tags ```bash # View current tags npm dist-tag ls vibetunnel # Set a version as latest npm dist-tag add vibetunnel@1.0.0-beta.13 latest # Add a new tag npm dist-tag add vibetunnel@1.0.0-beta.14 next # Remove a tag npm dist-tag rm vibetunnel next ``` ### Installation by Tag ```bash # Install latest stable (default) npm install -g vibetunnel # Install specific tag npm install -g vibetunnel@beta npm install -g vibetunnel@latest # Install specific version npm install -g vibetunnel@1.0.0-beta.11.1 ``` ### Best Practices - Always tag beta releases with `beta` tag - Only promote to `latest` after testing confirms stability - Use semantic versioning for beta iterations (e.g., 1.0.0-beta.11.1, 1.0.0-beta.11.2)