diff --git a/packages/freebuff/default.nix b/packages/freebuff/default.nix index 0ee9128..8f06c43 100644 --- a/packages/freebuff/default.nix +++ b/packages/freebuff/default.nix @@ -1 +1 @@ -{ pkgs, ... }: pkgs.callPackage ./package.nix { } +{ pkgs, ... }: pkgs.callPackage ./package.nix { glibc = pkgs.stdenv.cc.libc; } diff --git a/packages/freebuff/package.nix b/packages/freebuff/package.nix index 3ec81b6..02650ae 100644 --- a/packages/freebuff/package.nix +++ b/packages/freebuff/package.nix @@ -4,6 +4,8 @@ fetchurl, nodejs, makeWrapper, + patchelf, + glibc, }: let @@ -44,6 +46,12 @@ let hash = "sha256-fJ1D26t8qzsxM7Dmpa8UAUSCKFMWs57J9QjvrdnrzpU="; }; + # Pre-built binary release from codebuff.com + binarySrc = fetchurl { + url = "https://codebuff.com/api/releases/download/${version}/freebuff-linux-x64.tar.gz"; + hash = "sha256-WRTEXqKDww4ZPAnDLAAkAd0jxl+z6+dRbcQORmN7QfM="; + }; + in stdenv.mkDerivation rec { @@ -52,11 +60,34 @@ stdenv.mkDerivation rec { src = freebuffSrc; - nativeBuildInputs = [ makeWrapper ]; + nativeBuildInputs = [ makeWrapper patchelf ]; + + dontStrip = true; + dontPatchelf = true; installPhase = '' runHook preInstall + # Extract and patch the pre-built binary for NixOS compatibility + mkdir -p "$out/bin" /tmp/fb-engine + tar xzf "${binarySrc}" -C /tmp/fb-engine --strip-components=0 + cp /tmp/fb-engine/freebuff "$out/bin/freebuff-engine" + chmod 755 "$out/bin/freebuff-engine" + + # Patch ELF interpreter and rpath for glibc on NixOS + patchelf \ + --set-interpreter "${glibc}/lib/ld-linux-x86-64.so.2" \ + --set-rpath "${glibc}/lib:" \ + "$out/bin/freebuff-engine" + + # Copy tree-sitter.wasm next to the engine binary + if [ -f /tmp/fb-engine/tree-sitter.wasm ]; then + cp /tmp/fb-engine/tree-sitter.wasm "$out/bin/" + fi + + rm -rf /tmp/fb-engine + + # Set up JS launcher and npm dependencies mkdir -p "$out/lib/node_modules/freebuff" cp -r * "$out/lib/node_modules/freebuff/" @@ -75,10 +106,86 @@ stdenv.mkDerivation rec { mkdir -p "$out/lib/node_modules/@isaacs" extractNpmPkg "${pkgFsMinipass}" "$out/lib/node_modules/@isaacs/fs-minipass" - mkdir -p "$out/bin" + # Create wrapper launcher that uses the pre-patched binary instead of downloading + cat > "$out/lib/node_modules/freebuff/wrapper-launcher.js" << WRAPPER_EOF +#!/usr/bin/env node +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +// Use the Nix-store patched binary directly +const enginePath = process.env.FREEBUFF_ENGINE || '${placeholder "out"}/bin/freebuff-engine'; + +// Metadata path for version tracking +const configDir = path.join(process.env.HOME || '/', '.config', 'manicode'); +const metadataPath = path.join(configDir, 'freebuff-metadata.json'); + +function resetTerminal() { + try { + if (process.stdin.isTTY && process.stdin.setRawMode) { + process.stdin.setRawMode(false); + } + } catch {} + try { + const seqs = '\\x1b[?1049l\\x1b[?1000l\\x1b[?1002l\\x1b[?1003l\\x1b[?1006l\\x1b[?2004l\\x1b[?25h'; + if (process.stdout.isTTY) process.stdout.write(seqs); + } catch {} +} + +async function main() { + // Copy patched binary to user config dir so the engine finds tree-sitter.wasm there too + fs.mkdirSync(configDir, { recursive: true }); + const targetBinary = path.join(configDir, 'freebuff'); + const targetWasm = path.join(configDir, 'tree-sitter.wasm'); + + // Install patched binary if not present or version mismatch + let needsInstall = !fs.existsSync(targetBinary); + if (!needsInstall) { + try { + const meta = JSON.parse(fs.readFileSync(metadataPath, 'utf8')); + needsInstall = (meta.version !== '${version}'); + } catch {} + } + + if (needsInstall) { + try { fs.unlinkSync(targetBinary); } catch {} + fs.copyFileSync(enginePath, targetBinary); + fs.chmodSync(targetBinary, 0o755); + fs.writeFileSync(metadataPath, JSON.stringify({ version: '${version}' }, null, 2)); + + // Copy tree-sitter.wasm if available + const wasmSrc = '${placeholder "out"}/bin/tree-sitter.wasm'; + if (fs.existsSync(wasmSrc)) { + try { fs.copyFileSync(wasmSrc, targetWasm); } catch {} + } + } + + const child = spawn(targetBinary, process.argv.slice(2), { + stdio: 'inherit', + env: { ...process.env }, + }); + + child.on('exit', (code, signal) => { + resetTerminal(); + process.exit(signal ? 1 : (code || 0)); + }); + + child.on('error', (err) => { + console.error('Failed to start freebuff:', err.message); + process.exit(1); + }); +} + +main().catch((error) => { + console.error('Unexpected error:', error.message); + process.exit(1); +}); +WRAPPER_EOF + + # Create the main binary wrapper makeWrapper "${nodejs}/bin/node" "$out/bin/freebuff" \ --set NODE_PATH "$out/lib/node_modules" \ - --add-flags "$out/lib/node_modules/freebuff/index.js" + --add-flags "$out/lib/node_modules/freebuff/wrapper-launcher.js" runHook postInstall ''; @@ -99,6 +206,6 @@ stdenv.mkDerivation rec { homepage = "https://codebuff.com"; license = licenses.mit; mainProgram = "freebuff"; - platforms = platforms.all; + platforms = platforms.linux; }; }