opencode-browser-annotation-plugin 0.6.1 → 0.7.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
@@ -177,8 +177,13 @@ The plugin source is `src/plugin.ts`; the extension is plain MV3 in `extension/`
177
177
  ## Limits
178
178
 
179
179
  - Text + element metadata only; no screenshot is sent or seen by the model.
180
- - The plugin injects into the most recently active session (tracked via the
181
- `chat.message` hook). Send a message first so a session is active.
180
+ - The picker lists every recent session across all projects and all running
181
+ OpenCode processes (the store is shared), with sessions you've touched this
182
+ run floating to the top. Pick any of them by id; without a `sessionID` the
183
+ plugin targets the most recently active one.
184
+ - A single server owns the port (default `39517`); the first OpenCode process to
185
+ bind it serves the extension for every session. Send a message first so a
186
+ session is active if you rely on the no-`sessionID` fallback.
182
187
 
183
188
  ## License
184
189
 
package/dist/plugin.js CHANGED
@@ -139,17 +139,19 @@ function sendJson(res, status, body) {
139
139
  res.statusCode = status;
140
140
  res.end(payload);
141
141
  }
142
- export const BrowserAnnotationPlugin = async ({ client, directory }) => {
142
+ export const BrowserAnnotationPlugin = async ({ client }) => {
143
143
  const host = envHost();
144
144
  const port = envPort();
145
145
  let activeSessionID = null;
146
146
  let server = null;
147
- // Sessions that showed activity in THIS OpenCode run (created, messaged, or
148
- // status/idle events). OpenCode has no open/closed flag, so this approximates
149
- // "sessions you're currently working in". Deleted sessions are removed.
147
+ // Sessions this run has touched (created / messaged / status / idle). Used
148
+ // only to bias the picker ordering NOT to filter — so sessions from other
149
+ // OpenCode processes and other project directories still appear.
150
150
  const activeIDs = new Set();
151
- const RECENT_FALLBACK_MS = 2 * 60 * 60 * 1000; // 2h
152
- const RECENT_FALLBACK_MAX = 8;
151
+ // The picker shows every recent session across all directories/processes so
152
+ // one server (whichever wins the port) can target any of them; the shared
153
+ // OpenCode store makes them all reachable over the single loopback port.
154
+ const RECENT_MAX = 25;
153
155
  const log = (level, message, extra) => {
154
156
  void client.app
155
157
  .log({ body: { service: "browser-annotation", level, message, extra } })
@@ -157,7 +159,10 @@ export const BrowserAnnotationPlugin = async ({ client, directory }) => {
157
159
  };
158
160
  async function allSessions() {
159
161
  try {
160
- const res = (await client.session.list({ query: { directory } }));
162
+ // No directory filter: list every session in the shared OpenCode store so
163
+ // the picker spans all projects and all running processes, not just this
164
+ // plugin instance's own directory.
165
+ const res = (await client.session.list({}));
161
166
  const rows = Array.isArray(res) ? res : Array.isArray(res?.data) ? res.data : [];
162
167
  return rows
163
168
  .filter((s) => s && typeof s.id === "string" && !s.parentID)
@@ -169,31 +174,30 @@ export const BrowserAnnotationPlugin = async ({ client, directory }) => {
169
174
  }
170
175
  }
171
176
  /**
172
- * The picker list: sessions active in this run (newest first). If none have
173
- * been observed yet (e.g. right after a restart), fall back to the most
174
- * recently updated few so the picker is not empty. All live in this one
175
- * process, so any can be targeted over the single port.
177
+ * The picker list: all sessions, newest first. Sessions this run has actively
178
+ * touched sort ahead of the rest (recency within each group), so "what you're
179
+ * working on" floats to the top without hiding sessions owned by other
180
+ * OpenCode processes or directories.
176
181
  */
177
182
  async function listSessions() {
178
183
  const all = await allSessions();
179
- const byRecent = [...all].sort((a, b) => b.updated - a.updated);
180
- // Prune ids that no longer exist.
184
+ // Prune tracked ids that no longer exist.
181
185
  const existing = new Set(all.map((s) => s.id));
182
186
  for (const id of activeIDs)
183
187
  if (!existing.has(id))
184
188
  activeIDs.delete(id);
185
- if (activeIDs.size > 0) {
186
- return byRecent.filter((s) => activeIDs.has(s.id));
187
- }
188
- const now = Date.now();
189
- const recent = byRecent.filter((s) => now - s.updated < RECENT_FALLBACK_MS).slice(0, RECENT_FALLBACK_MAX);
190
- return recent.length ? recent : byRecent.slice(0, RECENT_FALLBACK_MAX);
189
+ const byRecent = [...all].sort((a, b) => b.updated - a.updated);
190
+ // Stable partition: touched-this-run first, everything else after; each
191
+ // group already in recency order.
192
+ const touched = byRecent.filter((s) => activeIDs.has(s.id));
193
+ const rest = byRecent.filter((s) => !activeIDs.has(s.id));
194
+ return [...touched, ...rest].slice(0, RECENT_MAX);
191
195
  }
192
196
  async function injectPrompt(sessionID, annotations) {
193
197
  try {
198
+ // No directory scoping: target the session by id wherever it lives.
194
199
  await client.session.promptAsync({
195
200
  path: { id: sessionID },
196
- query: { directory },
197
201
  body: { parts: [{ type: "text", text: buildPrompt(annotations) }] },
198
202
  });
199
203
  return { ok: true };
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,27 @@
1
+ <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" y1="0" x2="0" y2="128" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#22262e"/>
5
+ <stop offset="1" stop-color="#15171c"/>
6
+ </linearGradient>
7
+ <linearGradient id="mint" x1="34" y1="30" x2="94" y2="98" gradientUnits="userSpaceOnUse">
8
+ <stop offset="0" stop-color="#7ef0c8"/>
9
+ <stop offset="1" stop-color="#39c79a"/>
10
+ </linearGradient>
11
+ </defs>
12
+
13
+ <!-- rounded dark badge -->
14
+ <rect x="4" y="4" width="120" height="120" rx="28" fill="url(#bg)"/>
15
+ <rect x="4.5" y="4.5" width="119" height="119" rx="27.5" fill="none" stroke="#3a3f49" stroke-width="1"/>
16
+
17
+ <!-- element-picker corner brackets (mint) -->
18
+ <g stroke="url(#mint)" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" fill="none">
19
+ <path d="M34 50 V38 A4 4 0 0 1 38 34 H50"/>
20
+ <path d="M78 34 H90 A4 4 0 0 1 94 38 V50"/>
21
+ <path d="M34 78 V90 A4 4 0 0 1 38 94 H50"/>
22
+ </g>
23
+
24
+ <!-- cursor / pick arrow, lower-right, on top of brackets -->
25
+ <path d="M66 60 L98 74 L83 80 L91 98 L82 102 L74 84 L62 92 Z"
26
+ fill="#ffffff" stroke="#15171c" stroke-width="3" stroke-linejoin="round"/>
27
+ </svg>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "OpenCode Browser Annotation",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "description": "Alt+A to annotate an element, Alt+Shift+A for the annotation list. Sends element metadata to your OpenCode agent.",
6
6
  "permissions": [
7
7
  "activeTab",
@@ -16,8 +16,20 @@
16
16
  "service_worker": "background.js",
17
17
  "type": "module"
18
18
  },
19
+ "icons": {
20
+ "16": "icons/icon-16.png",
21
+ "32": "icons/icon-32.png",
22
+ "48": "icons/icon-48.png",
23
+ "128": "icons/icon-128.png"
24
+ },
19
25
  "action": {
20
- "default_title": "OpenCode Annotation — Alt+A to pick, Alt+Shift+A for list"
26
+ "default_title": "OpenCode Annotation — Alt+A to pick, Alt+Shift+A for list",
27
+ "default_icon": {
28
+ "16": "icons/icon-16.png",
29
+ "32": "icons/icon-32.png",
30
+ "48": "icons/icon-48.png",
31
+ "128": "icons/icon-128.png"
32
+ }
21
33
  },
22
34
  "options_page": "options.html",
23
35
  "commands": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-browser-annotation-plugin",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Select an element in your browser, type an instruction, and send it to your OpenCode agent over a loopback + SSH tunnel. Text and element metadata only (no screenshots).",
5
5
  "keywords": [
6
6
  "opencode",
@@ -34,6 +34,7 @@
34
34
  "scripts": {
35
35
  "build": "tsc -p tsconfig.json",
36
36
  "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "pack:ext": "node scripts/pack-extension.mjs",
37
38
  "prepublishOnly": "npm run build"
38
39
  },
39
40
  "peerDependencies": {