mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 17:52:49 +00:00
* fix(providers): launch plugin CLIs on Windows and tolerate Muse startup Plugin providers bypassed the core Windows launcher and the plugin host exposed an empty server SDK module. Share the launcher through the SDK and bind it in the host. Give Muse initialization its own deadline because native startup traverses session history before answering MSP. * fix(providers): terminate Windows launcher process trees A command-script launcher leaves the CLI behind cmd.exe. Expose forced process-tree termination in the server SDK, use it for Muse and SDK ACP teardown, and bound Muse closing so inherited streams cannot leave callers waiting forever. * test(muse): keep platform setup outside the teardown assertion * refactor(plugin): expose process capabilities without quoting helpers * fix(providers): close process trees on uncorrelated protocol errors
47 lines
1.8 KiB
TypeScript
47 lines
1.8 KiB
TypeScript
import { extname } from "node:path";
|
|
|
|
export function isWindowsCommandScript(executablePath: string): boolean {
|
|
const extension = extname(executablePath).toLowerCase();
|
|
return process.platform === "win32" && (extension === ".cmd" || extension === ".bat");
|
|
}
|
|
|
|
function escapeWindowsCmdValue(value: string): string {
|
|
if (process.platform !== "win32") return value;
|
|
|
|
const isQuoted = value.startsWith('"') && value.endsWith('"');
|
|
const unquoted = isQuoted ? value.slice(1, -1) : value;
|
|
// Do NOT double `%` here. cmd.exe only collapses `%%` → `%` inside batch
|
|
// files; on the command line / `cmd /c "..."` `%%` stays literal, which
|
|
// breaks args like git's `--format=%(refname)` (git treats `%%` as the
|
|
// escape for a literal `%`, so the format atoms become literals).
|
|
const escaped = unquoted.replace(/([&|^<>()!])/g, "^$1");
|
|
|
|
if (isQuoted || /[\s"]/u.test(unquoted)) {
|
|
const quoted = escaped
|
|
.replace(/(\\*)"/g, (_match, slashes: string) => `${slashes}${slashes}\\"`)
|
|
.replace(/\\+$/u, (slashes) => `${slashes}${slashes}`);
|
|
return `"${quoted}"`;
|
|
}
|
|
|
|
return escaped;
|
|
}
|
|
|
|
/**
|
|
* When spawning with `shell: true` on Windows, the command is passed to
|
|
* `cmd.exe /d /s /c "command args"`. The `/s` strips outer quotes, so a
|
|
* command path with spaces (e.g. `C:\Program Files\...`) is split at the
|
|
* space. Wrapping it in quotes produces the correct `"C:\Program Files\..." args`.
|
|
*/
|
|
export function quoteWindowsCommand(command: string): string {
|
|
return escapeWindowsCmdValue(command);
|
|
}
|
|
|
|
/**
|
|
* `spawn(..., { shell: true })` on Windows also passes argv through `cmd.exe`.
|
|
* Any argument containing spaces must be quoted or it will be split before the
|
|
* child process sees it.
|
|
*/
|
|
export function quoteWindowsArgument(argument: string): string {
|
|
return escapeWindowsCmdValue(argument);
|
|
}
|