{ lib, stdenv, buildNpmPackage, fetchzip, nodejs_22, python3, sqlite, }: let version = "2.1.0"; in buildNpmPackage rec { pname = "qmd"; inherit version; src = fetchzip { url = "https://git.johnogle.info/johno/qmd/archive/220e46e09c90e59bdcb0b4b81753ebc32c45ad80.tar.gz"; sha256 = "sha256-hPTBsJFsCEuPOk2oZqDy5XcbvP4T+aHlgCL3EHO2vb8="; }; # 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 ''; # npmDepsHash matches the vendored package-lock.json npmDepsHash = "sha256-3sis2NIuPDnwAOzWEQBcA+VUsMaxO8Nkuk6wCJ9foBA="; 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"; }; }