feat: enable Linux PATH inheritance for autostart & extend loginShellPath to Linux (#11372)

Merged via consolidated batch validation. Fixes autostart on Linux failing to inherit the user's shell PATH (CLI-dependent features like Kiro's Google OAuth broke). Resolved a conflict against a batch sibling in bin/cli/commands/doctor.mjs (kept the more complete prebuilds-aware candidate list) and setup-claude.mjs (formatting only). Own test (login-shell-path-3321.test.ts, 10/10) passes + typecheck:core clean. Thanks!
This commit is contained in:
Zius
2026-08-24 20:50:02 +05:30
committed by GitHub
parent 440113c8e8
commit 2544ee9498
4 changed files with 24 additions and 7 deletions

View File

@@ -169,7 +169,8 @@ export async function runSetupClaudeCommand(opts = {}) {
let detail = `HTTP ${res.status}`;
try {
const errorBody = await res.json();
const serverMsg = errorBody?.error?.message || errorBody?.error || errorBody?.message || "";
const serverMsg =
errorBody?.error?.message || errorBody?.error || errorBody?.message || "";
if (serverMsg) detail += `${serverMsg}`;
} catch {}
throw new Error(detail);

View File

@@ -114,10 +114,13 @@ function writeLinuxSystemdUnit(cliPath) {
const unitDir = dirname(linuxSystemdUnitPath());
mkdirSync(unitDir, { recursive: true });
const envFile = join(userHomeDir(), ".omniroute", ".env");
const nodeBinDir = dirname(process.execPath);
const userLocalBin = join(userHomeDir(), ".local", "bin");
const pathEnv = `${nodeBinDir}:${userLocalBin}:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin`;
const lines = [
"[Unit]",
"Description=OmniRoute AI proxy router",
"After=network-online.target",
"After=network-online.target graphical-session.target",
"Wants=network-online.target",
"",
"[Service]",
@@ -134,6 +137,7 @@ function writeLinuxSystemdUnit(cliPath) {
`ExecStart=${buildServeExecLine(cliPath, { tray: false })}`,
"Restart=on-failure",
"RestartSec=5",
`Environment="PATH=${pathEnv}"`,
];
if (existsSync(envFile)) lines.push(`EnvironmentFile=-${envFile}`);
lines.push("", "[Install]", "WantedBy=default.target", "");

View File

@@ -59,8 +59,8 @@ export interface LoginShellPathOptions {
*/
export function getLoginShellPath(opts: LoginShellPathOptions = {}): string | null {
const platform = opts.platform ?? process.platform;
if (platform !== "darwin") return null;
const shell = opts.shell || process.env.SHELL || "/bin/zsh";
if (platform !== "darwin" && platform !== "linux") return null;
const shell = opts.shell || process.env.SHELL || (platform === "darwin" ? "/bin/zsh" : "/bin/bash");
if (!/^[\w./-]+$/.test(shell)) return null;
const run =
opts.runShell ||

View File

@@ -43,17 +43,29 @@ test("parseShellPathOutput returns null when no PATH line is present", () => {
assert.equal(parseShellPathOutput(""), null);
});
test("getLoginShellPath returns null on non-darwin platforms (no-op on Linux/Windows)", () => {
test("getLoginShellPath returns null on win32 platform (no-op on Windows)", () => {
let called = false;
const result = getLoginShellPath({
platform: "linux",
platform: "win32",
runShell: () => {
called = true;
return "PATH=/should/not/be/used";
},
});
assert.equal(result, null);
assert.equal(called, false, "must not spawn the shell on non-darwin");
assert.equal(called, false, "must not spawn the shell on win32");
});
test("getLoginShellPath returns the login-shell PATH on linux", () => {
const result = getLoginShellPath({
platform: "linux",
shell: "/bin/bash",
runShell: (sh) => {
assert.equal(sh, "/bin/bash");
return "PATH=/home/user/.nvm/versions/node/v22.23.1/bin:/usr/local/bin:/usr/bin\n";
},
});
assert.equal(result, "/home/user/.nvm/versions/node/v22.23.1/bin:/usr/local/bin:/usr/bin");
});
test("getLoginShellPath returns the login-shell PATH on darwin (#3321)", () => {