webclaw-mcp 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chrome-launcher.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-launcher.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/chrome-launcher.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Tests for chrome-launcher.ts.
3
+ *
4
+ * Mocks child_process to test platform-specific launch logic.
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import * as childProcess from 'node:child_process';
8
+ import * as os from 'node:os';
9
+ // Mock modules before importing the tested module
10
+ vi.mock('node:child_process', () => ({
11
+ exec: vi.fn(),
12
+ spawn: vi.fn(),
13
+ }));
14
+ vi.mock('node:os', () => ({
15
+ platform: vi.fn(),
16
+ }));
17
+ // Import after mocking
18
+ const { launchChrome } = await import('../chrome-launcher.js');
19
+ const mockExec = vi.mocked(childProcess.exec);
20
+ const mockSpawn = vi.mocked(childProcess.spawn);
21
+ const mockPlatform = vi.mocked(os.platform);
22
+ /** Helper to create a mock spawned process. */
23
+ function mockSpawnProcess() {
24
+ mockSpawn.mockReturnValue({
25
+ unref: vi.fn(),
26
+ });
27
+ }
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ });
31
+ describe('launchChrome', () => {
32
+ it('launches Chrome on macOS with open -a', async () => {
33
+ mockPlatform.mockReturnValue('darwin');
34
+ mockSpawnProcess();
35
+ const result = await launchChrome();
36
+ expect(result).toBe(true);
37
+ expect(mockSpawn).toHaveBeenCalledWith('open', ['-a', 'Google Chrome'], expect.objectContaining({ detached: true, stdio: 'ignore' }));
38
+ });
39
+ it('launches Chrome on Windows with cmd.exe', async () => {
40
+ mockPlatform.mockReturnValue('win32');
41
+ mockSpawnProcess();
42
+ const result = await launchChrome();
43
+ expect(result).toBe(true);
44
+ expect(mockSpawn).toHaveBeenCalledWith('cmd.exe', ['/c', 'start', 'chrome'], expect.objectContaining({ detached: true }));
45
+ });
46
+ it('launches Chrome on Linux by finding executable', async () => {
47
+ mockPlatform.mockReturnValue('linux');
48
+ mockSpawnProcess();
49
+ // First which call succeeds
50
+ mockExec.mockImplementation((...args) => {
51
+ const cb = args[args.length - 1];
52
+ if (typeof cb === 'function')
53
+ cb(null, { stdout: '/usr/bin/google-chrome\n', stderr: '' });
54
+ return {};
55
+ });
56
+ const result = await launchChrome();
57
+ expect(result).toBe(true);
58
+ expect(mockSpawn).toHaveBeenCalledWith('google-chrome', [], expect.objectContaining({ detached: true }));
59
+ });
60
+ it('tries multiple candidates on Linux', async () => {
61
+ mockPlatform.mockReturnValue('linux');
62
+ mockSpawnProcess();
63
+ let callCount = 0;
64
+ mockExec.mockImplementation((...args) => {
65
+ const cb = args[args.length - 1];
66
+ callCount++;
67
+ if (typeof cb === 'function') {
68
+ if (callCount <= 2) {
69
+ // First two candidates not found
70
+ cb(new Error('not found'), { stdout: '', stderr: '' });
71
+ }
72
+ else {
73
+ // Third candidate found (chromium-browser)
74
+ cb(null, { stdout: '/usr/bin/chromium-browser\n', stderr: '' });
75
+ }
76
+ }
77
+ return {};
78
+ });
79
+ const result = await launchChrome();
80
+ expect(result).toBe(true);
81
+ expect(mockSpawn).toHaveBeenCalledWith('chromium-browser', [], expect.objectContaining({ detached: true }));
82
+ });
83
+ it('returns false on Linux when no Chrome executable found', async () => {
84
+ mockPlatform.mockReturnValue('linux');
85
+ // All which calls fail
86
+ mockExec.mockImplementation((...args) => {
87
+ const cb = args[args.length - 1];
88
+ if (typeof cb === 'function')
89
+ cb(new Error('not found'), { stdout: '', stderr: '' });
90
+ return {};
91
+ });
92
+ const result = await launchChrome();
93
+ expect(result).toBe(false);
94
+ });
95
+ });
96
+ //# sourceMappingURL=chrome-launcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-launcher.test.js","sourceRoot":"","sources":["../../src/__tests__/chrome-launcher.test.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ describe('MCP Server stdio startup', () => {
9
9
  const child = spawn('node', [cliPath], {
10
10
  stdio: ['pipe', 'pipe', 'pipe'],
11
11
  timeout: 10000,
12
+ env: { ...process.env, WEBCLAW_PORT: '19070' },
12
13
  });
13
14
  let stderr = '';
14
15
  // Wait for the startup message or timeout
@@ -16,7 +17,7 @@ describe('MCP Server stdio startup', () => {
16
17
  const timeout = setTimeout(() => resolve(), 5000);
17
18
  child.stderr?.on('data', (chunk) => {
18
19
  stderr += chunk.toString();
19
- if (stderr.includes('WebSocket server listening')) {
20
+ if (stderr.includes('MCP Server started')) {
20
21
  clearTimeout(timeout);
21
22
  resolve();
22
23
  }
@@ -31,7 +32,7 @@ describe('MCP Server stdio startup', () => {
31
32
  setTimeout(() => resolve(null), 3000);
32
33
  });
33
34
  // Should have started (stderr contains startup message)
34
- expect(stderr).toContain('WebSocket server listening');
35
+ expect(stderr).toContain('MCP Server started');
35
36
  });
36
37
  it('shows help with --help flag', async () => {
37
38
  const child = spawn('node', [cliPath, '--help'], {
@@ -1 +1 @@
1
- {"version":3,"file":"cli-startup.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-startup.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-startup.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-startup.test.ts"],"names":[],"mappings":"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"}
@@ -63,7 +63,7 @@ describe('MCP Protocol integration (in-process)', () => {
63
63
  const serverVersion = mcpClient.getServerVersion();
64
64
  expect(serverVersion).toBeDefined();
65
65
  expect(serverVersion.name).toBe('webclaw');
66
- expect(serverVersion.version).toBe('0.2.0');
66
+ expect(serverVersion.version).toBe('0.3.1');
67
67
  });
68
68
  // --- tools/list ---
69
69
  it('lists all 8 tools', async () => {
@@ -12,6 +12,7 @@ import { fileURLToPath } from 'node:url';
12
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
13
  const cliPath = resolve(__dirname, '../../dist/cli.js');
14
14
  let child = null;
15
+ let nextPort = 19080;
15
16
  /** Send a JSON-RPC message as NDJSON (newline-delimited JSON). */
16
17
  function sendJsonRpc(proc, message) {
17
18
  proc.stdin.write(JSON.stringify(message) + '\n');
@@ -42,6 +43,30 @@ function createResponseCollector(proc) {
42
43
  });
43
44
  return state;
44
45
  }
46
+ /** Spawn CLI and wait for it to be fully ready (WebSocket + MCP). */
47
+ function spawnAndWaitReady() {
48
+ const port = nextPort++;
49
+ const proc = spawn('node', [cliPath], {
50
+ stdio: ['pipe', 'pipe', 'pipe'],
51
+ timeout: 15000,
52
+ env: { ...process.env, WEBCLAW_PORT: String(port) },
53
+ });
54
+ return new Promise((resolve, reject) => {
55
+ let stderr = '';
56
+ const timeout = setTimeout(() => reject(new Error('Startup timed out')), 10000);
57
+ proc.stderr?.on('data', (chunk) => {
58
+ stderr += chunk.toString();
59
+ if (stderr.includes('MCP Server started')) {
60
+ clearTimeout(timeout);
61
+ resolve(proc);
62
+ }
63
+ });
64
+ proc.on('exit', (code) => {
65
+ clearTimeout(timeout);
66
+ reject(new Error(`Process exited with code ${code} before ready. stderr: ${stderr}`));
67
+ });
68
+ });
69
+ }
45
70
  afterEach(() => {
46
71
  if (child && child.exitCode === null) {
47
72
  child.kill('SIGTERM');
@@ -50,13 +75,8 @@ afterEach(() => {
50
75
  });
51
76
  describe('MCP Server stdio integration', () => {
52
77
  it('responds to initialize request via JSON-RPC', async () => {
53
- child = spawn('node', [cliPath], {
54
- stdio: ['pipe', 'pipe', 'pipe'],
55
- timeout: 15000,
56
- });
78
+ child = await spawnAndWaitReady();
57
79
  const collector = createResponseCollector(child);
58
- // Give the server time to start
59
- await new Promise((r) => setTimeout(r, 1000));
60
80
  sendJsonRpc(child, {
61
81
  jsonrpc: '2.0',
62
82
  id: 1,
@@ -73,15 +93,11 @@ describe('MCP Server stdio integration', () => {
73
93
  const initResponse = collector.responses.find((r) => r.id === 1 && r.result);
74
94
  expect(initResponse).toBeDefined();
75
95
  expect(initResponse.result.serverInfo.name).toBe('webclaw');
76
- expect(initResponse.result.serverInfo.version).toBe('0.2.0');
96
+ expect(initResponse.result.serverInfo.version).toBe('0.3.1');
77
97
  }, 20000);
78
98
  it('lists 8 tools via JSON-RPC after initialization', async () => {
79
- child = spawn('node', [cliPath], {
80
- stdio: ['pipe', 'pipe', 'pipe'],
81
- timeout: 15000,
82
- });
99
+ child = await spawnAndWaitReady();
83
100
  const collector = createResponseCollector(child);
84
- await new Promise((r) => setTimeout(r, 1000));
85
101
  // Send initialize
86
102
  sendJsonRpc(child, {
87
103
  jsonrpc: '2.0',
@@ -126,12 +142,8 @@ describe('MCP Server stdio integration', () => {
126
142
  ]);
127
143
  }, 20000);
128
144
  it('each tool schema from stdio has correct structure', async () => {
129
- child = spawn('node', [cliPath], {
130
- stdio: ['pipe', 'pipe', 'pipe'],
131
- timeout: 15000,
132
- });
145
+ child = await spawnAndWaitReady();
133
146
  const collector = createResponseCollector(child);
134
- await new Promise((r) => setTimeout(r, 1000));
135
147
  sendJsonRpc(child, {
136
148
  jsonrpc: '2.0',
137
149
  id: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-stdio-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-stdio-integration.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-stdio-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/mcp-stdio-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ws-client-ensure-connected.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-client-ensure-connected.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ws-client-ensure-connected.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Tests for WebSocketClient.ensureConnected() and auto-launch behavior.
3
+ *
4
+ * Uses a real WebSocket server but mocks the chrome-launcher module.
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import WebSocket from 'ws';
8
+ // Mock chrome-launcher before importing ws-client
9
+ vi.mock('../chrome-launcher.js', () => ({
10
+ launchChrome: vi.fn(),
11
+ }));
12
+ const { WebSocketClient } = await import('../ws-client.js');
13
+ const chromeLauncher = await import('../chrome-launcher.js');
14
+ const mockLaunchChrome = vi.mocked(chromeLauncher.launchChrome);
15
+ let nextPort = 19200;
16
+ let wsClient = null;
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+ afterEach(async () => {
21
+ if (wsClient) {
22
+ await wsClient.close().catch(() => { });
23
+ wsClient = null;
24
+ }
25
+ // Allow pending async operations to flush
26
+ await new Promise((r) => setTimeout(r, 100));
27
+ });
28
+ describe('WebSocketClient.ensureConnected()', () => {
29
+ it('resolves immediately when already connected', async () => {
30
+ const port = nextPort++;
31
+ wsClient = await WebSocketClient.create(port);
32
+ // Simulate extension connecting
33
+ const ext = new WebSocket(`ws://127.0.0.1:${port}`);
34
+ await new Promise((resolve) => ext.on('open', resolve));
35
+ // Wait for server to process connection
36
+ await new Promise((r) => setTimeout(r, 50));
37
+ // Should already be connected — no launch needed
38
+ await wsClient.ensureConnected(1000);
39
+ expect(wsClient.isConnected()).toBe(true);
40
+ expect(mockLaunchChrome).not.toHaveBeenCalled();
41
+ ext.close();
42
+ await new Promise((r) => setTimeout(r, 100));
43
+ });
44
+ it('launches Chrome and waits for connection', async () => {
45
+ const port = nextPort++;
46
+ wsClient = await WebSocketClient.create(port);
47
+ mockLaunchChrome.mockResolvedValue(true);
48
+ // Simulate extension connecting after a short delay (like Chrome launching)
49
+ const connectPromise = wsClient.ensureConnected(5000);
50
+ await new Promise((r) => setTimeout(r, 200));
51
+ const ext = new WebSocket(`ws://127.0.0.1:${port}`);
52
+ await new Promise((resolve) => ext.on('open', resolve));
53
+ await connectPromise;
54
+ expect(mockLaunchChrome).toHaveBeenCalled();
55
+ expect(wsClient.isConnected()).toBe(true);
56
+ ext.close();
57
+ await new Promise((r) => setTimeout(r, 100));
58
+ });
59
+ it('throws when Chrome cannot be launched', async () => {
60
+ const port = nextPort++;
61
+ wsClient = await WebSocketClient.create(port);
62
+ mockLaunchChrome.mockResolvedValue(false);
63
+ await expect(wsClient.ensureConnected(1000)).rejects.toThrow('Could not launch Chrome automatically');
64
+ });
65
+ it('throws extension install message when Chrome was launched but no connection', async () => {
66
+ const port = nextPort++;
67
+ wsClient = await WebSocketClient.create(port);
68
+ mockLaunchChrome.mockResolvedValue(true);
69
+ await expect(wsClient.ensureConnected(500)).rejects.toThrow('WebClaw extension did not connect');
70
+ });
71
+ it('does not launch Chrome again after first launch', async () => {
72
+ const port = nextPort++;
73
+ wsClient = await WebSocketClient.create(port);
74
+ mockLaunchChrome.mockResolvedValue(true);
75
+ // First call: launches Chrome, but times out (no extension connects)
76
+ await expect(wsClient.ensureConnected(300)).rejects.toThrow();
77
+ expect(mockLaunchChrome).toHaveBeenCalledTimes(1);
78
+ // Second call: should NOT launch Chrome again
79
+ mockLaunchChrome.mockClear();
80
+ await expect(wsClient.ensureConnected(300)).rejects.toThrow();
81
+ expect(mockLaunchChrome).not.toHaveBeenCalled();
82
+ });
83
+ it('deduplicates concurrent ensureConnected calls', async () => {
84
+ const port = nextPort++;
85
+ wsClient = await WebSocketClient.create(port);
86
+ mockLaunchChrome.mockResolvedValue(true);
87
+ // Call ensureConnected twice concurrently
88
+ const p1 = wsClient.ensureConnected(5000);
89
+ const p2 = wsClient.ensureConnected(5000);
90
+ // Simulate extension connecting
91
+ await new Promise((r) => setTimeout(r, 200));
92
+ const ext = new WebSocket(`ws://127.0.0.1:${port}`);
93
+ await new Promise((resolve) => ext.on('open', resolve));
94
+ await Promise.all([p1, p2]);
95
+ // launchChrome should only be called once
96
+ expect(mockLaunchChrome).toHaveBeenCalledTimes(1);
97
+ ext.close();
98
+ await new Promise((r) => setTimeout(r, 100));
99
+ });
100
+ });
101
+ describe('WebSocketClient.request() auto-connect', () => {
102
+ it('calls ensureConnected when not connected', async () => {
103
+ const port = nextPort++;
104
+ wsClient = await WebSocketClient.create(port);
105
+ mockLaunchChrome.mockResolvedValue(true);
106
+ // Start request — it triggers ensureConnected internally
107
+ const requestPromise = wsClient.request('navigate', { url: 'https://example.com' });
108
+ // Simulate extension connecting and set up message handler
109
+ await new Promise((r) => setTimeout(r, 200));
110
+ const ext = new WebSocket(`ws://127.0.0.1:${port}`);
111
+ await new Promise((resolve) => {
112
+ ext.on('open', resolve);
113
+ });
114
+ // Handle incoming request and respond
115
+ ext.on('message', (data) => {
116
+ const msg = JSON.parse(data.toString());
117
+ if (msg.type === 'request') {
118
+ ext.send(JSON.stringify({
119
+ id: msg.id,
120
+ type: 'response',
121
+ method: msg.method,
122
+ payload: { url: 'https://example.com', title: 'Example', tabId: 1 },
123
+ timestamp: Date.now(),
124
+ }));
125
+ }
126
+ });
127
+ const result = await requestPromise;
128
+ expect(result.type).toBe('response');
129
+ expect(mockLaunchChrome).toHaveBeenCalled();
130
+ ext.close();
131
+ await new Promise((r) => setTimeout(r, 100));
132
+ });
133
+ });
134
+ //# sourceMappingURL=ws-client-ensure-connected.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-client-ensure-connected.test.js","sourceRoot":"","sources":["../../src/__tests__/ws-client-ensure-connected.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Launch Chrome. Returns true if launch was attempted successfully. */
2
+ export declare function launchChrome(): Promise<boolean>;
3
+ //# sourceMappingURL=chrome-launcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-launcher.d.ts","sourceRoot":"","sources":["../src/chrome-launcher.ts"],"names":[],"mappings":"AAYA,wEAAwE;AACxE,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAwCrD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Platform-aware Chrome detection and launch utilities.
3
+ *
4
+ * Supports macOS, Linux (including WSL2), and Windows.
5
+ * On all platforms, launches the local/native Chrome.
6
+ */
7
+ import { exec, spawn } from 'node:child_process';
8
+ import { promisify } from 'node:util';
9
+ import { platform } from 'node:os';
10
+ const execAsync = promisify(exec);
11
+ /** Launch Chrome. Returns true if launch was attempted successfully. */
12
+ export async function launchChrome() {
13
+ try {
14
+ const os = platform();
15
+ if (os === 'darwin') {
16
+ spawn('open', ['-a', 'Google Chrome'], {
17
+ detached: true,
18
+ stdio: 'ignore',
19
+ }).unref();
20
+ return true;
21
+ }
22
+ if (os === 'win32') {
23
+ spawn('cmd.exe', ['/c', 'start', 'chrome'], {
24
+ detached: true,
25
+ stdio: 'ignore',
26
+ }).unref();
27
+ return true;
28
+ }
29
+ // Linux (including WSL2) — use the local Chrome
30
+ const candidates = [
31
+ 'google-chrome',
32
+ 'google-chrome-stable',
33
+ 'chromium-browser',
34
+ 'chromium',
35
+ ];
36
+ for (const cmd of candidates) {
37
+ try {
38
+ await execAsync(`which ${cmd}`);
39
+ spawn(cmd, [], { detached: true, stdio: 'ignore' }).unref();
40
+ return true;
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ //# sourceMappingURL=chrome-launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-launcher.js","sourceRoot":"","sources":["../src/chrome-launcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;QAEtB,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpB,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE;gBACrC,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YACnB,KAAK,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE;gBAC1C,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,gDAAgD;QAChD,MAAM,UAAU,GAAG;YACjB,eAAe;YACf,sBAAsB;YACtB,kBAAkB;YAClB,UAAU;SACX,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;gBAChC,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;gBAC5D,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
package/dist/cli.js CHANGED
@@ -44,11 +44,11 @@ else if (args[0] === 'install') {
44
44
  }
45
45
  else {
46
46
  const port = Number(process.env[WEBSOCKET_PORT_ENV]) || WEBSOCKET_DEFAULT_PORT;
47
- const wsClient = new WebSocketClient(port);
47
+ const wsClient = await WebSocketClient.create(port);
48
+ console.error(`[WebClaw] WebSocket server listening on 127.0.0.1:${port}`);
48
49
  const server = createWebClawServer({ wsClient });
49
50
  const transport = new StdioServerTransport();
50
51
  await server.connect(transport);
51
52
  console.error(`[WebClaw] MCP Server started (stdio transport)`);
52
- console.error(`[WebClaw] WebSocket server listening on 127.0.0.1:${port}`);
53
53
  }
54
54
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;IAaV,kBAAkB,gCAAgC,sBAAsB;;;;;;;;;+CAS7B,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;KAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;IACjC,MAAM,OAAO,EAAE,CAAC;AAClB,CAAC;KAAM,CAAC;IACN,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,sBAAsB,CAAC;IAC/E,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAChE,OAAO,CAAC,KAAK,CAAC,qDAAqD,IAAI,EAAE,CAAC,CAAC;AAC7E,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;IAaV,kBAAkB,gCAAgC,sBAAsB;;;;;;;;;+CAS7B,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;KAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;IACjC,MAAM,OAAO,EAAE,CAAC;AAClB,CAAC;KAAM,CAAC;IACN,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,sBAAsB,CAAC;IAC/E,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,CAAC,KAAK,CAAC,qDAAqD,IAAI,EAAE,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;AAClE,CAAC"}
package/dist/server.js CHANGED
@@ -9,7 +9,7 @@ import { z } from 'zod';
9
9
  export function createWebClawServer(options) {
10
10
  const server = new McpServer({
11
11
  name: 'webclaw',
12
- version: '0.2.0',
12
+ version: '0.3.1',
13
13
  });
14
14
  const wsClient = options.wsClient;
15
15
  // --- Tool: navigate_to ---
@@ -3,9 +3,25 @@ export declare class WebSocketClient {
3
3
  private wss;
4
4
  private connection;
5
5
  private pendingRequests;
6
- constructor(port: number, host?: string);
6
+ private connectingPromise;
7
+ private chromeLaunched;
8
+ private constructor();
9
+ /** Create a WebSocketClient and wait for the server to be listening. */
10
+ static create(port: number, host?: string): Promise<WebSocketClient>;
7
11
  private handleMessage;
8
- /** Send a request and wait for the response */
12
+ /**
13
+ * Ensure the Chrome extension is connected.
14
+ *
15
+ * If not connected:
16
+ * 1. If Chrome hasn't been launched yet this session, launch it
17
+ * 2. Wait for the extension to connect (up to timeoutMs)
18
+ * 3. If extension doesn't connect, suggest installing the extension
19
+ *
20
+ * Chrome is only launched once per session to prevent multiple instances.
21
+ */
22
+ ensureConnected(timeoutMs?: number): Promise<void>;
23
+ private _doEnsureConnected;
24
+ /** Send a request and wait for the response. Auto-connects if needed. */
9
25
  request(method: BridgeMethod, payload?: unknown, timeoutMs?: number): Promise<BridgeMessage>;
10
26
  isConnected(): boolean;
11
27
  close(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AASlE,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAqC;gBAEhD,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc;IAiC5C,OAAO,CAAC,aAAa;IAmBrB,+CAA+C;IACzC,OAAO,CACX,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,OAAY,EACrB,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC;IAkBzB,WAAW,IAAI,OAAO;IAIhB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
1
+ {"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAalE,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO;IAqCP,wEAAwE;WAC3D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAS/E,OAAO,CAAC,aAAa;IAmBrB;;;;;;;;;OASG;IACG,eAAe,CAAC,SAAS,SAA8B,GAAG,OAAO,CAAC,IAAI,CAAC;YAc/D,kBAAkB;IA+ChC,yEAAyE;IACnE,OAAO,CACX,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,OAAY,EACrB,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC;IAuBzB,WAAW,IAAI,OAAO;IAIhB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
package/dist/ws-client.js CHANGED
@@ -3,15 +3,27 @@
3
3
  *
4
4
  * Replaces NativeMessagingClient. Runs a WebSocket server on localhost
5
5
  * that the extension's Service Worker connects to.
6
+ *
7
+ * When a tool request is made and the extension is not connected,
8
+ * automatically detects/launches Chrome and waits for the extension
9
+ * to connect.
6
10
  */
7
11
  import { WebSocketServer, WebSocket } from 'ws';
8
12
  import { createRequest, isBridgeMessage } from 'webclaw-shared';
13
+ import { launchChrome } from './chrome-launcher.js';
14
+ /** Default timeout for waiting for Chrome extension to connect. */
15
+ const ENSURE_CONNECTED_TIMEOUT_MS = 15_000;
9
16
  export class WebSocketClient {
10
17
  wss;
11
18
  connection = null;
12
19
  pendingRequests = new Map();
13
- constructor(port, host = '127.0.0.1') {
14
- this.wss = new WebSocketServer({ port, host });
20
+ connectingPromise = null;
21
+ chromeLaunched = false;
22
+ constructor(wss) {
23
+ this.wss = wss;
24
+ this.wss.on('error', (err) => {
25
+ console.error('[WebClaw WS] Server error:', err.message);
26
+ });
15
27
  this.wss.on('connection', (ws) => {
16
28
  // Only allow one connection; close the previous one
17
29
  if (this.connection && this.connection.readyState === WebSocket.OPEN) {
@@ -39,6 +51,15 @@ export class WebSocketClient {
39
51
  });
40
52
  });
41
53
  }
54
+ /** Create a WebSocketClient and wait for the server to be listening. */
55
+ static async create(port, host = '127.0.0.1') {
56
+ const wss = new WebSocketServer({ port, host });
57
+ await new Promise((resolve, reject) => {
58
+ wss.once('listening', resolve);
59
+ wss.once('error', reject);
60
+ });
61
+ return new WebSocketClient(wss);
62
+ }
42
63
  handleMessage(message) {
43
64
  if (!isBridgeMessage(message)) {
44
65
  console.error('[WebClaw WS] Invalid message format:', message);
@@ -55,8 +76,74 @@ export class WebSocketClient {
55
76
  pending.resolve(bridgeMessage);
56
77
  }
57
78
  }
58
- /** Send a request and wait for the response */
79
+ /**
80
+ * Ensure the Chrome extension is connected.
81
+ *
82
+ * If not connected:
83
+ * 1. If Chrome hasn't been launched yet this session, launch it
84
+ * 2. Wait for the extension to connect (up to timeoutMs)
85
+ * 3. If extension doesn't connect, suggest installing the extension
86
+ *
87
+ * Chrome is only launched once per session to prevent multiple instances.
88
+ */
89
+ async ensureConnected(timeoutMs = ENSURE_CONNECTED_TIMEOUT_MS) {
90
+ if (this.isConnected())
91
+ return;
92
+ // Deduplicate concurrent calls
93
+ if (this.connectingPromise)
94
+ return this.connectingPromise;
95
+ this.connectingPromise = this._doEnsureConnected(timeoutMs);
96
+ try {
97
+ await this.connectingPromise;
98
+ }
99
+ finally {
100
+ this.connectingPromise = null;
101
+ }
102
+ }
103
+ async _doEnsureConnected(timeoutMs) {
104
+ if (!this.chromeLaunched) {
105
+ console.error('[WebClaw] Chrome extension not connected. Launching Chrome...');
106
+ const launched = await launchChrome();
107
+ if (!launched) {
108
+ throw new Error('Could not launch Chrome automatically.\n' +
109
+ 'Please start Chrome manually with the WebClaw extension installed.');
110
+ }
111
+ this.chromeLaunched = true;
112
+ console.error('[WebClaw] Chrome launched. Waiting for extension to connect...');
113
+ }
114
+ else {
115
+ console.error('[WebClaw] Waiting for Chrome extension to reconnect...');
116
+ }
117
+ // Wait for extension to connect via WebSocket
118
+ return new Promise((resolve, reject) => {
119
+ // Check again — might have connected while we were launching Chrome
120
+ if (this.isConnected()) {
121
+ resolve();
122
+ return;
123
+ }
124
+ const timeout = setTimeout(() => {
125
+ this.wss.removeListener('connection', onConnection);
126
+ reject(new Error('Chrome was launched but the WebClaw extension did not connect.\n' +
127
+ 'Please ensure the WebClaw extension is installed and enabled:\n' +
128
+ ' 1. Open chrome://extensions/\n' +
129
+ ' 2. Enable Developer mode\n' +
130
+ ' 3. Click "Load unpacked" and select the extension dist/ folder\n' +
131
+ ' 4. Verify the extension is enabled'));
132
+ }, timeoutMs);
133
+ const onConnection = () => {
134
+ clearTimeout(timeout);
135
+ // Small delay to let the connection handler in constructor finish setting up
136
+ setTimeout(() => resolve(), 50);
137
+ };
138
+ this.wss.once('connection', onConnection);
139
+ });
140
+ }
141
+ /** Send a request and wait for the response. Auto-connects if needed. */
59
142
  async request(method, payload = {}, timeoutMs = 60_000) {
143
+ // Auto-connect: launch Chrome if needed and wait for extension
144
+ if (!this.isConnected()) {
145
+ await this.ensureConnected();
146
+ }
60
147
  if (!this.connection || this.connection.readyState !== WebSocket.OPEN) {
61
148
  throw new Error('Chrome extension is not connected');
62
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webclaw-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "WebClaw MCP Server - WebMCP-native browser agent for Chrome",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,7 +35,7 @@
35
35
  "@modelcontextprotocol/sdk": "^1.0.0",
36
36
  "ws": "^8.18.0",
37
37
  "zod": "^3.23.0",
38
- "webclaw-shared": "0.2.0"
38
+ "webclaw-shared": "0.3.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^20.0.0",