fix(nix): package local speech worker (#1587)

* fix(nix): package local speech worker

* fix(nix): reuse sherpa package helper

* fix(nix): patch sherpa-onnx prebuilt binaries for NixOS libstdc++

The prebuilt sherpa-onnx-linux-x64 .so files link against libstdc++.so.6
which is not on the NixOS library path. Add autoPatchelfHook to fix ELF
RPATHs and stdenv.cc.cc.lib to provide the C++ runtime, resolving the
"Failed to load model because protobuf parsing failed" SIGABRT at
speech worker startup.
This commit is contained in:
yhori
2026-07-20 18:21:10 +09:00
committed by GitHub
parent 3d86c738ff
commit 0c68b26a8b
2 changed files with 31 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
// Emit the set of files the daemon and CLI need at runtime, computed by
// static module-graph tracing (@vercel/nft) from the three entry points.
// static module-graph tracing (@vercel/nft) from the daemon entry points.
// Used by nix/package.nix's installPhase to materialize $out/lib/paseo
// with only the bytes the daemon actually loads — no Expo, RN, Metro,
// Electron, ML stacks, or other non-daemon workspace bloat.
@@ -15,16 +15,27 @@
import { nodeFileTrace } from "@vercel/nft";
import { glob } from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";
const REPO_ROOT = path.resolve(import.meta.dirname, "..");
// Three entry points. The terminal worker is forked into its own Node
// process and has its own require tree (node-pty, etc.) — nft does not
// follow fork boundaries, so it must be traced separately.
const { sherpaPlatformPackageName } = await import(
pathToFileURL(
path.join(
REPO_ROOT,
"packages/server/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js",
),
).href
);
// Daemon entry points. Workers forked into their own Node processes have
// independent require trees; nft does not follow fork boundaries, so trace
// them separately.
const entries = [
"packages/cli/dist/index.js",
"packages/server/dist/scripts/supervisor-entrypoint.js",
"packages/server/dist/server/terminal/terminal-worker-process.js",
"packages/server/dist/server/server/speech/providers/local/worker-process.js",
];
// Files read at runtime via fs APIs rather than `require`. nft only
@@ -44,19 +55,22 @@ const additionalInputs = [
// the Nix derivation builds for one platform at a time and ships only
// its own binaries.
`node_modules/node-pty/prebuilds/${process.platform}-${process.arch}/**`,
// sherpa-onnx-node dynamically resolves a platform-specific native package.
// Copy the wrapper plus the host platform package explicitly.
"node_modules/sherpa-onnx-node/**",
`node_modules/${sherpaPlatformPackageName()}/**`,
];
// Trace.
const { fileList, warnings } = await nodeFileTrace(entries, {
base: REPO_ROOT,
// Tolerate the conditional / dynamic patterns we already audited:
// sherpa-onnx-${platform}-${arch} package resolution (sherpa is
// intentionally not built in the Nix sandbox; voice features degrade
// gracefully when unavailable), and a handful of test-only requires
// that get tree-shaken out by tsc.
// sherpa-onnx-${platform}-${arch} package resolution (the host package
// is copied explicitly above), and a handful of test-only requires that
// get tree-shaken out by tsc.
ignore: [
// Cross-platform native packages for the sherpa speech runtime;
// unsupported in the Nix build, lazily loaded when present.
// only the host platform package is needed at runtime.
"sherpa-onnx-*/**",
// Platform-specific clipboard variants; only the host's variant
// is needed at runtime, and the package's index.js resolver picks