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.
- package/dist/__tests__/chrome-launcher.test.d.ts +2 -0
- package/dist/__tests__/chrome-launcher.test.d.ts.map +1 -0
- package/dist/__tests__/chrome-launcher.test.js +96 -0
- package/dist/__tests__/chrome-launcher.test.js.map +1 -0
- package/dist/__tests__/cli-startup.test.js +3 -2
- package/dist/__tests__/cli-startup.test.js.map +1 -1
- package/dist/__tests__/mcp-protocol-integration.test.js +1 -1
- package/dist/__tests__/mcp-stdio-integration.test.js +29 -17
- package/dist/__tests__/mcp-stdio-integration.test.js.map +1 -1
- package/dist/__tests__/ws-client-ensure-connected.test.d.ts +2 -0
- package/dist/__tests__/ws-client-ensure-connected.test.d.ts.map +1 -0
- package/dist/__tests__/ws-client-ensure-connected.test.js +134 -0
- package/dist/__tests__/ws-client-ensure-connected.test.js.map +1 -0
- package/dist/chrome-launcher.d.ts +3 -0
- package/dist/chrome-launcher.d.ts.map +1 -0
- package/dist/chrome-launcher.js +52 -0
- package/dist/chrome-launcher.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/ws-client.d.ts +18 -2
- package/dist/ws-client.d.ts.map +1 -1
- package/dist/ws-client.js +90 -3
- package/dist/ws-client.js.map +1 -1
- package/package.json +2 -2
|
@@ -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('
|
|
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('
|
|
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":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;AAExD,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE;YACrC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,OAAO,EAAE,KAAK;
|
|
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.
|
|
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 =
|
|
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.
|
|
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 =
|
|
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 =
|
|
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":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;AAExD,IAAI,KAAK,GAAwB,IAAI,CAAC;
|
|
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 @@
|
|
|
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 @@
|
|
|
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 =
|
|
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,
|
|
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
package/dist/ws-client.d.ts
CHANGED
|
@@ -3,9 +3,25 @@ export declare class WebSocketClient {
|
|
|
3
3
|
private wss;
|
|
4
4
|
private connection;
|
|
5
5
|
private pendingRequests;
|
|
6
|
-
|
|
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
|
-
/**
|
|
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>;
|
package/dist/ws-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
/**
|
|
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
|
}
|
package/dist/ws-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"AAAA
|
|
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.
|
|
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.
|
|
38
|
+
"webclaw-shared": "0.3.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^20.0.0",
|