mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-10 10:25:03 +00:00
fix(daemon): derive desktop management from executable
Desktop management now follows the daemon runtime path, so daemons started through the bundled CLI remain eligible for desktop upgrade restarts. New locks record executablePath; the old desktopManaged lock bit is accepted only for compatibility with existing locks.
This commit is contained in:
@@ -25,6 +25,7 @@ export interface LocalDaemonPidInfo {
|
||||
hostname?: string;
|
||||
uid?: number;
|
||||
listen?: string;
|
||||
executablePath?: string;
|
||||
desktopManaged?: boolean;
|
||||
}
|
||||
|
||||
@@ -255,6 +256,7 @@ function readPidFile(pidPath: string): LocalDaemonPidInfo | null {
|
||||
hostname: typeof parsed.hostname === "string" ? parsed.hostname : undefined,
|
||||
uid: typeof parsed.uid === "number" ? parsed.uid : undefined,
|
||||
listen: resolveListenField(parsed.listen, parsed.sockPath),
|
||||
executablePath: typeof parsed.executablePath === "string" ? parsed.executablePath : undefined,
|
||||
desktopManaged: parsed.desktopManaged === true ? true : undefined,
|
||||
};
|
||||
} catch {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import type { Command } from "commander";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||
import type { CommandOptions } from "../../output/index.js";
|
||||
import { runStatusCommand } from "./status.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
execCommand: vi.fn(async () => ({ stdout: process.execPath, stderr: "" })),
|
||||
findExecutable: vi.fn(async () => null),
|
||||
getOrCreateServerId: vi.fn(() => "srv_test"),
|
||||
loadConfig: vi.fn(() => ({
|
||||
listen: "127.0.0.1:6767",
|
||||
relayEnabled: true,
|
||||
relayEndpoint: "relay.paseo.sh:443",
|
||||
relayUseTls: false,
|
||||
relayPublicUseTls: false,
|
||||
})),
|
||||
resolvePaseoHome: vi.fn((env: NodeJS.ProcessEnv) => env.PASEO_HOME ?? "/tmp/paseo"),
|
||||
spawnProcess: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@getpaseo/server", () => ({
|
||||
execCommand: mocks.execCommand,
|
||||
findExecutable: mocks.findExecutable,
|
||||
getOrCreateServerId: mocks.getOrCreateServerId,
|
||||
loadConfig: mocks.loadConfig,
|
||||
resolvePaseoHome: mocks.resolvePaseoHome,
|
||||
spawnProcess: mocks.spawnProcess,
|
||||
}));
|
||||
|
||||
const tempRoots: string[] = [];
|
||||
|
||||
async function createStatusHome(pidLock: Record<string, unknown>): Promise<string> {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "paseo-daemon-status-"));
|
||||
tempRoots.push(root);
|
||||
const home = path.join(root, ".paseo");
|
||||
await mkdir(home, { recursive: true });
|
||||
await writeFile(path.join(home, "paseo.pid"), JSON.stringify(pidLock));
|
||||
return home;
|
||||
}
|
||||
|
||||
async function readStatusJson(home: string): Promise<Record<string, unknown>> {
|
||||
const previousPath = process.env.PATH;
|
||||
try {
|
||||
process.env.PATH = "";
|
||||
const result = await runStatusCommand({ home } as CommandOptions, {} as Command);
|
||||
return result.schema.serialize?.(result.data[0]) as Record<string, unknown>;
|
||||
} finally {
|
||||
if (previousPath === undefined) {
|
||||
delete process.env.PATH;
|
||||
} else {
|
||||
process.env.PATH = previousPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("daemon status desktop management fields", () => {
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
test("reports executable identity without deriving desktop management in the CLI", async () => {
|
||||
const executablePath =
|
||||
"/Applications/Paseo.app/Contents/Frameworks/Paseo Helper.app/Contents/MacOS/Paseo Helper";
|
||||
const home = await createStatusHome({
|
||||
pid: process.pid,
|
||||
startedAt: "2026-07-06T00:00:00.000Z",
|
||||
hostname: "dev-host",
|
||||
uid: 501,
|
||||
listen: "/tmp/paseo-status.sock",
|
||||
executablePath,
|
||||
});
|
||||
|
||||
await expect(readStatusJson(home)).resolves.toMatchObject({
|
||||
daemonExecutablePath: executablePath,
|
||||
desktopManaged: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps reporting legacy desktopManaged locks for old readers", async () => {
|
||||
const home = await createStatusHome({
|
||||
pid: process.pid,
|
||||
startedAt: "2026-07-06T00:00:00.000Z",
|
||||
hostname: "dev-host",
|
||||
uid: 501,
|
||||
listen: "/tmp/paseo-status.sock",
|
||||
desktopManaged: true,
|
||||
});
|
||||
|
||||
await expect(readStatusJson(home)).resolves.toMatchObject({
|
||||
daemonExecutablePath: null,
|
||||
desktopManaged: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -28,6 +28,7 @@ interface DaemonStatus {
|
||||
owner: string | null;
|
||||
logPath: string;
|
||||
daemonNode: string;
|
||||
daemonExecutablePath: string | null;
|
||||
cliNode: string;
|
||||
cliVersion: string;
|
||||
daemonVersion: string | null;
|
||||
@@ -126,6 +127,7 @@ function toStatusRows(status: DaemonStatus): StatusRow[] {
|
||||
{ key: "Owner", value: status.owner ?? "-" },
|
||||
{ key: "Logs", value: status.logPath },
|
||||
{ key: "Daemon Node", value: status.daemonNode },
|
||||
{ key: "Daemon Executable", value: status.daemonExecutablePath ?? "-" },
|
||||
{ key: "CLI Node", value: status.cliNode },
|
||||
{ key: "CLI", value: status.cliVersion },
|
||||
{ key: "Daemon Version", value: status.daemonVersion ?? "-" },
|
||||
@@ -405,9 +407,11 @@ export async function runStatusCommand(
|
||||
owner,
|
||||
logPath: state.logPath,
|
||||
daemonNode,
|
||||
daemonExecutablePath: state.pidInfo?.executablePath ?? null,
|
||||
cliNode,
|
||||
cliVersion,
|
||||
daemonVersion,
|
||||
// COMPAT(desktopManagedPidLock): added in v0.1.105, remove after 2027-01-06 once locks without executablePath have aged out.
|
||||
desktopManaged: state.pidInfo?.desktopManaged === true,
|
||||
providers,
|
||||
note,
|
||||
|
||||
Reference in New Issue
Block a user