{ lib, stdenv, buildNpmPackage, fetchFromGitHub, nodejs_22, python3, sqlite, }: let version = "2.1.0"; in buildNpmPackage rec { pname = "qmd"; inherit version; src = fetchFromGitHub { owner = "tobi"; repo = "qmd"; rev = "v${version}"; hash = "sha256-bqIVaNRTa8H5vrw3RwsD7QdtTa0xNvRuEVzlzE1hIBQ="; }; # Vendored package-lock.json generated from QMD's package.json. # QMD ships bun.lock/pnpm-lock.yaml but not package-lock.json. # buildNpmPackage requires npm's lockfile format. postPatch = '' cp ${./package-lock.json} package-lock.json ''; # Will be updated on first build attempt — nix will report the correct hash npmDepsHash = "sha256-iBFj0C0BYLPtjOQqp5O/lRjeKTMMNoqHLtjGeERECpk="; nodejs = nodejs_22; nativeBuildInputs = [ nodejs python3 # for node-gyp (better-sqlite3, sqlite-vec) ]; buildInputs = [ sqlite # for sqlite extension loading at runtime ]; # npm rebuild compiles native addons (better-sqlite3, sqlite-vec) against Node 22's V8 npmRebuildFlags = [ "--build-from-source" ]; # Don't run npm run prepare (it tries to install git hooks) npmPruneFlags = [ "--omit=dev" ]; buildPhase = '' runHook preBuild npm run build runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/lib/qmd $out/bin # Copy compiled output, node_modules, and config cp -r dist node_modules $out/lib/qmd/ cp package.json $out/lib/qmd/ # Create wrapper that runs the compiled CLI with Node.js 22 # Sets LD_LIBRARY_PATH for sqlite-vec extension loading cat > $out/bin/qmd << EOF #!/bin/sh export LD_LIBRARY_PATH="${sqlite.out}/lib''${LD_LIBRARY_PATH:+:}\$LD_LIBRARY_PATH" exec ${nodejs}/bin/node $out/lib/qmd/dist/cli/qmd.js "\$@" EOF chmod +x $out/bin/qmd runHook postInstall ''; meta = with lib; { description = "Query Markup Documents — on-device hybrid search for markdown files"; longDescription = '' QMD combines BM25 full-text search, vector semantic search, and LLM re-ranking. This build uses Node.js 22 (instead of Bun) to avoid native module ABI issues with better-sqlite3 and sqlite-vec. ''; homepage = "https://github.com/tobi/qmd"; license = licenses.mit; platforms = platforms.linux; mainProgram = "qmd"; }; }