From 7db9888ddf478df8cc87e2f9e7cdfe29f9ae3204 Mon Sep 17 00:00:00 2001 From: "A.R." Date: Mon, 11 May 2026 21:03:17 +0300 Subject: [PATCH 01/13] fix(#6.1): resolve symlinks in direct-run guard `import.meta.url === pathToFileURL(process.argv[1]).href` silently returned false when the CLI was invoked through a symlink (npm .bin, Homebrew Cellar, etc.), causing the CLI to exit 0 with no output. Extract a shared `isMainModule()` helper that resolves both sides through `realpathSync` before comparing, with a graceful fallback to the old behavior if realpath fails. Files: cli.js, index.ts, is-main-module.js(+d.ts) --- packages/mcp-server/src/cli.js | 7 ++-- packages/mcp-server/src/index.ts | 4 +-- packages/mcp-server/src/is-main-module.d.ts | 6 ++++ packages/mcp-server/src/is-main-module.js | 37 +++++++++++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 packages/mcp-server/src/is-main-module.d.ts create mode 100644 packages/mcp-server/src/is-main-module.js diff --git a/packages/mcp-server/src/cli.js b/packages/mcp-server/src/cli.js index 274b42b..b9487b8 100644 --- a/packages/mcp-server/src/cli.js +++ b/packages/mcp-server/src/cli.js @@ -8,6 +8,7 @@ import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { promisify } from "node:util"; import { fileURLToPath, pathToFileURL } from "node:url"; +import { isMainModule } from "./is-main-module.js"; const execFile = promisify(execFileCallback); @@ -1302,8 +1303,8 @@ Environment: PERPLEXITY_NO_DAEMON=1 'daemon attach' runs in-process stdio (bypass daemon) `; -/* v8 ignore start -- only runs when cli.js is executed as a script */ -if (import.meta.url === pathToFileURL(process.argv[1]).href) { + +if (isMainModule(import.meta.url)) { const parsed = parseArgs(process.argv.slice(2)); routeCommand(parsed).then((res) => { if (res.stdout) process.stdout.write(res.stdout); @@ -1311,4 +1312,4 @@ if (import.meta.url === pathToFileURL(process.argv[1]).href) { process.exit(res.code); }); } -/* v8 ignore stop */ + diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 322df8c..597ad00 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { pathToFileURL } from "node:url"; +import { isMainModule } from "./is-main-module.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { PerplexityClient } from "./client.js"; @@ -191,7 +191,7 @@ export async function main() { } } -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { +if (isMainModule(import.meta.url)) { runEntrypoint().catch(async (error) => { console.error("[perplexity-mcp] Fatal error:", error); await shutdownClientWithTimeout(client); diff --git a/packages/mcp-server/src/is-main-module.d.ts b/packages/mcp-server/src/is-main-module.d.ts new file mode 100644 index 0000000..8f42651 --- /dev/null +++ b/packages/mcp-server/src/is-main-module.d.ts @@ -0,0 +1,6 @@ +/** + * Returns true when the importing module is the process entrypoint (i.e. was + * invoked as `node