@different-ai/opencode-browser 4.5.0 → 4.5.1
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/.opencode/skill/github-release/SKILL.md +12 -0
- package/README.md +9 -7
- package/bin/broker.cjs +20 -19
- package/dist/plugin.js +18 -0
- package/extension/background.js +7 -0
- package/package.json +9 -11
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-release
|
|
3
|
+
description: Create a GitHub release after pnpm publish with clear feature updates.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use this skill after running `pnpm publish`.
|
|
7
|
+
|
|
8
|
+
1. Read the current version from `package.json` and set the tag name to `v<version>`.
|
|
9
|
+
2. Summarize changes from git commits since the last tag, or if no tags exist, from the current conversation and latest commits.
|
|
10
|
+
3. Draft release notes with a "## Features" section using those changes, and confirm with the user.
|
|
11
|
+
4. Create the GitHub release with `gh release create v<version> --title "v<version>" --notes "<notes>"`.
|
|
12
|
+
5. Confirm the release appears on GitHub and share the URL.
|
package/README.md
CHANGED
|
@@ -111,11 +111,11 @@ export OPENCODE_BROWSER_AGENT_PORT=9833
|
|
|
111
111
|
|
|
112
112
|
## Per-tab ownership
|
|
113
113
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- `browser_open_tab` always
|
|
114
|
+
- Each session owns its own tabs; tabs are never shared between sessions.
|
|
115
|
+
- If a session has no tab yet, the broker auto-creates a background tab on first tool use.
|
|
116
|
+
- `browser_open_tab` always creates and claims a new tab for the session.
|
|
117
117
|
- Claims expire after inactivity (`OPENCODE_BROWSER_CLAIM_TTL_MS`, default 5 minutes).
|
|
118
|
-
- Use `browser_status` or `browser_list_claims`
|
|
118
|
+
- Use `browser_status` or `browser_list_claims` for debugging.
|
|
119
119
|
|
|
120
120
|
## Available tools
|
|
121
121
|
|
|
@@ -126,6 +126,7 @@ Core primitives:
|
|
|
126
126
|
- `browser_claim_tab`
|
|
127
127
|
- `browser_release_tab`
|
|
128
128
|
- `browser_open_tab`
|
|
129
|
+
- `browser_close_tab`
|
|
129
130
|
- `browser_navigate`
|
|
130
131
|
- `browser_query` (modes: `text`, `value`, `list`, `exists`, `page_text`; optional `timeoutMs`/`pollMs`)
|
|
131
132
|
- `browser_click` (optional `timeoutMs`/`pollMs`)
|
|
@@ -149,7 +150,7 @@ Diagnostics:
|
|
|
149
150
|
|
|
150
151
|
## Roadmap
|
|
151
152
|
|
|
152
|
-
- [ ] Add tab management tools (`browser_set_active_tab
|
|
153
|
+
- [ ] Add tab management tools (`browser_set_active_tab`)
|
|
153
154
|
- [ ] Add navigation helpers (`browser_back`, `browser_forward`, `browser_reload`)
|
|
154
155
|
- [ ] Add keyboard input tool (`browser_key`)
|
|
155
156
|
- [ ] Add download support (`browser_download`, `browser_list_downloads`)
|
|
@@ -162,8 +163,9 @@ Diagnostics:
|
|
|
162
163
|
- If you loaded a custom extension ID, rerun with `--extension-id <id>`
|
|
163
164
|
|
|
164
165
|
**Tab ownership errors**
|
|
165
|
-
-
|
|
166
|
-
- Use `
|
|
166
|
+
- Errors usually mean you passed a `tabId` owned by another session
|
|
167
|
+
- Use `browser_open_tab` to create a tab for your session (or omit `tabId` to use your default)
|
|
168
|
+
- Use `browser_status` or `browser_list_claims` for debugging
|
|
167
169
|
|
|
168
170
|
## Uninstall
|
|
169
171
|
|
package/bin/broker.cjs
CHANGED
|
@@ -206,10 +206,13 @@ function callExtension(tool, args, sessionId) {
|
|
|
206
206
|
});
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
async function
|
|
210
|
-
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
260
|
-
|
|
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;
|
package/dist/plugin.js
CHANGED
|
@@ -12864,6 +12864,14 @@ function createAgentBackend(sessionId) {
|
|
|
12864
12864
|
}
|
|
12865
12865
|
return { content: { tabId: created.index, url: args.url, active: active !== false } };
|
|
12866
12866
|
}
|
|
12867
|
+
case "close_tab": {
|
|
12868
|
+
const payload = {};
|
|
12869
|
+
if (Number.isFinite(args.tabId))
|
|
12870
|
+
payload.index = args.tabId;
|
|
12871
|
+
const result = await agentCommand("tab_close", payload);
|
|
12872
|
+
const closed = Number.isFinite(result?.closed) ? result.closed : args.tabId;
|
|
12873
|
+
return { content: { tabId: closed, remaining: result?.remaining } };
|
|
12874
|
+
}
|
|
12867
12875
|
case "navigate": {
|
|
12868
12876
|
return await withTab(args.tabId, async () => {
|
|
12869
12877
|
if (!args.url)
|
|
@@ -13268,6 +13276,16 @@ var plugin = async (ctx) => {
|
|
|
13268
13276
|
return toolResultText(data, "Opened new tab");
|
|
13269
13277
|
}
|
|
13270
13278
|
}),
|
|
13279
|
+
browser_close_tab: tool({
|
|
13280
|
+
description: "Close a browser tab owned by this session",
|
|
13281
|
+
args: {
|
|
13282
|
+
tabId: schema.number().optional()
|
|
13283
|
+
},
|
|
13284
|
+
async execute({ tabId }, ctx2) {
|
|
13285
|
+
const data = await toolRequest("close_tab", { tabId });
|
|
13286
|
+
return toolResultText(data, "Closed tab");
|
|
13287
|
+
}
|
|
13288
|
+
}),
|
|
13271
13289
|
browser_navigate: tool({
|
|
13272
13290
|
description: "Navigate to a URL in the browser",
|
|
13273
13291
|
args: {
|
package/extension/background.js
CHANGED
|
@@ -101,6 +101,7 @@ async function executeTool(toolName, args) {
|
|
|
101
101
|
get_active_tab: toolGetActiveTab,
|
|
102
102
|
get_tabs: toolGetTabs,
|
|
103
103
|
open_tab: toolOpenTab,
|
|
104
|
+
close_tab: toolCloseTab,
|
|
104
105
|
navigate: toolNavigate,
|
|
105
106
|
click: toolClick,
|
|
106
107
|
type: toolType,
|
|
@@ -709,6 +710,12 @@ async function toolOpenTab({ url, active = true }) {
|
|
|
709
710
|
return { tabId: tab.id, content: { tabId: tab.id, url: tab.url, active: tab.active } }
|
|
710
711
|
}
|
|
711
712
|
|
|
713
|
+
async function toolCloseTab({ tabId }) {
|
|
714
|
+
if (!Number.isFinite(tabId)) throw new Error("tabId is required")
|
|
715
|
+
await chrome.tabs.remove(tabId)
|
|
716
|
+
return { tabId, content: { tabId, closed: true } }
|
|
717
|
+
}
|
|
718
|
+
|
|
712
719
|
async function toolNavigate({ url, tabId }) {
|
|
713
720
|
if (!url) throw new Error("URL is required")
|
|
714
721
|
const tab = await getTabById(tabId)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@different-ai/opencode-browser",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "Browser automation plugin for OpenCode (native messaging + per-tab ownership).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,15 +18,6 @@
|
|
|
18
18
|
"extension",
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "bun build src/plugin.ts --target=node --outfile=dist/plugin.js",
|
|
23
|
-
"prepublishOnly": "bun run build",
|
|
24
|
-
"publish": "node -e \"const argv=(() => { try { return JSON.parse(process.env.npm_config_argv || '{}').original || []; } catch { return []; } })(); if (argv.length === 1 && argv[0] === 'publish') process.exit(0); require('child_process').execSync('npm publish --access public', { stdio: 'inherit' });\"",
|
|
25
|
-
"install": "node bin/cli.js install",
|
|
26
|
-
"uninstall": "node bin/cli.js uninstall",
|
|
27
|
-
"status": "node bin/cli.js status",
|
|
28
|
-
"tool-test": "bun bin/tool-test.ts"
|
|
29
|
-
},
|
|
30
21
|
"keywords": [
|
|
31
22
|
"opencode",
|
|
32
23
|
"browser",
|
|
@@ -54,5 +45,12 @@
|
|
|
54
45
|
"devDependencies": {
|
|
55
46
|
"@opencode-ai/plugin": "*",
|
|
56
47
|
"bun-types": "*"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "bun build src/plugin.ts --target=node --outfile=dist/plugin.js",
|
|
51
|
+
"install": "node bin/cli.js install",
|
|
52
|
+
"uninstall": "node bin/cli.js uninstall",
|
|
53
|
+
"status": "node bin/cli.js status",
|
|
54
|
+
"tool-test": "bun bin/tool-test.ts"
|
|
57
55
|
}
|
|
58
|
-
}
|
|
56
|
+
}
|