You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@different-ai/opencode-browser

Package Overview
Dependencies
Maintainers
2
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@different-ai/opencode-browser - npm Package Compare versions

Comparing version
2.0.1
to
2.0.2
+1
-1
package.json
{
"name": "@different-ai/opencode-browser",
"version": "2.0.1",
"version": "2.0.2",
"description": "Browser automation plugin for OpenCode. Control your real Chrome browser with existing logins and cookies.",

@@ -5,0 +5,0 @@ "type": "module",

@@ -37,2 +37,3 @@ /**

let hasLock = false;
let serverFailed = false;

@@ -123,3 +124,3 @@ // ============================================================================

process.kill(targetPid, "SIGTERM");
// Wait a bit for process to die
// Wait for process to die
let attempts = 0;

@@ -146,3 +147,21 @@ while (isProcessAlive(targetPid) && attempts < 10) {

function checkPortAvailable(): boolean {
try {
const testSocket = Bun.connect({ port: WS_PORT, timeout: 1000 });
testSocket.end();
return true;
} catch (e) {
if ((e as any).code === "ECONNREFUSED") {
return false;
}
return true;
}
}
function startServer(): boolean {
if (server) {
console.error(`[browser-plugin] Server already running`);
return true;
}
try {

@@ -177,2 +196,3 @@ server = Bun.serve({

console.error(`[browser-plugin] WebSocket server listening on port ${WS_PORT}`);
serverFailed = false;
return true;

@@ -185,3 +205,3 @@ } catch (e) {

function handleMessage(message: { type: string; id?: number; result?: any; error?: any }) {
function handleMessage(message: { type: string; id?: number; result?: any; error?: any }): void {
if (message.type === "tool_response" && message.id !== undefined) {

@@ -211,3 +231,3 @@ const pending = pendingRequests.get(message.id);

async function executeCommand(tool: string, args: Record<string, any>): Promise<any> {
// Check lock first
// Check lock and start server if needed
const lockResult = tryAcquireLock();

@@ -220,3 +240,2 @@ if (!lockResult.success) {

// Start server if not running
if (!server) {

@@ -283,8 +302,29 @@ if (!startServer()) {

// Try to acquire lock and start server on load
const lockResult = tryAcquireLock();
if (lockResult.success) {
startServer();
// Check port availability on load, don't try to acquire lock yet
checkPortAvailable();
// Check lock status and set appropriate state
const lock = readLock();
if (!lock) {
// No lock - just check if we can start server
console.error(`[browser-plugin] No lock file, checking port...`);
if (!startServer()) {
serverFailed = true;
}
} else if (lock.sessionId === sessionId) {
// We own the lock - start server
console.error(`[browser-plugin] Already have lock, starting server...`);
if (!startServer()) {
serverFailed = true;
}
} else if (!isProcessAlive(lock.pid)) {
// Stale lock - take it and start server
console.error(`[browser-plugin] Stale lock from dead PID ${lock.pid}, taking over...`);
writeLock();
if (!startServer()) {
serverFailed = true;
}
} else {
console.error(`[browser-plugin] Lock held by PID ${lockResult.lock?.pid}, tools will fail until lock is released`);
// Another session has the lock
console.error(`[browser-plugin] Lock held by PID ${lock.pid}, tools will fail until lock is released`);
}

@@ -327,3 +367,8 @@

writeLock();
if (!server) startServer();
// Start server if needed
if (!server) {
if (!startServer()) {
throw new Error("Failed to start WebSocket server after acquiring lock.");
}
}
return "No active session. Browser now connected to this session.";

@@ -339,10 +384,19 @@ }

writeLock();
if (!server) startServer();
// Start server if needed
if (!server) {
if (!startServer()) {
throw new Error("Failed to start WebSocket server after cleaning stale lock.");
}
}
return `Cleaned stale lock (PID ${lock.pid} was dead). Browser now connected to this session.`;
}
// Kill the other session
// Kill other session and wait for port to be free
const result = await killSession(lock.pid);
if (result.success) {
if (!server) startServer();
if (!server) {
if (!startServer()) {
throw new Error("Failed to start WebSocket server after killing other session.");
}
}
return `Killed session ${lock.sessionId} (PID ${lock.pid}). Browser now connected to this session.`;

@@ -356,3 +410,3 @@ } else {

browser_navigate: tool({
description: "Navigate to a URL in the browser",
description: "Navigate to a URL in browser",
args: {

@@ -368,5 +422,5 @@ url: tool.schema.string({ description: "The URL to navigate to" }),

browser_click: tool({
description: "Click an element on the page using a CSS selector",
description: "Click an element on page using a CSS selector",
args: {
selector: tool.schema.string({ description: "CSS selector for the element to click" }),
selector: tool.schema.string({ description: "CSS selector for element to click" }),
tabId: tool.schema.optional(tool.schema.number({ description: "Optional tab ID" })),

@@ -382,3 +436,3 @@ },

args: {
selector: tool.schema.string({ description: "CSS selector for the input element" }),
selector: tool.schema.string({ description: "CSS selector for input element" }),
text: tool.schema.string({ description: "Text to type" }),

@@ -394,12 +448,13 @@ clear: tool.schema.optional(tool.schema.boolean({ description: "Clear field before typing" })),

browser_screenshot: tool({
description: "Take a screenshot of the current page. Saves to ~/.opencode-browser/screenshots/ and returns the file path.",
description: "Take a screenshot of the current page. Saves to ~/.opencode-browser/screenshots/",
args: {
tabId: tool.schema.optional(tool.schema.number({ description: "Optional tab ID" })),
name: tool.schema.optional(tool.schema.string({ description: "Optional name for the screenshot file (without extension)" })),
name: tool.schema.optional(
tool.schema.string({ description: "Optional name for screenshot file (without extension)" })
),
},
async execute(args) {
const result = await executeCommand("screenshot", args);
if (result && result.startsWith("data:image")) {
// Extract base64 data and save to file
const base64Data = result.replace(/^data:image\/\w+;base64,/, "");

@@ -409,8 +464,7 @@ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");

const filepath = join(SCREENSHOTS_DIR, filename);
writeFileSync(filepath, Buffer.from(base64Data, "base64"));
return `Screenshot saved: ${filepath}`;
}
return result;

@@ -417,0 +471,0 @@ },