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.
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * VenomBrowser Agent — CLI entry point (Kimi-style)
4
4
  *
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * VenomBrowser Interactive Chat Agent — CLI entry point (Kimi-style)
4
4
  *
@@ -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;
@@ -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
- * Usage: node bin/venombrowser-mcp.js
7
- * Or: npm run mcp
8
- *
9
- * Agent configuration example (Claude Code):
10
- * {
11
- * "mcpServers": {
12
- * "venombrowser": {
13
- * "command": "node",
14
- * "args": ["C:/path/to/VenomBrowser/server/bin/venombrowser-mcp.js"],
15
- * "env": { "REST_API_KEY": "your-bridge-api-key" }
16
- * }
17
- * }
18
- * }
19
- */
20
-
21
- // Load .env for default config — agents can also pass env vars directly
22
- require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
23
-
24
- const VenomBrowserMcpServer = require('../src/mcp-server');
25
-
26
- const server = new VenomBrowserMcpServer();
27
- server.start().catch(err => {
28
- console.error('[VenomBrowser MCP] Failed to start:', err.message);
29
- process.exit(1);
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,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * VenomBrowser Bridge Server — CLI entry point
4
4
  * Starts the WebSocket + REST API bridge server.
@@ -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. Generating a REST_API_KEY if missing
8
- * 3. Prompting for WS_AUTH_TOKEN (from extension popup)
9
- * 4. Configuring the LLM provider
10
- *
11
- * Usage:
12
- * node bin/venombrowser-setup.js
13
- * node bin/venombrowser-setup.js --auto # Non-interactive: generate keys, use defaults
14
- * node bin/venombrowser-setup.js --token=<tok> # Set the WS_AUTH_TOKEN directly
15
- */
16
-
17
- const fs = require('fs');
18
- const path = require('path');
19
- const crypto = require('crypto');
20
- const readline = require('readline');
21
-
22
- const ENV_PATH = path.join(__dirname, '..', '.env');
23
- const EXAMPLE_PATH = path.join(__dirname, '..', '.env.example');
24
-
25
- function generateKey(length = 32) {
26
- return crypto.randomBytes(length).toString('hex');
27
- }
28
-
29
- function parseEnv(content) {
30
- const vars = {};
31
- for (const line of content.split('\n')) {
32
- const trimmed = line.trim();
33
- if (!trimmed || trimmed.startsWith('#')) continue;
34
- const eqIndex = trimmed.indexOf('=');
35
- if (eqIndex === -1) continue;
36
- const key = trimmed.slice(0, eqIndex).trim();
37
- const val = trimmed.slice(eqIndex + 1).trim();
38
- vars[key] = val;
39
- }
40
- return vars;
41
- }
42
-
43
- function updateEnvFile(updates) {
44
- let content;
45
- if (fs.existsSync(ENV_PATH)) {
46
- content = fs.readFileSync(ENV_PATH, 'utf8');
47
- } else if (fs.existsSync(EXAMPLE_PATH)) {
48
- content = fs.readFileSync(EXAMPLE_PATH, 'utf8');
49
- } else {
50
- // Build minimal .env
51
- content = Object.entries(updates).map(([k, v]) => `${k}=${v}`).join('\n') + '\n';
52
- fs.writeFileSync(ENV_PATH, content);
53
- return;
54
- }
55
-
56
- for (const [key, value] of Object.entries(updates)) {
57
- // Replace existing key= lines, or append
58
- const regex = new RegExp(`^${key}=.*$`, 'm');
59
- if (regex.test(content)) {
60
- content = content.replace(regex, `${key}=${value}`);
61
- } else {
62
- content += `\n${key}=${value}\n`;
63
- }
64
- }
65
-
66
- fs.writeFileSync(ENV_PATH, content);
67
- }
68
-
69
- function ask(rl, question) {
70
- return new Promise(resolve => rl.question(question, resolve));
71
- }
72
-
73
- async function main() {
74
- const args = process.argv.slice(2);
75
- const isAuto = args.includes('--auto');
76
- const tokenArg = args.find(a => a.startsWith('--token='));
77
- const tokenValue = tokenArg ? tokenArg.split('=').slice(1).join('=') : null;
78
-
79
- console.log('🕷️ VenomBrowser Bridge Setup');
80
- console.log('═'.repeat(50));
81
-
82
- // Load existing env
83
- let existing = {};
84
- if (fs.existsSync(ENV_PATH)) {
85
- existing = parseEnv(fs.readFileSync(ENV_PATH, 'utf8'));
86
- console.log('📄 Found existing .env file');
87
- } else {
88
- console.log('📄 No .env file found — will create one');
89
- }
90
-
91
- const updates = {};
92
-
93
- // ── REST_API_KEY ─────────────────────────────────────────────────────────
94
- if (!existing.REST_API_KEY || existing.REST_API_KEY.includes('pick-any') || existing.REST_API_KEY.includes('your')) {
95
- const key = generateKey();
96
- updates.REST_API_KEY = key;
97
- console.log(`🔑 Generated REST_API_KEY: ${key}`);
98
- } else {
99
- console.log(`🔑 REST_API_KEY: ${existing.REST_API_KEY.slice(0, 8)}...`);
100
- }
101
-
102
- // ── WS_AUTH_TOKEN ────────────────────────────────────────────────────────
103
- if (tokenValue) {
104
- updates.WS_AUTH_TOKEN = tokenValue;
105
- console.log(`🔐 WS_AUTH_TOKEN set from --token flag`);
106
- } else if (isAuto) {
107
- if (!existing.WS_AUTH_TOKEN || existing.WS_AUTH_TOKEN.includes('paste')) {
108
- console.log('⚠️ WS_AUTH_TOKEN not set. After loading the extension, run:');
109
- console.log(' node bin/venombrowser-setup.js --token=<paste-token-from-extension-popup>');
110
- }
111
- } else {
112
- // Interactive
113
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
114
-
115
- if (!existing.WS_AUTH_TOKEN || existing.WS_AUTH_TOKEN.includes('paste')) {
116
- console.log();
117
- console.log('📋 To get your WS_AUTH_TOKEN:');
118
- console.log(' 1. Load the extension/ folder in chrome://extensions/');
119
- console.log(' 2. Click the VenomBrowser Bridge icon in your toolbar');
120
- console.log(' 3. Click the auth token to copy it');
121
- console.log();
122
- const token = await ask(rl, '🔐 Paste your Auth Token (or press Enter to skip): ');
123
- if (token.trim()) {
124
- updates.WS_AUTH_TOKEN = token.trim();
125
- console.log('✅ WS_AUTH_TOKEN saved!');
126
- } else {
127
- console.log('⏭️ Skipped you can set it later with: node bin/venombrowser-setup.js --token=<token>');
128
- }
129
- } else {
130
- console.log(`🔐 WS_AUTH_TOKEN: ${existing.WS_AUTH_TOKEN.slice(0, 8)}...`);
131
- }
132
-
133
- rl.close();
134
- }
135
-
136
- // ── Save ──────────────────────────────────────────────────────────────────
137
- if (Object.keys(updates).length > 0) {
138
- updateEnvFile(updates);
139
- console.log();
140
- console.log('💾 Configuration saved to server/.env');
141
- } else {
142
- console.log();
143
- console.log('✅ Configuration is already up to date');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "venombrowser",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Agent-agnostic browser automation platform — give any AI agent eyes and hands in your real Chrome browser",
5
5
  "author": "TechVenom",
6
6
  "main": "src/bridge-server.js",