fix: non-blocking browser launch in Pi extension (Linux) (#292)

* fix: use non-blocking spawn for browser launch in Pi extension

execSync(xdg-open ...) blocks the Node.js event loop, preventing the
HTTP server from responding to the browser's initial request on Linux
desktops where xdg-open doesn't immediately exit.

Closes #288

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle async spawn errors in Pi openBrowser

spawn() reports missing-command failures asynchronously via an 'error'
event. Without a listener, a bad PLANNOTATOR_BROWSER or missing
xdg-open crashes the Pi process. Add child.once("error", () => {})
to swallow it silently, matching the original execSync try/catch
behavior.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Ramos
2026-03-14 17:40:44 -07:00
committed by GitHub
parent d2238ac736
commit f5705cdb9c
+20 -7
View File
@@ -7,7 +7,7 @@
*/
import { createServer, type IncomingMessage, type Server } from "node:http";
import { execSync } from "node:child_process";
import { execSync, spawn } from "node:child_process";
import os from "node:os";
import { mkdirSync, writeFileSync, readFileSync, readdirSync, statSync } from "node:fs";
import { join, basename } from "node:path";
@@ -54,21 +54,34 @@ export function openBrowser(url: string): void {
const platform = process.platform;
const wsl = platform === "linux" && os.release().toLowerCase().includes("microsoft");
let cmd: string;
let args: string[];
if (browser) {
if (process.env.PLANNOTATOR_BROWSER && platform === "darwin") {
execSync(`open -a ${JSON.stringify(browser)} ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = "open";
args = ["-a", browser, url];
} else if (platform === "win32" || wsl) {
execSync(`cmd.exe /c start "" ${JSON.stringify(browser)} ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = "cmd.exe";
args = ["/c", "start", "", browser, url];
} else {
execSync(`${JSON.stringify(browser)} ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = browser;
args = [url];
}
} else if (platform === "win32" || wsl) {
execSync(`cmd.exe /c start "" ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = "cmd.exe";
args = ["/c", "start", "", url];
} else if (platform === "darwin") {
execSync(`open ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = "open";
args = [url];
} else {
execSync(`xdg-open ${JSON.stringify(url)}`, { stdio: "ignore" });
cmd = "xdg-open";
args = [url];
}
const child = spawn(cmd, args, { detached: true, stdio: "ignore" });
child.once("error", () => {});
child.unref();
} catch {
// Silently fail
}