From e1a9bade8a4da597e75993d8648ebde5309d6fa6 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 6 Apr 2026 22:29:35 +0000 Subject: [PATCH] fix: resolve symlinked npm global bin path for standalone server.js When failproofai is installed globally via npm, the bin entry is a symlink. Bun can resolve import.meta.url to the symlink's directory rather than the real package directory, causing server.js to be looked up at the wrong path (e.g. ~/.next/standalone/server.js). Fix by wrapping fileURLToPath with realpathSync in both the bin entry point and scripts/launch.ts. The bin script also sets FAILPROOFAI_PACKAGE_ROOT early (before any dynamic imports) so launch.ts has a reliable fallback even if its own import.meta.url resolution is affected. Co-Authored-By: Claude Sonnet 4.6 --- bin/failproofai.mjs | 13 +++++++++++++ scripts/launch.ts | 8 ++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/bin/failproofai.mjs b/bin/failproofai.mjs index e6f4d0e7..e471644e 100644 --- a/bin/failproofai.mjs +++ b/bin/failproofai.mjs @@ -10,8 +10,21 @@ * --list-policies List available policies and their status * (default) Launch production dashboard */ +import { realpathSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; import { version } from "../package.json"; +// Resolve the real package root early (following any npm bin symlinks) so that +// scripts/launch.ts can locate .next/standalone/server.js correctly regardless +// of how bun resolves import.meta.url for dynamically-imported modules. +if (!process.env.FAILPROOFAI_PACKAGE_ROOT) { + process.env.FAILPROOFAI_PACKAGE_ROOT = resolve( + dirname(realpathSync(fileURLToPath(import.meta.url))), + ".." + ); +} + const args = process.argv.slice(2); // --version / -v diff --git a/scripts/launch.ts b/scripts/launch.ts index 7cd53ece..e98d373d 100644 --- a/scripts/launch.ts +++ b/scripts/launch.ts @@ -3,6 +3,7 @@ */ import { getDefaultClaudeProjectsPath } from "../lib/paths"; import { spawn } from "child_process"; +import { realpathSync } from "node:fs"; import { resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { parseScriptArgs } from "./parse-script-args"; @@ -39,8 +40,11 @@ export function launch(mode: "dev" | "start"): void { process.env.PORT = port; process.env.HOSTNAME = "0.0.0.0"; cmd = "node"; - // Absolute path — required so the CLI works from any working directory after install - cmdArgs = [resolve(dirname(fileURLToPath(import.meta.url)), "../.next/standalone/server.js")]; + // Resolve the real package root via realpathSync so symlinked npm global binaries + // don't cause import.meta.url to point at the symlink dir instead of the package dir. + const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT + ?? resolve(dirname(realpathSync(fileURLToPath(import.meta.url))), ".."); + cmdArgs = [resolve(packageRoot, ".next/standalone/server.js")]; } else { cmd = "bunx"; cmdArgs = ["--bun", "next", "dev", ...remainingArgs];