Fix Windows daemon status output (#1725)
This commit is contained in:
@@ -28,12 +28,13 @@ async function resolveNodePathFromPidUnix(pid: number): Promise<NodePathFromPidR
|
|||||||
async function runProcessProbe(
|
async function runProcessProbe(
|
||||||
command: string,
|
command: string,
|
||||||
args: string[],
|
args: string[],
|
||||||
|
options?: { shell?: boolean },
|
||||||
): Promise<{
|
): Promise<{
|
||||||
resolved: string | null;
|
resolved: string | null;
|
||||||
error?: string;
|
error?: string;
|
||||||
}> {
|
}> {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execCommand(command, args);
|
const { stdout } = await execCommand(command, args, { shell: options?.shell });
|
||||||
const resolved = stdout.trim();
|
const resolved = stdout.trim();
|
||||||
return resolved
|
return resolved
|
||||||
? { resolved }
|
? { resolved }
|
||||||
@@ -52,7 +53,7 @@ async function resolveNodePathFromPidWindows(pid: number): Promise<NodePathFromP
|
|||||||
}> = [
|
}> = [
|
||||||
{
|
{
|
||||||
label: "powershell-cim",
|
label: "powershell-cim",
|
||||||
command: "powershell",
|
command: "powershell.exe",
|
||||||
args: [
|
args: [
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-Command",
|
||||||
@@ -61,7 +62,7 @@ async function resolveNodePathFromPidWindows(pid: number): Promise<NodePathFromP
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "powershell-process",
|
label: "powershell-process",
|
||||||
command: "powershell",
|
command: "powershell.exe",
|
||||||
args: ["-NoProfile", "-Command", `(Get-Process -Id ${pid}).Path`],
|
args: ["-NoProfile", "-Command", `(Get-Process -Id ${pid}).Path`],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -85,7 +86,7 @@ async function resolveNodePathFromPidWindows(pid: number): Promise<NodePathFromP
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const probe = probes[index];
|
const probe = probes[index];
|
||||||
const result = await runProcessProbe(probe.command, probe.args);
|
const result = await runProcessProbe(probe.command, probe.args, { shell: false });
|
||||||
if (result.resolved) {
|
if (result.resolved) {
|
||||||
const resolved = probe.parseValue ? probe.parseValue(result.resolved) : result.resolved;
|
const resolved = probe.parseValue ? probe.parseValue(result.resolved) : result.resolved;
|
||||||
if (resolved) return { nodePath: resolved };
|
if (resolved) return { nodePath: resolved };
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env npx tsx
|
||||||
|
|
||||||
|
import assert from "node:assert";
|
||||||
|
import { spawn } from "node:child_process";
|
||||||
|
import { mkdtemp, rm } from "node:fs/promises";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { getAvailablePort } from "./helpers/network.ts";
|
||||||
|
|
||||||
|
const CLI_ENTRY = join(import.meta.dirname, "..", "dist", "index.js");
|
||||||
|
|
||||||
|
interface CommandResult {
|
||||||
|
exitCode: number | null;
|
||||||
|
stdout: string;
|
||||||
|
stderr: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runLocalPaseo(args: string[], env: NodeJS.ProcessEnv): Promise<CommandResult> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const child = spawn(process.execPath, [CLI_ENTRY, ...args], {
|
||||||
|
env: { ...process.env, ...env },
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
windowsHide: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let stdout = "";
|
||||||
|
let stderr = "";
|
||||||
|
child.stdout.on("data", (chunk: Buffer) => {
|
||||||
|
stdout += chunk.toString();
|
||||||
|
});
|
||||||
|
child.stderr.on("data", (chunk: Buffer) => {
|
||||||
|
stderr += chunk.toString();
|
||||||
|
});
|
||||||
|
child.on("error", reject);
|
||||||
|
child.on("close", (exitCode) => {
|
||||||
|
resolve({ exitCode, stdout, stderr });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.platform !== "win32") {
|
||||||
|
console.log("Skipping Windows daemon status process lookup regression on non-Windows.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("=== Windows Daemon Status Process Lookup ===\n");
|
||||||
|
|
||||||
|
const paseoHome = await mkdtemp(join(tmpdir(), "paseo-windows-status-home-"));
|
||||||
|
const port = await getAvailablePort();
|
||||||
|
const env = {
|
||||||
|
PASEO_HOME: paseoHome,
|
||||||
|
PASEO_LOCAL_SPEECH_AUTO_DOWNLOAD: "0",
|
||||||
|
PASEO_DICTATION_ENABLED: "0",
|
||||||
|
PASEO_VOICE_MODE_ENABLED: "0",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const start = await runLocalPaseo(["daemon", "restart", "--port", String(port)], env);
|
||||||
|
assert.strictEqual(
|
||||||
|
start.exitCode,
|
||||||
|
0,
|
||||||
|
`daemon restart should succeed:\nstdout:\n${start.stdout}\nstderr:\n${start.stderr}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const statusResult = await runLocalPaseo(
|
||||||
|
["daemon", "status", "--home", paseoHome, "--json"],
|
||||||
|
env,
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
statusResult.exitCode,
|
||||||
|
0,
|
||||||
|
`daemon status should succeed:\nstdout:\n${statusResult.stdout}\nstderr:\n${statusResult.stderr}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const status = JSON.parse(statusResult.stdout) as {
|
||||||
|
localDaemon?: string;
|
||||||
|
daemonNode?: string;
|
||||||
|
};
|
||||||
|
assert.strictEqual(status.localDaemon, "running", "daemon should be running");
|
||||||
|
assert(status.daemonNode, "daemon status should include daemonNode");
|
||||||
|
assert(
|
||||||
|
!status.daemonNode.startsWith("unknown ("),
|
||||||
|
`daemonNode should resolve cleanly, got: ${status.daemonNode}`,
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
!status.daemonNode.includes("Get-Process") &&
|
||||||
|
!status.daemonNode.includes("Get-CimInstance") &&
|
||||||
|
!status.daemonNode.includes("wmic failed"),
|
||||||
|
`daemonNode should not contain process probe failures, got: ${status.daemonNode}`,
|
||||||
|
);
|
||||||
|
console.log("✓ daemon status resolves daemonNode on Windows\n");
|
||||||
|
} finally {
|
||||||
|
await runLocalPaseo(["daemon", "stop", "--home", paseoHome, "--force"], env);
|
||||||
|
await rm(paseoHome, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("=== Windows daemon status process lookup passed ===");
|
||||||
@@ -361,12 +361,26 @@ async function runCliShimJsonCommand({ appPath, env, args, label }) {
|
|||||||
|
|
||||||
async function smokeCliShim({ appPath, env }) {
|
async function smokeCliShim({ appPath, env }) {
|
||||||
console.log("Packaged desktop smoke: running bundled CLI shim daemon status");
|
console.log("Packaged desktop smoke: running bundled CLI shim daemon status");
|
||||||
await runCliShimCommand({
|
const result = await runCliShimCommand({
|
||||||
appPath,
|
appPath,
|
||||||
env,
|
env,
|
||||||
args: ["daemon", "status"],
|
args: ["daemon", "status"],
|
||||||
label: "Bundled CLI shim daemon status",
|
label: "Bundled CLI shim daemon status",
|
||||||
});
|
});
|
||||||
|
assertCleanDaemonStatusOutput(`${result.stdout}\n${result.stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertCleanDaemonStatusOutput(output) {
|
||||||
|
const failureNeedles = [
|
||||||
|
"Get-CimInstance",
|
||||||
|
"Get-Process :",
|
||||||
|
"Cannot bind parameter",
|
||||||
|
"wmic failed",
|
||||||
|
];
|
||||||
|
const failure = failureNeedles.find((needle) => output.includes(needle));
|
||||||
|
if (failure) {
|
||||||
|
throw new Error(`Bundled CLI shim daemon status included process lookup failure: ${failure}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function smokeCliTerminal({ appPath, env }) {
|
async function smokeCliTerminal({ appPath, env }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user