venombrowser 4.1.0 → 4.1.2
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-agent.js +1 -1
- package/bin/venombrowser-chat.js +1 -1
- package/bin/venombrowser-cli.js +38 -1
- package/bin/venombrowser-mcp.js +153 -30
- package/bin/venombrowser-server.js +1 -1
- package/bin/venombrowser-setup.js +145 -183
- package/package.json +1 -1
- package/src/bridge-client.js +65 -5
- package/src/bridge-server.js +216 -13
- package/src/connect.js +10 -2
- package/src/mcp-server.js +9 -2
- package/src/tools/browser-tools.js +265 -2
package/bin/venombrowser-chat.js
CHANGED
package/bin/venombrowser-cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* VenomBrowser CLI — Unified command dispatcher
|
|
4
4
|
*
|
|
@@ -37,6 +37,8 @@ Commands:
|
|
|
37
37
|
setup Run the interactive setup wizard
|
|
38
38
|
start Start the bridge daemon
|
|
39
39
|
status Check daemon & extension connection status
|
|
40
|
+
stop Stop the bridge daemon (releases port)
|
|
41
|
+
restart Restart the bridge daemon
|
|
40
42
|
connect Auto-register MCP server with known agents
|
|
41
43
|
uninstall Remove MCP entries, stop daemon (does NOT npm uninstall)
|
|
42
44
|
agent "<task>" Run a one-shot browser automation task
|
|
@@ -153,6 +155,35 @@ function runChat() {
|
|
|
153
155
|
child.on('exit', (code) => process.exit(code || 0));
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
function runStop() {
|
|
159
|
+
const { BrowserBridge } = require('../src/bridge-client');
|
|
160
|
+
const bridge = new BrowserBridge({ port: BRIDGE_PORT, session: 'cli', apiKey: process.env.REST_API_KEY });
|
|
161
|
+
bridge.stopServer()
|
|
162
|
+
.then(() => console.log('✅ Sent stop signal to bridge daemon. It will shut down gracefully.'))
|
|
163
|
+
.catch(err => {
|
|
164
|
+
if (err.message.includes('fetch failed') || err.message.includes('ECONNREFUSED')) {
|
|
165
|
+
console.log('✅ Daemon is already stopped.');
|
|
166
|
+
} else {
|
|
167
|
+
console.error('❌ Failed to stop daemon:', err.message);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function runRestart() {
|
|
173
|
+
console.log('🔄 Restarting VenomBrowser daemon...');
|
|
174
|
+
const { BrowserBridge } = require('../src/bridge-client');
|
|
175
|
+
const bridge = new BrowserBridge({ port: BRIDGE_PORT, session: 'cli', apiKey: process.env.REST_API_KEY });
|
|
176
|
+
bridge.stopServer()
|
|
177
|
+
.then(() => {
|
|
178
|
+
console.log('✅ Daemon stopped.');
|
|
179
|
+
setTimeout(() => runStart(), 1000);
|
|
180
|
+
})
|
|
181
|
+
.catch(err => {
|
|
182
|
+
console.log('✅ Daemon was not running.');
|
|
183
|
+
runStart();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
156
187
|
// ─── Dispatch ───────────────────────────────────────────────────────────────
|
|
157
188
|
|
|
158
189
|
const command = process.argv[2];
|
|
@@ -167,6 +198,12 @@ switch (command) {
|
|
|
167
198
|
case 'status':
|
|
168
199
|
runStatus();
|
|
169
200
|
break;
|
|
201
|
+
case 'stop':
|
|
202
|
+
runStop();
|
|
203
|
+
break;
|
|
204
|
+
case 'restart':
|
|
205
|
+
runRestart();
|
|
206
|
+
break;
|
|
170
207
|
case 'connect':
|
|
171
208
|
runConnect();
|
|
172
209
|
break;
|
package/bin/venombrowser-mcp.js
CHANGED
|
@@ -1,30 +1,153 @@
|
|
|
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
|
+
const VenomBrowserMcpServer = require('../src/mcp-server');
|
|
140
|
+
const server = new VenomBrowserMcpServer({
|
|
141
|
+
onBeforeCommand: async (toolName) => {
|
|
142
|
+
// Don't auto-start if the agent is explicitly trying to stop the server
|
|
143
|
+
if (toolName === 'stop_server') return;
|
|
144
|
+
await ensureBridgeRunning();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
await server.start();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
main().catch(err => {
|
|
151
|
+
console.error('[VenomBrowser MCP] Failed to start:', err.message);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
});
|
|
@@ -1,183 +1,145 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* VenomBrowser Setup — Interactive setup wizard
|
|
4
|
-
*
|
|
5
|
-
* Helps users (and agents) configure VenomBrowser by:
|
|
6
|
-
* 1. Creating/updating .env from .env.example
|
|
7
|
-
* 2.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log('
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
// ──
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// ── Final summary ─────────────────────────────────────────────────────────
|
|
147
|
-
const final = { ...existing, ...updates };
|
|
148
|
-
console.log();
|
|
149
|
-
console.log('🚀 Next steps:');
|
|
150
|
-
if (!final.WS_AUTH_TOKEN || final.WS_AUTH_TOKEN.includes('paste')) {
|
|
151
|
-
console.log(' 1. Set your WS_AUTH_TOKEN (see instructions above)');
|
|
152
|
-
console.log(' 2. venombrowser start — start the bridge server');
|
|
153
|
-
} else {
|
|
154
|
-
console.log(' 1. venombrowser start — start the bridge server');
|
|
155
|
-
}
|
|
156
|
-
console.log(' 2. venombrowser chat — start interactive chat');
|
|
157
|
-
console.log(' 3. venombrowser agent "task" — run a one-shot task');
|
|
158
|
-
console.log();
|
|
159
|
-
|
|
160
|
-
// ── Auto-register with agents ────────────────────────────────────────────
|
|
161
|
-
try {
|
|
162
|
-
const { connect } = require('../src/connect');
|
|
163
|
-
connect();
|
|
164
|
-
} catch (err) {
|
|
165
|
-
console.log('ℹ️ Auto-registration skipped:', err.message);
|
|
166
|
-
// Still print manual instructions as fallback
|
|
167
|
-
const absPath = path.resolve(__dirname, 'venombrowser-mcp.js').replace(/\\/g, '/');
|
|
168
|
-
console.log('🔌 To connect Claude Code or other MCP agents, add this to your MCP config:');
|
|
169
|
-
console.log(JSON.stringify({
|
|
170
|
-
"venombrowser": {
|
|
171
|
-
command: "node",
|
|
172
|
-
args: [absPath],
|
|
173
|
-
env: {
|
|
174
|
-
REST_API_KEY: final.REST_API_KEY || updates.REST_API_KEY || 'your-key'
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}, null, 2));
|
|
178
|
-
console.log();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
main().catch(console.error);
|
|
183
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* VenomBrowser Setup — Interactive setup wizard
|
|
4
|
+
*
|
|
5
|
+
* Helps users (and agents) configure VenomBrowser by:
|
|
6
|
+
* 1. Creating/updating .env from .env.example
|
|
7
|
+
* 2. Configuring the LLM provider (optional)
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node bin/venombrowser-setup.js
|
|
11
|
+
* node bin/venombrowser-setup.js --auto # Non-interactive: use defaults
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const readline = require('readline');
|
|
17
|
+
|
|
18
|
+
const ENV_PATH = path.join(__dirname, '..', '.env');
|
|
19
|
+
const EXAMPLE_PATH = path.join(__dirname, '..', '.env.example');
|
|
20
|
+
|
|
21
|
+
function parseEnv(content) {
|
|
22
|
+
const vars = {};
|
|
23
|
+
for (const line of content.split('\n')) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
26
|
+
const eqIndex = trimmed.indexOf('=');
|
|
27
|
+
if (eqIndex === -1) continue;
|
|
28
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
29
|
+
const val = trimmed.slice(eqIndex + 1).trim();
|
|
30
|
+
vars[key] = val;
|
|
31
|
+
}
|
|
32
|
+
return vars;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function updateEnvFile(updates) {
|
|
36
|
+
let content;
|
|
37
|
+
if (fs.existsSync(ENV_PATH)) {
|
|
38
|
+
content = fs.readFileSync(ENV_PATH, 'utf8');
|
|
39
|
+
} else if (fs.existsSync(EXAMPLE_PATH)) {
|
|
40
|
+
content = fs.readFileSync(EXAMPLE_PATH, 'utf8');
|
|
41
|
+
} else {
|
|
42
|
+
// Build minimal .env
|
|
43
|
+
content = Object.entries(updates).map(([k, v]) => `${k}=${v}`).join('\n') + '\n';
|
|
44
|
+
fs.writeFileSync(ENV_PATH, content);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
49
|
+
// Replace existing key= lines, or append
|
|
50
|
+
const regex = new RegExp(`^${key}=.*$`, 'm');
|
|
51
|
+
if (regex.test(content)) {
|
|
52
|
+
content = content.replace(regex, `${key}=${value}`);
|
|
53
|
+
} else {
|
|
54
|
+
content += `\n${key}=${value}\n`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fs.writeFileSync(ENV_PATH, content);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function ask(rl, question) {
|
|
62
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function main() {
|
|
66
|
+
console.log('🕷️ VenomBrowser Bridge Setup');
|
|
67
|
+
console.log('═'.repeat(50));
|
|
68
|
+
|
|
69
|
+
// Load existing env
|
|
70
|
+
let existing = {};
|
|
71
|
+
if (fs.existsSync(ENV_PATH)) {
|
|
72
|
+
existing = parseEnv(fs.readFileSync(ENV_PATH, 'utf8'));
|
|
73
|
+
console.log('📄 Found existing .env file');
|
|
74
|
+
} else {
|
|
75
|
+
console.log('📄 No .env file found — will create one');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const crypto = require('crypto');
|
|
79
|
+
const updates = {};
|
|
80
|
+
|
|
81
|
+
// ── Auto-generate security tokens if missing ──────────────────────────────
|
|
82
|
+
if (!existing.REST_API_KEY) {
|
|
83
|
+
updates.REST_API_KEY = crypto.randomBytes(32).toString('hex');
|
|
84
|
+
console.log('🔑 Generated new REST_API_KEY');
|
|
85
|
+
}
|
|
86
|
+
if (!existing.WS_AUTH_TOKEN) {
|
|
87
|
+
updates.WS_AUTH_TOKEN = crypto.randomUUID();
|
|
88
|
+
console.log('🔑 Generated new WS_AUTH_TOKEN');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const finalWsToken = updates.WS_AUTH_TOKEN || existing.WS_AUTH_TOKEN;
|
|
92
|
+
|
|
93
|
+
// ── Inject token into extension ───────────────────────────────────────────
|
|
94
|
+
const bgPath = path.join(__dirname, '..', '..', 'extension', 'background.js');
|
|
95
|
+
if (fs.existsSync(bgPath)) {
|
|
96
|
+
let bgContent = fs.readFileSync(bgPath, 'utf8');
|
|
97
|
+
// Look for INJECTED_TOKEN = '__WS_AUTH_TOKEN__' or an already injected token
|
|
98
|
+
bgContent = bgContent.replace(/const INJECTED_TOKEN = '.*?';/, `const INJECTED_TOKEN = '${finalWsToken}';`);
|
|
99
|
+
fs.writeFileSync(bgPath, bgContent);
|
|
100
|
+
console.log('💉 Injected WS_AUTH_TOKEN into extension/background.js');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── Save ──────────────────────────────────────────────────────────────────
|
|
104
|
+
if (Object.keys(updates).length > 0) {
|
|
105
|
+
updateEnvFile(updates);
|
|
106
|
+
console.log();
|
|
107
|
+
console.log('💾 Configuration saved to server/.env');
|
|
108
|
+
} else {
|
|
109
|
+
console.log();
|
|
110
|
+
console.log('✅ Configuration is already up to date');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── Final summary ─────────────────────────────────────────────────────────
|
|
114
|
+
console.log();
|
|
115
|
+
console.log('🚀 Next steps:');
|
|
116
|
+
console.log(' 1. IMPORTANT: Go to chrome://extensions and click the "Reload" icon on the VenomBrowser extension');
|
|
117
|
+
console.log(' (This is required to apply the newly generated security token)');
|
|
118
|
+
console.log(' 2. Start using your AI agent (the bridge daemon will auto-start)');
|
|
119
|
+
console.log(' 3. venombrowser chat — start interactive chat');
|
|
120
|
+
console.log(' 4. venombrowser agent "task" — run a one-shot task');
|
|
121
|
+
console.log();
|
|
122
|
+
|
|
123
|
+
// ── Auto-register with agents ────────────────────────────────────────────
|
|
124
|
+
try {
|
|
125
|
+
const { connect } = require('../src/connect');
|
|
126
|
+
connect();
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.log('ℹ️ Auto-registration skipped:', err.message);
|
|
129
|
+
// Still print manual instructions as fallback
|
|
130
|
+
const absPath = path.resolve(__dirname, 'venombrowser-mcp.js').replace(/\\/g, '/');
|
|
131
|
+
console.log('🔌 To connect Claude Code or other MCP agents, add this to your MCP config:');
|
|
132
|
+
console.log(JSON.stringify({
|
|
133
|
+
"venombrowser": {
|
|
134
|
+
command: "node",
|
|
135
|
+
args: [absPath],
|
|
136
|
+
env: {
|
|
137
|
+
BRIDGE_PORT: "10086"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}, null, 2));
|
|
141
|
+
console.log();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main().catch(console.error);
|
package/package.json
CHANGED