@different-ai/opencode-browser 4.0.0 → 4.0.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/README.md CHANGED
@@ -23,11 +23,11 @@ The installer will:
23
23
  1. Copy the extension to `~/.opencode-browser/extension/`
24
24
  2. Walk you through loading + pinning it in `chrome://extensions`
25
25
  3. Ask for the extension ID and install a **Native Messaging Host manifest**
26
- 4. Update your `opencode.json` to load the plugin
26
+ 4. Update your `.opencode.json` to load the plugin
27
27
 
28
28
  ### Configure OpenCode
29
29
 
30
- Your `opencode.json` should contain:
30
+ Your `.opencode.json` should contain:
31
31
 
32
32
  ```json
33
33
  {
@@ -59,6 +59,7 @@ Tools:
59
59
 
60
60
  ## Available tools
61
61
 
62
+ - `browser_version`
62
63
  - `browser_status`
63
64
  - `browser_get_tabs`
64
65
  - `browser_navigate`
@@ -86,4 +87,4 @@ Tools:
86
87
  npx @different-ai/opencode-browser uninstall
87
88
  ```
88
89
 
89
- Then remove the unpacked extension in `chrome://extensions` and remove the plugin from `opencode.json`.
90
+ Then remove the unpacked extension in `chrome://extensions` and remove the plugin from `.opencode.json`.
package/bin/cli.js CHANGED
@@ -275,38 +275,65 @@ Find it at ${color("cyan", "chrome://extensions")}:
275
275
 
276
276
  header("Step 7: Configure OpenCode");
277
277
 
278
- const opencodeJsonPath = join(process.cwd(), "opencode.json");
278
+ // OpenCode config discovery (per upstream docs):
279
+ // - $HOME/.opencode.json
280
+ // - $XDG_CONFIG_HOME/opencode/.opencode.json
281
+ // - ./.opencode.json (project-local)
282
+ // We write the project-local config to avoid touching global state.
283
+ const opencodeJsonPath = join(process.cwd(), ".opencode.json");
279
284
 
280
285
  const desiredPlugin = "@different-ai/opencode-browser";
281
286
 
287
+ function normalizePlugins(val) {
288
+ if (Array.isArray(val)) return val.filter((v) => typeof v === "string");
289
+ if (typeof val === "string" && val.trim()) return [val.trim()];
290
+ return [];
291
+ }
292
+
293
+ function removeLegacyMcp(config) {
294
+ if (config.mcp?.browser) {
295
+ delete config.mcp.browser;
296
+ if (Object.keys(config.mcp).length === 0) delete config.mcp;
297
+ warn("Removed old MCP browser config (replaced by plugin)");
298
+ }
299
+ if (config.mcpServers?.browser) {
300
+ delete config.mcpServers.browser;
301
+ if (Object.keys(config.mcpServers).length === 0) delete config.mcpServers;
302
+ warn("Removed old MCP browser config (replaced by plugin)");
303
+ }
304
+ }
305
+
282
306
  if (existsSync(opencodeJsonPath)) {
283
- const shouldUpdate = await confirm("Found opencode.json. Add plugin automatically?");
307
+ const shouldUpdate = await confirm("Found .opencode.json. Add plugin automatically?");
284
308
  if (shouldUpdate) {
285
309
  try {
286
310
  const config = JSON.parse(readFileSync(opencodeJsonPath, "utf-8"));
287
- config.plugin = config.plugin || [];
288
- if (!Array.isArray(config.plugin)) config.plugin = [];
311
+
312
+ // Make sure plugin is an array.
313
+ config.plugin = normalizePlugins(config.plugin);
289
314
  if (!config.plugin.includes(desiredPlugin)) config.plugin.push(desiredPlugin);
290
315
 
291
- // Remove MCP config if present
292
- if (config.mcp?.browser) {
293
- delete config.mcp.browser;
294
- if (Object.keys(config.mcp).length === 0) delete config.mcp;
295
- warn("Removed old MCP browser config (replaced by plugin)");
296
- }
316
+ removeLegacyMcp(config);
317
+
318
+ // Ensure schema is correct if present.
319
+ if (typeof config.$schema !== "string") config.$schema = "https://opencode.ai/config.json";
297
320
 
298
321
  writeFileSync(opencodeJsonPath, JSON.stringify(config, null, 2) + "\n");
299
- success("Updated opencode.json with plugin");
322
+ success("Updated .opencode.json with plugin");
300
323
  } catch (e) {
301
- error(`Failed to update opencode.json: ${e.message}`);
324
+ error(`Failed to update .opencode.json: ${e.message}`);
302
325
  }
303
326
  }
304
327
  } else {
305
- const shouldCreate = await confirm("No opencode.json found. Create one?");
328
+ const shouldCreate = await confirm("No .opencode.json found. Create one?");
306
329
  if (shouldCreate) {
307
- const config = { $schema: "https://opencode.ai/config.json", plugin: [desiredPlugin] };
330
+ const config = {
331
+ $schema: "https://opencode.ai/config.json",
332
+ theme: "opencode",
333
+ plugin: [desiredPlugin],
334
+ };
308
335
  writeFileSync(opencodeJsonPath, JSON.stringify(config, null, 2) + "\n");
309
- success("Created opencode.json with plugin");
336
+ success("Created .opencode.json with plugin");
310
337
  }
311
338
  }
312
339
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@different-ai/opencode-browser",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Browser automation plugin for OpenCode (native messaging + per-tab ownership).",
5
5
  "type": "module",
6
6
  "bin": {
7
- "opencode-browser": "./bin/cli.js"
7
+ "opencode-browser": "bin/cli.js"
8
8
  },
9
9
  "main": "./src/plugin.ts",
10
10
  "exports": {
package/src/plugin.ts CHANGED
@@ -1,10 +1,34 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { tool } from "@opencode-ai/plugin";
3
3
  import net from "net";
4
- import { existsSync, mkdirSync } from "fs";
4
+ import { existsSync, mkdirSync, readFileSync } from "fs";
5
5
  import { homedir } from "os";
6
- import { join } from "path";
6
+ import { dirname, join } from "path";
7
7
  import { spawn } from "child_process";
8
+ import { fileURLToPath } from "url";
9
+
10
+ console.log("[opencode-browser] Plugin loading...", { pid: process.pid });
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ const PACKAGE_JSON_PATH = join(__dirname, "..", "package.json");
15
+
16
+ let cachedVersion: string | null = null;
17
+
18
+ function getPackageVersion(): string {
19
+ if (cachedVersion) return cachedVersion;
20
+ try {
21
+ const pkg = JSON.parse(readFileSync(PACKAGE_JSON_PATH, "utf8"));
22
+ if (typeof pkg?.version === "string") {
23
+ cachedVersion = pkg.version;
24
+ return cachedVersion;
25
+ }
26
+ } catch {
27
+ // ignore
28
+ }
29
+ cachedVersion = "unknown";
30
+ return cachedVersion;
31
+ }
8
32
 
9
33
  const BASE_DIR = join(homedir(), ".opencode-browser");
10
34
  const SOCKET_PATH = join(BASE_DIR, "broker.sock");
@@ -142,6 +166,37 @@ function toolResultText(data: any, fallback: string): string {
142
166
  const plugin: Plugin = {
143
167
  name: "opencode-browser",
144
168
  tools: [
169
+
170
+ tool(
171
+ "browser_debug",
172
+ "Debug plugin loading and connection status.",
173
+ {},
174
+ async () => {
175
+ console.log("[opencode-browser] browser_debug called", { sessionId, pid: process.pid });
176
+ return JSON.stringify({
177
+ loaded: true,
178
+ sessionId,
179
+ pid: process.pid,
180
+ tools: plugin.tools.map(t => t.name),
181
+ timestamp: new Date().toISOString(),
182
+ });
183
+ }
184
+ ),
185
+
186
+ tool(
187
+ "browser_version",
188
+ "Return the installed @different-ai/opencode-browser plugin version.",
189
+ {},
190
+ async () => {
191
+ return JSON.stringify({
192
+ name: "@different-ai/opencode-browser",
193
+ version: getPackageVersion(),
194
+ sessionId,
195
+ pid: process.pid,
196
+ });
197
+ }
198
+ ),
199
+
145
200
  tool(
146
201
  "browser_status",
147
202
  "Check broker/native-host connection status and current tab claims.",
@@ -151,6 +206,7 @@ const plugin: Plugin = {
151
206
  return JSON.stringify(data);
152
207
  }
153
208
  ),
209
+
154
210
  tool(
155
211
  "browser_get_tabs",
156
212
  "List all open browser tabs",