@different-ai/opencode-browser 4.5.0 → 4.6.0

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
@@ -58,6 +58,25 @@ Your `opencode.json` or `opencode.jsonc` should contain:
58
58
  bunx @different-ai/opencode-browser@latest update
59
59
  ```
60
60
 
61
+ ## Chrome Web Store maintainer flow
62
+
63
+ Build a store-ready extension package:
64
+
65
+ ```bash
66
+ bun run build:cws
67
+ ```
68
+
69
+ Outputs:
70
+
71
+ - `artifacts/chrome-web-store/opencode-browser-cws-v<version>.zip`
72
+ - `artifacts/chrome-web-store/manifest.chrome-web-store.json`
73
+
74
+ Submission checklist and guidance:
75
+
76
+ - `CHROME_WEB_STORE.md`
77
+ - `CHROME_WEB_STORE_REQUEST_TEMPLATE.md`
78
+ - `PRIVACY.md`
79
+
61
80
  ## How it works
62
81
 
63
82
  ```
@@ -111,11 +130,11 @@ export OPENCODE_BROWSER_AGENT_PORT=9833
111
130
 
112
131
  ## Per-tab ownership
113
132
 
114
- - First time a session touches a tab, the broker **auto-claims** it for that session.
115
- - Each session tracks a default tab; tools without `tabId` route to it.
116
- - `browser_open_tab` always works; if another session owns the active tab, the new tab opens in the background.
133
+ - Each session owns its own tabs; tabs are never shared between sessions.
134
+ - If a session has no tab yet, the broker auto-creates a background tab on first tool use.
135
+ - `browser_open_tab` always creates and claims a new tab for the session.
117
136
  - Claims expire after inactivity (`OPENCODE_BROWSER_CLAIM_TTL_MS`, default 5 minutes).
118
- - Use `browser_status` or `browser_list_claims` to inspect claims if needed.
137
+ - Use `browser_status` or `browser_list_claims` for debugging.
119
138
 
120
139
  ## Available tools
121
140
 
@@ -126,6 +145,7 @@ Core primitives:
126
145
  - `browser_claim_tab`
127
146
  - `browser_release_tab`
128
147
  - `browser_open_tab`
148
+ - `browser_close_tab`
129
149
  - `browser_navigate`
130
150
  - `browser_query` (modes: `text`, `value`, `list`, `exists`, `page_text`; optional `timeoutMs`/`pollMs`)
131
151
  - `browser_click` (optional `timeoutMs`/`pollMs`)
@@ -134,6 +154,13 @@ Core primitives:
134
154
  - `browser_scroll` (optional `timeoutMs`/`pollMs`)
135
155
  - `browser_wait`
136
156
 
157
+ Downloads:
158
+ - `browser_download`
159
+ - `browser_list_downloads`
160
+
161
+ Uploads:
162
+ - `browser_set_file_input` (extension backend supports small files; use agent backend for larger uploads)
163
+
137
164
  Selector helpers (usable in `selector`):
138
165
  - `label:Mailing Address: City`
139
166
  - `aria:Principal Address: City`
@@ -149,11 +176,11 @@ Diagnostics:
149
176
 
150
177
  ## Roadmap
151
178
 
152
- - [ ] Add tab management tools (`browser_set_active_tab`, `browser_close_tab`)
179
+ - [ ] Add tab management tools (`browser_set_active_tab`)
153
180
  - [ ] Add navigation helpers (`browser_back`, `browser_forward`, `browser_reload`)
154
181
  - [ ] Add keyboard input tool (`browser_key`)
155
- - [ ] Add download support (`browser_download`, `browser_list_downloads`)
156
- - [ ] Add upload support (`browser_set_file_input`)
182
+ - [x] Add download support (`browser_download`, `browser_list_downloads`)
183
+ - [x] Add upload support (`browser_set_file_input`)
157
184
 
158
185
  ## Troubleshooting
159
186
 
@@ -162,8 +189,9 @@ Diagnostics:
162
189
  - If you loaded a custom extension ID, rerun with `--extension-id <id>`
163
190
 
164
191
  **Tab ownership errors**
165
- - Use `browser_status` or `browser_list_claims` to see current claims
166
- - Use `browser_release_tab` or close the other OpenCode session to release ownership
192
+ - Errors usually mean you passed a `tabId` owned by another session
193
+ - Use `browser_open_tab` to create a tab for your session (or omit `tabId` to use your default)
194
+ - Use `browser_status` or `browser_list_claims` for debugging
167
195
 
168
196
  ## Uninstall
169
197
 
@@ -172,3 +200,7 @@ npx @different-ai/opencode-browser uninstall
172
200
  ```
173
201
 
174
202
  Then remove the unpacked extension in `chrome://extensions` and remove the plugin from `opencode.json` or `opencode.jsonc`.
203
+
204
+ ## Privacy
205
+
206
+ - Privacy policy: `PRIVACY.md`
package/bin/broker.cjs CHANGED
@@ -53,7 +53,7 @@ function writeJsonLine(socket, msg) {
53
53
  }
54
54
 
55
55
  function wantsTab(toolName) {
56
- return !["get_tabs", "get_active_tab", "open_tab"].includes(toolName);
56
+ return !["get_tabs", "get_active_tab", "open_tab", "list_downloads"].includes(toolName);
57
57
  }
58
58
 
59
59
  // --- State ---
@@ -206,10 +206,13 @@ function callExtension(tool, args, sessionId) {
206
206
  });
207
207
  }
208
208
 
209
- async function resolveActiveTab(sessionId) {
210
- const res = await callExtension("get_active_tab", {}, sessionId);
209
+ async function ensureSessionTab(sessionId) {
210
+ if (!sessionId) throw new Error("Missing sessionId for tab creation");
211
+ const res = await callExtension("open_tab", { active: false }, sessionId);
211
212
  const tabId = res && typeof res.tabId === "number" ? res.tabId : undefined;
212
- if (!tabId) throw new Error("Could not determine active tab");
213
+ if (!tabId) throw new Error("Failed to create a new tab for this session");
214
+ touchClaim(tabId, sessionId);
215
+ setDefaultTab(sessionId, tabId);
213
216
  return tabId;
214
217
  }
215
218
 
@@ -222,13 +225,7 @@ async function handleTool(pluginSocket, req) {
222
225
  let tabId = args.tabId;
223
226
  const toolArgs = { ...args };
224
227
 
225
- if (tool === "open_tab" && toolArgs.active !== false) {
226
- const activeTabId = await resolveActiveTab(sessionId);
227
- const claimCheck = checkClaim(activeTabId, sessionId);
228
- if (!claimCheck.ok) {
229
- toolArgs.active = false;
230
- }
231
- }
228
+ const isCloseTool = tool === "close_tab";
232
229
 
233
230
  if (wantsTab(tool)) {
234
231
  if (typeof tabId !== "number") {
@@ -236,14 +233,10 @@ async function handleTool(pluginSocket, req) {
236
233
  const defaultTabId = state && Number.isFinite(state.defaultTabId) ? state.defaultTabId : null;
237
234
  if (Number.isFinite(defaultTabId)) {
238
235
  tabId = defaultTabId;
236
+ } else if (!isCloseTool) {
237
+ tabId = await ensureSessionTab(sessionId);
239
238
  } else {
240
- const activeTabId = await resolveActiveTab(sessionId);
241
- const claimCheck = checkClaim(activeTabId, sessionId);
242
- if (!claimCheck.ok) {
243
- throw new Error(`${claimCheck.error}. No default tab for session; open a new tab or claim one.`);
244
- }
245
- tabId = activeTabId;
246
- setDefaultTab(sessionId, tabId);
239
+ throw new Error("No tab owned by this session. Open a new tab first.");
247
240
  }
248
241
  }
249
242
 
@@ -256,8 +249,16 @@ async function handleTool(pluginSocket, req) {
256
249
  const usedTabId =
257
250
  res && typeof res.tabId === "number" ? res.tabId : typeof tabId === "number" ? tabId : undefined;
258
251
  if (typeof usedTabId === "number") {
259
- touchClaim(usedTabId, sessionId);
260
- setDefaultTab(sessionId, usedTabId);
252
+ if (isCloseTool) {
253
+ if (claims.has(usedTabId)) {
254
+ releaseClaim(usedTabId);
255
+ } else {
256
+ clearDefaultTab(sessionId, usedTabId);
257
+ }
258
+ } else {
259
+ touchClaim(usedTabId, sessionId);
260
+ setDefaultTab(sessionId, usedTabId);
261
+ }
261
262
  }
262
263
 
263
264
  return res;