Skip to content

Commit fef669f

Browse files
committed
Fix Windows browser opener
Pass the browser target through an environment variable instead of as a positional PowerShell argument after -Command. This prevents Windows PowerShell from rejecting status-page URLs as extra command tokens. Copilot-Session: a9952624-0a25-4d6e-ae67-537c962a8a60
1 parent 78aa621 commit fef669f

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

plugins/power-pages/scripts/lib/default-browser.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@ function openInDefaultBrowser(target, deps = {}) {
1010
execFile('open', [target], { stdio: 'ignore' });
1111
} else if (platform === 'win32') {
1212
// Avoid `cmd /c start`: cmd.exe reparses metacharacters such as `&` in URL
13-
// query strings. Passing the target as a PowerShell argument keeps it as
14-
// data while still letting Windows choose the registered default handler.
15-
execFile('powershell.exe', ['-NoProfile', '-Command', 'param([string]$Target) Start-Process -FilePath $Target', target], { stdio: 'ignore', windowsHide: true });
13+
// query strings. Also avoid passing the URL as a positional PowerShell
14+
// argument after `-Command`; Windows PowerShell can treat it as an extra
15+
// command token instead of binding it to `param(...)`. An environment
16+
// variable keeps URLs and file paths as inert data while Start-Process still
17+
// uses the registered default handler.
18+
execFile('powershell.exe', ['-NoProfile', '-Command', 'Start-Process -FilePath $env:COPILOT_OPEN_TARGET'], {
19+
stdio: 'ignore',
20+
windowsHide: true,
21+
env: { ...process.env, COPILOT_OPEN_TARGET: target },
22+
});
1623
} else {
1724
execFile('xdg-open', [target], { stdio: 'ignore' });
1825
}

plugins/power-pages/scripts/tests/open-url.test.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ test('openInDefaultBrowser uses platform-specific opener commands', () => {
1414
openInDefaultBrowser('https://example.test/a path?q=1&x=2', { os: { platform: () => 'win32' }, execFileSync });
1515
openInDefaultBrowser('https://example.test', { os: { platform: () => 'linux' }, execFileSync });
1616

17-
assert.deepEqual(calls, [
18-
['open', ['https://example.test'], { stdio: 'ignore' }],
19-
['powershell.exe', ['-NoProfile', '-Command', 'param([string]$Target) Start-Process -FilePath $Target', 'https://example.test/a path?q=1&x=2'], { stdio: 'ignore', windowsHide: true }],
20-
['xdg-open', ['https://example.test'], { stdio: 'ignore' }],
21-
]);
17+
assert.deepEqual(calls[0], ['open', ['https://example.test'], { stdio: 'ignore' }]);
18+
assert.equal(calls[1][0], 'powershell.exe');
19+
assert.deepEqual(calls[1][1], ['-NoProfile', '-Command', 'Start-Process -FilePath $env:COPILOT_OPEN_TARGET']);
20+
assert.equal(calls[1][2].stdio, 'ignore');
21+
assert.equal(calls[1][2].windowsHide, true);
22+
assert.equal(calls[1][2].env.COPILOT_OPEN_TARGET, 'https://example.test/a path?q=1&x=2');
23+
assert.deepEqual(calls[2], ['xdg-open', ['https://example.test'], { stdio: 'ignore' }]);
2224
});
2325

2426
test('openUrl validates URL shape and reports opener failures without throwing', () => {

0 commit comments

Comments
 (0)