Files
Stefan Broenner f3f80acbf2 fix(plugins): preserve quoted arguments and survive an unreachable release API (#779)
* fix(plugins): preserve quoted arguments and survive an unreachable release API

Two defects made the published excel-cli and excel-mcp plugins fail in normal use.

Quoted arguments were destroyed in transit. Windows PowerShell rebuilds the command
line when invoking a native executable and drops embedded double quotes, so every
documented inline JSON example arrived as [[Name,Amount]] instead of
[["Name","Amount"]] when run through the plugin wrapper or the generated PATH shim.
Escaping at the call site cannot fix this. start-cli.ps1 now builds the command line
itself using the standard MSVCRT quoting rules and passes it to ProcessStartInfo
verbatim; stdio is inherited, so interactive and piped use are unchanged. The .cmd
shim had a second, independent mangling layer -- powershell -File strips quotes
before the wrapper ever runs -- so it now resolves the executable up front and
invokes it directly, letting cmd forward %* untouched.

The bootstrap also aborted whenever the GitHub release API was unreachable, even
with the correct runtime already downloaded and extracted. A rate limit (60/hr per
IP, shared behind corporate NAT) or an offline machine therefore stopped the MCP
server from starting at all. A failed freshness check now degrades to the cached
runtime and warns on stderr -- never stdout, which carries the resolved path and is
the MCP stdio channel -- and records the attempt so one dead endpoint is not retried
by every command in the session. With no usable cached runtime the failure stays
loud and still points at the release page.

Relatedly, the download was attempted before checking whether a valid runtime was
already present, leaving the early return unreachable. Any cleanup tool that
reclaimed the cached .zip bricked the plugin offline even though the extracted
binary was intact and tag-matched. Resolution now happens first and short-circuits.

The two download.ps1 copies remain byte-identical modulo 13 plugin-specific tokens;
a normalize-and-compare test now enforces that so a fix applied to one and forgotten
in the other fails in CI instead of shipping. Argument escaping is verified by
round-tripping through CommandLineToArgvW, the same parser the CRT uses to split a
process command line, which keeps the assertion independent of the PowerShell
version running the tests.

start-mcp.ps1 shares the wrapper pattern but is deliberately left alone: it never
receives arguments, so the bug cannot manifest there, and it is not worth perturbing
the MCP stdio handshake in a fix release.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462

* fix(plugins): validate download.ps1 before writing excelcli shims

install-global.ps1 generates a .cmd shim that resolves the runtime by
invoking bin\download.ps1, but it only validated that bin\start-cli.ps1
existed. With download.ps1 missing or corrupt the installer reported
success and wrote shims that failed later, at first use, with an opaque
error from cmd rather than a pointer to the real problem.

Guard the dependency up front, alongside the existing wrapper check and
before any shim or PATH mutation, so a broken plugin tree fails fast and
leaves nothing behind.

The new test pins the "leaves nothing behind" half specifically: it runs
the real installer against a sandbox plugin tree with only download.ps1
absent, redirects USERPROFILE so a regression writes into the sandbox,
and asserts both a non-zero exit and that ~/.copilot/bin was never
created. Mutation-verified: removing the guard makes it fail.

excel-mcp's installer has no such dependency, so this is excel-cli only.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: edb4d8c2-36e0-4719-ab55-4d501b7a2462
2026-08-20 04:50:31 +00:00
..