diffplug / diffplug/dormouse

quoteCmdArg corrupts arguments containing a literal `"` on cmd surfaces

Open
#162 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
5
Forks
0
Avg merge
13h 46m
Merged PRs (30d)
205

Description

## `quoteCmdArg` corrupts arguments containing a literal `"` on cmd surfaces

When `dor` forwards a command tail (`dor split -- …`, `dor ensure …`) to a pane whose shell is `cmd.exe`, the host renders the argv with [`quoteCmdArg`](https://github.com/diffplug/dormouse/blob/7f88741dadf837a4711d4c725b6f8a9977c496cc/dor/src/commands/shell-quote.ts#L54-L61). For any argument that contains a double-quote, the output is malformed.

### Trace

```ts
function quoteCmdArg(arg: string): string {
if (arg === '') return '""';
const escaped = arg
.replace(/[%]/g, '%%')
.replace(/([&|<>()^"])/g, '^$1'); // caret-escapes the "
if (WINDOWS_SAFE_ARG.test(arg)) return escaped;
return `"${escaped}"`; // ...then wraps the result in quotes
}
```

For `arg = 'say "hi"'` the function:
1. caret-escapes each `"` → `say ^"hi^"`, then
2. wraps in surrounding quotes → `"say ^"hi^""`.

Inside a cmd double-quoted region, `^` is **not** an escape character — it is literal. So the embedded `^"` does not produce an escaped quote; the first `^"` is read as a literal `^` followed by a quote that **closes** the surrounding quoted region early, and the rest of the argument is re-parsed outside quotes. The argument the launched program receives is not `say "hi"`.

The same belt-and-suspenders pattern (caret-escape *and* wrap in quotes) is what the existing test pins for `a&b` → `"a^&b"` ([cli-output.test.mjs:204-206](https://github.com/diffplug/dormouse/blob/7f88741dadf837a4711d4c725b6f8a9977c496cc/dor/test/cli-output.test.mjs#L204-L206)); for `&`/`(`/`)` the caret inside quotes is merely redundant (those chars are already literal inside quotes), so it's harmless-but-odd. For `"` it is actively wrong, and that case is **untested**.

### Why this needs maintainer input rather than a drive-by fix

Correct cmd-line quoting for a literal `"` depends on how the *receiving* program parses its command line (the msvcrt/`CommandLineToArgvW` convention uses `\"` and `""`; a bare cmd builtin differs). Picking the right escaping is a design decision that should be validated on an actual Windows + cmd.exe host, which this CI environment can't do. Flagging rather than guessing.

### Suggested direction (needs Windows verification)

For the `cmd` kind, escape an embedded `"` by doubling it (`""`) or backslash-escaping (`\"`) *inside* the wrapped form, and don't caret-escape characters that already sit inside the surrounding quotes. Add a `cli-output.test.mjs` case with an embedded `"` to pin whatever behavior is chosen.

_Surfaced by the nightly code-quality survey._

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in dor/src/commands/shell-quote.ts at quoteCmdArg and review the existing expectations in dor/test/cli-output.test.mjs around lines 204-206. Validate the chosen literal-quote behavior on a Windows cmd.exe host, then add an embedded-quote regression case and confirm the launched program receives the original argument.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.