venombrowser 4.1.0 → 4.1.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/bin/venombrowser-chat.js
CHANGED
package/bin/venombrowser-cli.js
CHANGED
package/bin/venombrowser-mcp.js
CHANGED
|
@@ -1,30 +1,148 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* VenomBrowser MCP Server — CLI entry point
|
|
4
|
-
* Starts the MCP server in stdio mode for agent integration.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* VenomBrowser MCP Server — CLI entry point
|
|
4
|
+
* Starts the MCP server in stdio mode for agent integration.
|
|
5
|
+
*
|
|
6
|
+
* Kimi-style: Auto-starts the bridge daemon if it's not already running.
|
|
7
|
+
* The agent just configures this MCP entry — no manual `venombrowser start` needed.
|
|
8
|
+
*
|
|
9
|
+
* Usage: node bin/venombrowser-mcp.js
|
|
10
|
+
* Or: npm run mcp
|
|
11
|
+
*
|
|
12
|
+
* Agent configuration example (Claude Code / Cursor):
|
|
13
|
+
* {
|
|
14
|
+
* "mcpServers": {
|
|
15
|
+
* "venombrowser": {
|
|
16
|
+
* "command": "venombrowser-mcp",
|
|
17
|
+
* "env": { "BRIDGE_PORT": "10086" }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* Agent configuration example (OpenCode):
|
|
23
|
+
* {
|
|
24
|
+
* "mcp": {
|
|
25
|
+
* "venombrowser": {
|
|
26
|
+
* "type": "local",
|
|
27
|
+
* "command": ["venombrowser-mcp"],
|
|
28
|
+
* "environment": { "BRIDGE_PORT": "10086" }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// Load .env for default config — agents can also pass env vars directly
|
|
35
|
+
require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
|
|
36
|
+
|
|
37
|
+
const path = require('path');
|
|
38
|
+
const http = require('http');
|
|
39
|
+
const { spawn } = require('child_process');
|
|
40
|
+
const fs = require('fs');
|
|
41
|
+
|
|
42
|
+
const BRIDGE_PORT = parseInt(process.env.BRIDGE_PORT || '10086', 10);
|
|
43
|
+
const BRIDGE_HOST = process.env.BRIDGE_HOST || '127.0.0.1';
|
|
44
|
+
const MAX_WAIT_ATTEMPTS = 30; // 30 × 500ms = 15 seconds max wait
|
|
45
|
+
const POLL_INTERVAL_MS = 500;
|
|
46
|
+
|
|
47
|
+
// ─── Health check ─────────────────────────────────────────────────────────
|
|
48
|
+
function checkBridgeHealth() {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const req = http.get(
|
|
51
|
+
`http://${BRIDGE_HOST}:${BRIDGE_PORT}/health`,
|
|
52
|
+
{ timeout: 2000 },
|
|
53
|
+
(res) => {
|
|
54
|
+
let body = '';
|
|
55
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
56
|
+
res.on('end', () => {
|
|
57
|
+
try {
|
|
58
|
+
const data = JSON.parse(body);
|
|
59
|
+
resolve(data.server === 'ok');
|
|
60
|
+
} catch {
|
|
61
|
+
resolve(false);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
req.on('error', () => resolve(false));
|
|
67
|
+
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ─── Wait for bridge to become ready ──────────────────────────────────────
|
|
72
|
+
function sleep(ms) {
|
|
73
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function waitForBridge() {
|
|
77
|
+
for (let i = 0; i < MAX_WAIT_ATTEMPTS; i++) {
|
|
78
|
+
if (await checkBridgeHealth()) return true;
|
|
79
|
+
await sleep(POLL_INTERVAL_MS);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Auto-start the bridge daemon ─────────────────────────────────────────
|
|
85
|
+
async function ensureBridgeRunning() {
|
|
86
|
+
// Already running? Great, nothing to do.
|
|
87
|
+
if (await checkBridgeHealth()) {
|
|
88
|
+
console.error('[VenomBrowser MCP] Bridge daemon already running on port ' + BRIDGE_PORT);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.error('[VenomBrowser MCP] Bridge daemon not running — auto-starting...');
|
|
93
|
+
|
|
94
|
+
const serverScript = path.join(__dirname, 'venombrowser-server.js');
|
|
95
|
+
const serverCwd = path.join(__dirname, '..');
|
|
96
|
+
|
|
97
|
+
// Create a log file for the daemon's output
|
|
98
|
+
const logDir = path.join(serverCwd, 'logs');
|
|
99
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
100
|
+
const logFile = path.join(logDir, 'bridge-daemon.log');
|
|
101
|
+
|
|
102
|
+
// Spawn the bridge server as a fully detached background process.
|
|
103
|
+
// This means: when the MCP process exits, the bridge stays alive.
|
|
104
|
+
// The bridge maintains the WebSocket connection with the Chrome extension.
|
|
105
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
106
|
+
const child = spawn(process.execPath, [serverScript], {
|
|
107
|
+
detached: true,
|
|
108
|
+
stdio: ['ignore', logFd, logFd],
|
|
109
|
+
env: { ...process.env },
|
|
110
|
+
cwd: serverCwd,
|
|
111
|
+
windowsHide: true
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Unref so the MCP process can exit independently
|
|
115
|
+
child.unref();
|
|
116
|
+
|
|
117
|
+
console.error(`[VenomBrowser MCP] Spawned bridge daemon (PID ${child.pid}), waiting for ready...`);
|
|
118
|
+
console.error(`[VenomBrowser MCP] Daemon logs: ${logFile}`);
|
|
119
|
+
|
|
120
|
+
// Wait for the bridge to be ready
|
|
121
|
+
const ready = await waitForBridge();
|
|
122
|
+
|
|
123
|
+
if (ready) {
|
|
124
|
+
console.error('[VenomBrowser MCP] Bridge daemon is ready!');
|
|
125
|
+
return true;
|
|
126
|
+
} else {
|
|
127
|
+
console.error('[VenomBrowser MCP] WARNING: Bridge daemon did not become ready within 15s.');
|
|
128
|
+
console.error('[VenomBrowser MCP] Check logs at: ' + logFile);
|
|
129
|
+
console.error('[VenomBrowser MCP] Continuing anyway — commands will fail if daemon is not running.');
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ─── Main ─────────────────────────────────────────────────────────────────
|
|
135
|
+
async function main() {
|
|
136
|
+
// Step 1: Ensure the bridge daemon is running (Kimi-style auto-start)
|
|
137
|
+
await ensureBridgeRunning();
|
|
138
|
+
|
|
139
|
+
// Step 2: Start the MCP server (stdio transport for agent communication)
|
|
140
|
+
const VenomBrowserMcpServer = require('../src/mcp-server');
|
|
141
|
+
const server = new VenomBrowserMcpServer();
|
|
142
|
+
await server.start();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main().catch(err => {
|
|
146
|
+
console.error('[VenomBrowser MCP] Failed to start:', err.message);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* VenomBrowser Setup — Interactive setup wizard
|
|
4
4
|
*
|
|
@@ -149,9 +149,9 @@ async function main() {
|
|
|
149
149
|
console.log('🚀 Next steps:');
|
|
150
150
|
if (!final.WS_AUTH_TOKEN || final.WS_AUTH_TOKEN.includes('paste')) {
|
|
151
151
|
console.log(' 1. Set your WS_AUTH_TOKEN (see instructions above)');
|
|
152
|
-
console.log(' 2.
|
|
152
|
+
console.log(' 2. Start using your AI agent (the bridge daemon will auto-start)');
|
|
153
153
|
} else {
|
|
154
|
-
console.log(' 1.
|
|
154
|
+
console.log(' 1. Start using your AI agent (the bridge daemon will auto-start)');
|
|
155
155
|
}
|
|
156
156
|
console.log(' 2. venombrowser chat — start interactive chat');
|
|
157
157
|
console.log(' 3. venombrowser agent "task" — run a one-shot task');
|
package/package.json
CHANGED