Skip to content

Commit 5271f55

Browse files
authored
fix: agentcore dev not working in windows (#951)
1 parent c30ed54 commit 5271f55

3 files changed

Lines changed: 67 additions & 3 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
const mockUnref = vi.fn();
4+
const mockSpawn = vi.fn().mockReturnValue({ unref: mockUnref });
5+
6+
vi.mock('child_process', () => ({
7+
spawn: (...args: unknown[]) => mockSpawn(...args),
8+
}));
9+
10+
describe('openBrowser', () => {
11+
const originalPlatform = process.platform;
12+
13+
beforeEach(() => {
14+
mockSpawn.mockClear();
15+
mockUnref.mockClear();
16+
});
17+
18+
afterEach(() => {
19+
Object.defineProperty(process, 'platform', { value: originalPlatform });
20+
});
21+
22+
it('uses "open" on macOS', async () => {
23+
Object.defineProperty(process, 'platform', { value: 'darwin' });
24+
const { openBrowser } = await import('../utils');
25+
openBrowser('http://localhost:3000');
26+
27+
expect(mockSpawn).toHaveBeenCalledWith('open', ['http://localhost:3000'], {
28+
stdio: 'ignore',
29+
detached: true,
30+
});
31+
expect(mockUnref).toHaveBeenCalled();
32+
});
33+
34+
it('uses "cmd /c start" on Windows to avoid ENOENT', async () => {
35+
Object.defineProperty(process, 'platform', { value: 'win32' });
36+
const { openBrowser } = await import('../utils');
37+
openBrowser('http://localhost:3000');
38+
39+
expect(mockSpawn).toHaveBeenCalledWith('cmd', ['/c', 'start', 'http://localhost:3000'], {
40+
stdio: 'ignore',
41+
detached: true,
42+
});
43+
expect(mockUnref).toHaveBeenCalled();
44+
});
45+
46+
it('uses "xdg-open" on Linux', async () => {
47+
Object.defineProperty(process, 'platform', { value: 'linux' });
48+
const { openBrowser } = await import('../utils');
49+
openBrowser('http://localhost:3000');
50+
51+
expect(mockSpawn).toHaveBeenCalledWith('xdg-open', ['http://localhost:3000'], {
52+
stdio: 'ignore',
53+
detached: true,
54+
});
55+
expect(mockUnref).toHaveBeenCalled();
56+
});
57+
});

src/cli/operations/dev/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { spawn } from 'child_process';
12
import { createConnection, createServer } from 'net';
23

34
/** Check if a port is available on a specific host */
@@ -108,3 +109,10 @@ export function convertEntrypointToModule(entrypoint: string): string {
108109
const path = entrypoint.replace(/\.py$/, '').replace(/\//g, '.');
109110
return `${path}:app`;
110111
}
112+
113+
export function openBrowser(url: string): void {
114+
const isWindows = process.platform === 'win32';
115+
const cmd = isWindows ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open';
116+
const args = isWindows ? ['/c', 'start', url] : [url];
117+
spawn(cmd, args, { stdio: 'ignore', detached: true }).unref();
118+
}

src/cli/operations/dev/web-ui/run-web-ui.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ExecLogger } from '../../../logging';
22
import { findAvailablePort } from '../server';
3+
import { openBrowser } from '../utils';
34
import { WEB_UI_DEFAULT_PORT } from './constants';
45
import { type WebUIOptions, WebUIServer } from './web-server';
5-
import { spawn } from 'child_process';
66

77
export interface RunWebUIOptions {
88
/** Options to pass to WebUIServer (minus uiPort, which is resolved automatically) */
@@ -42,8 +42,7 @@ export async function runWebUI(opts: RunWebUIOptions): Promise<void> {
4242
const chatUrl = url;
4343
console.log(`\nChat UI: ${chatUrl}`);
4444
console.log(`Press Ctrl+C to stop\n`);
45-
const openCmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
46-
spawn(openCmd, [chatUrl], { stdio: 'ignore', detached: true }).unref();
45+
openBrowser(chatUrl);
4746
},
4847
onLog,
4948
});

0 commit comments

Comments
 (0)