Fix Windows question browser opening (#510)

AI assistance: Codex reproduced the issue, implemented the fix, and ran the validation described in the pull request.
This commit is contained in:
Paul Bakaus
2026-08-04 14:09:59 -07:00
committed by GitHub
parent d086837dfc
commit a37b3f6b02
3 changed files with 49 additions and 2 deletions
+26
View File
@@ -0,0 +1,26 @@
import { spawn } from 'node:child_process';
export function browserOpenCommand(url, {
platform = process.platform,
comspec = process.env.ComSpec || process.env.COMSPEC || 'cmd.exe',
} = {}) {
if (platform === 'darwin') return { command: 'open', args: [url] };
if (platform === 'win32') return { command: comspec, args: ['/c', 'start', '', url] };
return { command: 'xdg-open', args: [url] };
}
export function openSystemBrowser(url, {
platform = process.platform,
comspec = process.env.ComSpec || process.env.COMSPEC || 'cmd.exe',
spawnImpl = spawn,
} = {}) {
const { command, args } = browserOpenCommand(url, { platform, comspec });
try {
const child = spawnImpl(command, args, { stdio: 'ignore', detached: true });
child.on('error', () => {});
child.unref();
return true;
} catch {
return false;
}
}
+2 -2
View File
@@ -79,6 +79,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { openSystemBrowser } from './lib/open-system-browser.mjs';
function arg(name, fallback = null) {
const i = process.argv.indexOf(`--${name}`);
@@ -976,8 +977,7 @@ server.listen(portArg, '127.0.0.1', () => {
console.log('Waiting for the user to choose in the browser (Ctrl-C aborts)...');
}
if (!hasFlag('no-open')) {
const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
try { spawn(opener, [url], { stdio: 'ignore', detached: true }).unref(); } catch { /* URL printed anyway */ }
openSystemBrowser(url);
}
if (timeoutSec > 0) {
setTimeout(() => {
+21
View File
@@ -5,6 +5,9 @@ import { writeFileSync, mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { EventEmitter } from 'node:events';
import { browserOpenCommand, openSystemBrowser } from '../skill/scripts/lib/open-system-browser.mjs';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const SCRIPT = path.join(ROOT, 'skill', 'scripts', 'serve-question.mjs');
@@ -39,6 +42,24 @@ const PAYLOAD = {
};
describe('serve-question', () => {
it('opens Windows URLs through cmd.exe and reserves the start title argument', () => {
assert.deepEqual(
browserOpenCommand('http://127.0.0.1:1234/', { platform: 'win32', comspec: 'cmd.exe' }),
{ command: 'cmd.exe', args: ['/c', 'start', '', 'http://127.0.0.1:1234/'] },
);
});
it('absorbs asynchronous system-opener failures after printing the URL', () => {
const child = new EventEmitter();
child.unref = () => {};
assert.equal(openSystemBrowser('http://127.0.0.1:1234/', {
platform: 'linux',
spawnImpl: () => child,
}), true);
assert.equal(child.listenerCount('error'), 1);
assert.doesNotThrow(() => child.emit('error', Object.assign(new Error('missing opener'), { code: 'ENOENT' })));
});
it('serves the page, records the answer, prints ANSWER, exits 0', async () => {
const { child, url, read } = await startServer(PAYLOAD);
const html = await (await fetch(url)).text();