FN-7418: fix Cursor CLI Windows shim spawning
Fix Cursor runtime probes to execute Windows cmd and bat shims reliably while preserving diagnostics. - Run shared Cursor CLI probe and discovery spawns through the shell only on Windows. - Surface bounded spawn error details in unavailable Cursor probe reasons. - Cover Windows shell spawning, failure diagnostics, probe, and process-manager behavior with tests. - Document the Windows PATH shim invocation contract and add a patch changeset. Files changed: .changeset/fn-7418-cursor-cli-windows-cmd.md | 7 ++ docs/cursor-cli-contract.md | 17 ++++ .../src/__tests__/cli-spawn.test.ts | 103 +++++++++++++++++++++ .../src/__tests__/probe.test.ts | 44 ++++++++- .../src/__tests__/process-manager.test.ts | 24 ++++- .../fusion-plugin-cursor-runtime/src/cli-spawn.ts | 41 ++++++-- plugins/fusion-plugin-cursor-runtime/src/probe.ts | 14 ++- 7 files changed, 236 insertions(+), 14 deletions(-) Fusion-Task-Id: FN-7418 Fusion-Task-Lineage: d689bea7-4676-4190-a60a-f85efab90aba Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -1,25 +1,50 @@
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
function formatSpawnError(error: Error & { code?: unknown }): string {
|
||||
const code = typeof error.code === "string" ? `${error.code}: ` : "";
|
||||
return `spawn error: ${code}${error.message}`.trim();
|
||||
}
|
||||
|
||||
export async function runCursorCommand(binary: string, args: string[], timeoutMs: number): Promise<{ code: number | null; stdout: string; stderr: string }> {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(binary, args, { stdio: ["ignore", "pipe", "pipe"] });
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
const timer = setTimeout(() => {
|
||||
let settled = false;
|
||||
let timer: NodeJS.Timeout | undefined;
|
||||
|
||||
const finish = (result: { code: number | null; stdout: string; stderr: string }) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
if (timer) clearTimeout(timer);
|
||||
resolve(result);
|
||||
};
|
||||
|
||||
/*
|
||||
FNXC:CursorCli 2026-07-02-00:00:
|
||||
Windows Cursor installers and npm-style shims can expose `cursor-agent.cmd` or `cursor.cmd` on PATH, and Node cannot direct-spawn those batch wrappers without the command shell.
|
||||
Keep Unix/macOS on direct spawn so only the known Cursor CLI probe/discovery seam uses shell resolution where Windows requires it.
|
||||
*/
|
||||
const child = spawn(binary, args, {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
shell: process.platform === "win32",
|
||||
});
|
||||
|
||||
timer = setTimeout(() => {
|
||||
try { child.kill("SIGKILL"); } catch {
|
||||
// best effort
|
||||
}
|
||||
resolve({ code: 124, stdout, stderr });
|
||||
finish({ code: 124, stdout, stderr });
|
||||
}, timeoutMs);
|
||||
|
||||
child.stdout?.on("data", (c: Buffer) => { stdout += c.toString("utf-8"); });
|
||||
child.stderr?.on("data", (c: Buffer) => { stderr += c.toString("utf-8"); });
|
||||
child.once("error", () => {
|
||||
clearTimeout(timer);
|
||||
resolve({ code: 127, stdout, stderr });
|
||||
child.once("error", (error: Error & { code?: unknown }) => {
|
||||
const diagnostic = formatSpawnError(error);
|
||||
stderr = stderr ? `${stderr}\n${diagnostic}` : diagnostic;
|
||||
finish({ code: 127, stdout, stderr });
|
||||
});
|
||||
child.once("close", (code) => {
|
||||
clearTimeout(timer);
|
||||
resolve({ code, stdout, stderr });
|
||||
finish({ code, stdout, stderr });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user