@jobshimo/browser-link 0.11.0 → 0.12.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.
@@ -10,7 +10,8 @@
10
10
  * `primary-elected` event as the fundamental marker — older history is
11
11
  * intentionally lost (the agent has nothing useful to do with it anyway).
12
12
  */
13
- export type BridgeEventKind = 'primary-elected' | 'tab-registered' | 'tab-disconnected' | 'tab-renamed' | 'tab-claimed' | 'tab-released' | 'tab-claim-rejected';
13
+ export type BridgeEventKind = 'primary-elected' | 'tab-registered' | 'tab-disconnected' | 'tab-renamed' | 'tab-claimed' | 'tab-released' | 'tab-claim-rejected' | 'dialog-opening' | 'dialog-closed' | 'tab-created';
14
+ export declare function isExtensionEventKind(kind: string): kind is BridgeEventKind;
14
15
  export interface BridgeEvent {
15
16
  /** Monotonic id assigned by addEvent. */
16
17
  id: number;
@@ -20,11 +21,33 @@ export interface BridgeEvent {
20
21
  /** Kind-specific payload. Documented per-kind in the JSDoc below. */
21
22
  data: Record<string, unknown>;
22
23
  }
24
+ export type BridgeEventListener = (event: BridgeEvent) => void;
25
+ export interface SubscribeOptions {
26
+ /** If > 0, the listener is invoked synchronously with every event in the
27
+ * buffer that is at most `replayWithinMs` old, BEFORE subscribe returns.
28
+ * Lets a caller racing the source of an event still see it: the agent
29
+ * fires an action and `wait_for_tab` in the same MCP batch, the action
30
+ * lands first, wait_for_tab subscribes with replayWithinMs=1500 and the
31
+ * fresh `tab-created` event reaches its listener. Events older than the
32
+ * window are NOT replayed — those belong to a previous flow. */
33
+ replayWithinMs?: number;
34
+ }
23
35
  export declare class BridgeEventLog {
24
36
  private buffer;
25
37
  private nextId;
26
- /** Append an event and return it. Drops the oldest if the buffer is full. */
38
+ private listeners;
39
+ /** Append an event and return it. Drops the oldest if the buffer is full.
40
+ * Notifies every active subscriber synchronously AFTER the buffer is
41
+ * updated — so a listener that calls `recent()` sees the new entry. */
27
42
  add(kind: BridgeEventKind, data?: Record<string, unknown>): BridgeEvent;
43
+ /** Subscribe to every event ADDED after this call returns. Returns an
44
+ * unsubscribe function the caller MUST invoke (on completion / timeout /
45
+ * error) to avoid leaks.
46
+ *
47
+ * If `options.replayWithinMs` is set, recent events from the buffer are
48
+ * replayed synchronously to the listener BEFORE subscribe returns —
49
+ * see `SubscribeOptions.replayWithinMs` for the rationale. */
50
+ subscribe(fn: BridgeEventListener, options?: SubscribeOptions): () => void;
28
51
  /** Return up to `limit` recent events, optionally filtered to those
29
52
  * with id > sinceId. Cursor pattern — pass the previous-call's last id
30
53
  * back in as sinceId to get only what's new. */
@@ -10,11 +10,25 @@
10
10
  * `primary-elected` event as the fundamental marker — older history is
11
11
  * intentionally lost (the agent has nothing useful to do with it anyway).
12
12
  */
13
+ /** Kinds the extension is permitted to push via `bridge.event`. Lifecycle
14
+ * events (primary-elected, tab-registered, etc.) are produced server-side
15
+ * and must NOT be spoofable from the extension side. */
16
+ const EXTENSION_EVENT_KINDS = new Set([
17
+ 'dialog-opening',
18
+ 'dialog-closed',
19
+ 'tab-created',
20
+ ]);
21
+ export function isExtensionEventKind(kind) {
22
+ return EXTENSION_EVENT_KINDS.has(kind);
23
+ }
13
24
  const MAX_EVENTS = 200;
14
25
  export class BridgeEventLog {
15
26
  buffer = [];
16
27
  nextId = 1;
17
- /** Append an event and return it. Drops the oldest if the buffer is full. */
28
+ listeners = new Set();
29
+ /** Append an event and return it. Drops the oldest if the buffer is full.
30
+ * Notifies every active subscriber synchronously AFTER the buffer is
31
+ * updated — so a listener that calls `recent()` sees the new entry. */
18
32
  add(kind, data = {}) {
19
33
  const event = {
20
34
  id: this.nextId++,
@@ -25,8 +39,53 @@ export class BridgeEventLog {
25
39
  this.buffer.push(event);
26
40
  if (this.buffer.length > MAX_EVENTS)
27
41
  this.buffer.shift();
42
+ // Iterate a snapshot of the set so a listener that unsubscribes itself
43
+ // mid-fire doesn't skip its peers. Catch per-listener errors so one
44
+ // bad listener can't take the whole notification chain down.
45
+ for (const fn of [...this.listeners]) {
46
+ try {
47
+ fn(event);
48
+ }
49
+ catch {
50
+ // Best-effort delivery — listener failures stay local.
51
+ }
52
+ }
28
53
  return event;
29
54
  }
55
+ /** Subscribe to every event ADDED after this call returns. Returns an
56
+ * unsubscribe function the caller MUST invoke (on completion / timeout /
57
+ * error) to avoid leaks.
58
+ *
59
+ * If `options.replayWithinMs` is set, recent events from the buffer are
60
+ * replayed synchronously to the listener BEFORE subscribe returns —
61
+ * see `SubscribeOptions.replayWithinMs` for the rationale. */
62
+ subscribe(fn, options = {}) {
63
+ // Register first so a listener that opts to unsubscribe itself during
64
+ // replay does so against a live registration (the unsubscribe path
65
+ // calls `this.listeners.delete(fn)` and the replay loop breaks when
66
+ // membership drops).
67
+ this.listeners.add(fn);
68
+ const replayMs = options.replayWithinMs;
69
+ if (typeof replayMs === 'number' && replayMs > 0) {
70
+ const cutoff = Date.now() - replayMs;
71
+ for (const e of this.buffer) {
72
+ if (!this.listeners.has(fn))
73
+ break;
74
+ const at = Date.parse(e.at);
75
+ if (!Number.isFinite(at) || at < cutoff)
76
+ continue;
77
+ try {
78
+ fn(e);
79
+ }
80
+ catch {
81
+ // Best-effort replay.
82
+ }
83
+ }
84
+ }
85
+ return () => {
86
+ this.listeners.delete(fn);
87
+ };
88
+ }
30
89
  /** Return up to `limit` recent events, optionally filtered to those
31
90
  * with id > sinceId. Cursor pattern — pass the previous-call's last id
32
91
  * back in as sinceId to get only what's new. */
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/bridge/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAqBH,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,OAAO,cAAc;IACjB,MAAM,GAAkB,EAAE,CAAC;IAC3B,MAAM,GAAG,CAAC,CAAC;IAEnB,6EAA6E;IAC7E,GAAG,CAAC,IAAqB,EAAE,OAAgC,EAAE;QAC3D,MAAM,KAAK,GAAgB;YACzB,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE;YACjB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI;YACJ,IAAI;SACL,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,UAAU;YAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;oDAEgD;IAChD,MAAM,CAAC,OAA6C,EAAE;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,QAAQ,GACZ,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC;QAClF,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,2DAA2D;IAC3D,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,CAAC;IAED,4CAA4C;IAC5C,IAAI;QACF,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;6EACyE;IACzE,KAAK;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/bridge/events.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { WebSocket, WebSocketServer } from 'ws';
2
- import type { BridgeEventLog } from './events.js';
2
+ import { type BridgeEventLog } from './events.js';
3
3
  export declare const WS_HOST = "127.0.0.1";
4
4
  export declare const WS_PORT = 17529;
5
5
  export interface TabSession {
@@ -1,6 +1,8 @@
1
1
  import { WebSocketServer } from 'ws';
2
2
  import { isAllowedBrowser } from '../auth/allowlist.js';
3
3
  import { lookupPeerProcess } from '../auth/process-identity.js';
4
+ import { VERSION } from '../version.js';
5
+ import { isExtensionEventKind } from './events.js';
4
6
  export const WS_HOST = '127.0.0.1';
5
7
  export const WS_PORT = 17529;
6
8
  function log(msg) {
@@ -142,7 +144,10 @@ export function startWsBridge(tabs, pendingRequests, events) {
142
144
  title: msg.payload.title,
143
145
  ws,
144
146
  });
145
- send(ws, { kind: 'tab.registered', payload: { tabId: assignedTabId } });
147
+ send(ws, {
148
+ kind: 'tab.registered',
149
+ payload: { tabId: assignedTabId, serverVersion: VERSION },
150
+ });
146
151
  log(`Tab registered: ${assignedTabId} -> ${msg.payload.url}`);
147
152
  if (previousTabId && previousTabId !== assignedTabId) {
148
153
  events.add('tab-renamed', {
@@ -172,6 +177,22 @@ export function startWsBridge(tabs, pendingRequests, events) {
172
177
  pending.resolve(msg.result);
173
178
  else
174
179
  pending.reject(new Error(msg.error));
180
+ return;
181
+ }
182
+ if (msg.kind === 'bridge.event') {
183
+ // Closed allowlist — the extension can only push the kinds tied to
184
+ // popup awareness (dialogs / new tabs). Lifecycle kinds (primary-elected,
185
+ // tab-registered, etc.) stay server-owned so they can't be spoofed
186
+ // from the renderer side.
187
+ if (!isExtensionEventKind(msg.eventKind)) {
188
+ log(`Ignoring bridge.event with unknown/forbidden kind: ${msg.eventKind}`);
189
+ return;
190
+ }
191
+ const data = { ...msg.data };
192
+ if (msg.tabId)
193
+ data.tab_id = msg.tabId;
194
+ events.add(msg.eventKind, data);
195
+ return;
175
196
  }
176
197
  });
177
198
  ws.on('close', () => {
@@ -1 +1 @@
1
- {"version":3,"file":"ws-bridge.js","sourceRoot":"","sources":["../../src/bridge/ws-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws-bridge.js","sourceRoot":"","sources":["../../src/bridge/ws-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,eAAe,EAAE,MAAM,IAAI,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAuB,MAAM,aAAa,CAAC;AAExE,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,CAAC;AACnC,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,CAAC;AAe7B,SAAS,GAAG,CAAC,GAAW;IACtB,OAAO,CAAC,KAAK,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,EAAa,EAAE,GAAsB;IACjD,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,kBAAkB;QAAE,OAAO,WAAW,CAAC;IACtE,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;6EAC6E;AAC7E,MAAM,cAAe,SAAQ,KAAK;IAChC;QACE,KAAK,CAAC,sBAAsB,OAAO,IAAI,OAAO,qBAAqB,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,SAAS,kBAAkB,CAAC,GAA0B;IACpD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,cAAc,EAAE,CAAC;IAC3D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,GAAG,YAAY,cAAc,CAAC;AACvC,CAAC;AAED,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,SAAS,WAAW;IAClB,YAAY,IAAI,CAAC,CAAC;IAClB,OAAO,OAAO,YAAY,EAAE,CAAC;AAC/B,CAAC;AAED;;;oBAGoB;AACpB,MAAM,UAAU,aAAa,CAC3B,IAA6B,EAC7B,eAA4C,EAC5C,MAAsB;IAEtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC;YAC9B,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,OAAO;YACb,yEAAyE;YACzE,yEAAyE;YACzE,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;gBACzB,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;gBAC7E,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;gBAC9C,IAAI,CAAC,aAAa,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;oBACzC,GAAG,CAAC,iEAAiE,CAAC,CAAC;oBACvE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;oBACvC,OAAO;gBACT,CAAC;gBACD,iBAAiB,CAAC,aAAa,EAAE,UAAU,CAAC;qBACzC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;oBACb,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,GAAG,CACD,8BAA8B,aAAa,IAAI,UAAU,sCAAsC,CAChG,CAAC;wBACF,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;wBACvC,OAAO;oBACT,CAAC;oBACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;wBACvC,GAAG,CACD,kCAAkC,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,UAAU,kCAAkC,CACjG,CAAC;wBACF,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,sCAAsC,CAAC,CAAC;wBACvD,OAAO;oBACT,CAAC;oBACD,EAAE,CAAC,IAAI,CAAC,CAAC;gBACX,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;oBACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC7D,GAAG,CAAC,iDAAiD,GAAG,IAAI,CAAC,CAAC;oBAC9D,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,uBAAuB,CAAC,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACP,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;YACvB,OAAO,GAAG,IAAI,CAAC;YACf,GAAG,CAAC,+BAA+B,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;gBAChC,OAAO;YACT,CAAC;YACD,2EAA2E;YAC3E,qBAAqB;YACrB,GAAG,CAAC,2BAA2B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE;YAC1B,IAAI,aAAa,GAAkB,IAAI,CAAC;YAExC,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,iEAAiE;gBACjE,iEAAiE;gBACjE,kDAAkD;gBAClD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAC/B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;oBACtB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;wBAClB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;wBACrC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACxC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,CAAC,GAAG;oBAAE,OAAO;gBAEjB,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,CAAC,aAAa,EAAE,CAAC;oBAClD,gEAAgE;oBAChE,iEAAiE;oBACjE,+DAA+D;oBAC/D,4BAA4B;oBAC5B,MAAM,aAAa,GACjB,OAAO,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;oBACxF,IAAI,aAAa,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;wBACjF,aAAa,GAAG,aAAa,CAAC;wBAC9B,8DAA8D;wBAC9D,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC3D,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY;4BAAE,YAAY,GAAG,CAAC,CAAC;oBAC/D,CAAC;yBAAM,CAAC;wBACN,aAAa,GAAG,WAAW,EAAE,CAAC;oBAChC,CAAC;oBACD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE;wBACtB,KAAK,EAAE,aAAa;wBACpB,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG;wBACpB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK;wBACxB,EAAE;qBACH,CAAC,CAAC;oBACH,IAAI,CAAC,EAAE,EAAE;wBACP,IAAI,EAAE,gBAAgB;wBACtB,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE;qBAC1D,CAAC,CAAC;oBACH,GAAG,CAAC,mBAAmB,aAAa,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;oBAC9D,IAAI,aAAa,IAAI,aAAa,KAAK,aAAa,EAAE,CAAC;wBACrD,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE;4BACxB,QAAQ,EAAE,aAAa;4BACvB,OAAO,EAAE,aAAa;4BACtB,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG;4BACpB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK;yBACzB,CAAC,CAAC;wBACH,GAAG,CAAC,mBAAmB,aAAa,OAAO,aAAa,EAAE,CAAC,CAAC;oBAC9D,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE;4BAC3B,KAAK,EAAE,aAAa;4BACpB,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG;4BACpB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK;yBACzB,CAAC,CAAC;oBACL,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;oBACjC,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC5C,IAAI,CAAC,OAAO;wBAAE,OAAO;oBACrB,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBAC9B,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC/B,IAAI,GAAG,CAAC,EAAE;wBAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;;wBACnC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;oBAC1C,OAAO;gBACT,CAAC;gBAED,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBAChC,mEAAmE;oBACnE,0EAA0E;oBAC1E,mEAAmE;oBACnE,0BAA0B;oBAC1B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;wBACzC,GAAG,CAAC,sDAAsD,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;wBAC3E,OAAO;oBACT,CAAC;oBACD,MAAM,IAAI,GAA4B,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;oBACtD,IAAI,GAAG,CAAC,KAAK;wBAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC;oBACvC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBAChC,OAAO;gBACT,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClB,IAAI,aAAa,EAAE,CAAC;oBAClB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;oBAC3B,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;oBACzD,GAAG,CAAC,qBAAqB,aAAa,EAAE,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrB,GAAG,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;WAGW;AACX,MAAM,UAAU,eAAe,CAC7B,IAA6B,EAC7B,eAA4C,EAC5C,KAAa,EACb,EAAU,EACV,IAAY,EACZ,MAAe,EACf,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,kEAAkE;QAClE,gEAAgE;QAChE,kEAAkE;QAClE,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CACP,sBAAsB,KAAK,8DAA8D;YACvF,2FAA2F,KAAK,IAAI;YACpG,oDAAoD,CACvD,CACF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9C,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,IAAI,qBAAqB,SAAS,IAAI,CAAC,CAAC,CAAC;QACrE,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -19,9 +19,15 @@ function isRuntimeMessage(msg) {
19
19
  if (typeof msg !== 'object' || msg === null)
20
20
  return false;
21
21
  const m = msg;
22
+ if (m.action === 'versionCheck')
23
+ return true;
22
24
  if (typeof m.tabId !== 'number')
23
25
  return false;
24
- return m.action === 'connect' || m.action === 'disconnect' || m.action === 'status';
26
+ return (m.action === 'connect' ||
27
+ m.action === 'disconnect' ||
28
+ m.action === 'status' ||
29
+ m.action === 'pendingDialog' ||
30
+ m.action === 'respondDialog');
25
31
  }
26
32
  const tabStates = new Map();
27
33
  function send(ws, msg) {
@@ -38,6 +44,43 @@ function safeParse(raw) {
38
44
  function cdp(tabId, method, params = {}) {
39
45
  return chrome.debugger.sendCommand({ tabId }, method, params);
40
46
  }
47
+ /**
48
+ * Mapping from the CDP permission name (the contract `browser.set_permission`
49
+ * accepts on the wire) to the `chrome.contentSettings` setting key. Only the
50
+ * names that actually have a contentSettings surface in MV3 are listed —
51
+ * `Browser.setPermission` covers more, but that domain is not reachable from
52
+ * `chrome.debugger` attached to a tab.
53
+ */
54
+ const CONTENT_SETTING_BY_PERMISSION = {
55
+ geolocation: 'location',
56
+ notifications: 'notifications',
57
+ camera: 'camera',
58
+ microphone: 'microphone',
59
+ clipboardReadWrite: 'clipboard',
60
+ clipboardSanitizedWrite: 'clipboard',
61
+ sensors: 'sensors',
62
+ };
63
+ const STATE_TO_CONTENT_SETTING = {
64
+ granted: 'allow',
65
+ denied: 'block',
66
+ prompt: 'ask',
67
+ };
68
+ /**
69
+ * Apply a `chrome.contentSettings.<setting>.set({ primaryPattern, setting })`
70
+ * call without statically referencing each key — the `contentSettings`
71
+ * surface is dynamic at the API level. We narrow `unknown` carefully so the
72
+ * cast is the smallest possible.
73
+ */
74
+ async function applyContentSetting(settingKey, primaryPattern, setting) {
75
+ const root = chrome.contentSettings;
76
+ if (!root)
77
+ throw new Error('chrome.contentSettings not available in this build');
78
+ const setter = root[settingKey];
79
+ if (!setter || typeof setter.set !== 'function') {
80
+ throw new Error(`chrome.contentSettings.${settingKey} is not exposed in this Chrome build`);
81
+ }
82
+ await setter.set({ primaryPattern, setting });
83
+ }
41
84
  /**
42
85
  * Defensive caps applied to every duration that ends up in a setTimeout
43
86
  * driven by tool params. The MCP request payload is technically untrusted
@@ -283,6 +326,56 @@ function attachDebuggerListener(state) {
283
326
  entry.failed = p.errorText ?? 'failed';
284
327
  return;
285
328
  }
329
+ if (method === 'Page.javascriptDialogOpening') {
330
+ // The page JS thread is now frozen until something calls
331
+ // Page.handleJavaScriptDialog. We do NOT respond automatically —
332
+ // the agent reads dialog-opening from browser.events and decides
333
+ // via browser.dialog_respond. The popup also exposes accept/dismiss
334
+ // buttons as a manual escape hatch.
335
+ const p = params;
336
+ const info = {
337
+ type: p.type ?? 'alert',
338
+ message: p.message ?? '',
339
+ };
340
+ if (typeof p.defaultPrompt === 'string')
341
+ info.default_prompt = p.defaultPrompt;
342
+ if (typeof p.url === 'string')
343
+ info.url = p.url;
344
+ state.pendingDialog = info;
345
+ if (state.ws && state.ws.readyState === WebSocket.OPEN && state.serverTabId) {
346
+ const data = {
347
+ type: info.type,
348
+ message: info.message,
349
+ };
350
+ if (info.default_prompt !== undefined)
351
+ data.default_prompt = info.default_prompt;
352
+ if (info.url !== undefined)
353
+ data.url = info.url;
354
+ send(state.ws, {
355
+ kind: 'bridge.event',
356
+ eventKind: 'dialog-opening',
357
+ tabId: state.serverTabId,
358
+ data,
359
+ });
360
+ }
361
+ return;
362
+ }
363
+ if (method === 'Page.javascriptDialogClosed') {
364
+ const p = params;
365
+ state.pendingDialog = undefined;
366
+ if (state.ws && state.ws.readyState === WebSocket.OPEN && state.serverTabId) {
367
+ const data = { accept: p.result === true };
368
+ if (typeof p.userInput === 'string')
369
+ data.user_input = p.userInput;
370
+ send(state.ws, {
371
+ kind: 'bridge.event',
372
+ eventKind: 'dialog-closed',
373
+ tabId: state.serverTabId,
374
+ data,
375
+ });
376
+ }
377
+ return;
378
+ }
286
379
  };
287
380
  state.debuggerListener = listener;
288
381
  }
@@ -901,6 +994,73 @@ async function handleTool(state, msg) {
901
994
  : { matched: false, elapsed_ms: elapsedMs, checks, reason: 'timeout' },
902
995
  };
903
996
  }
997
+ case 'dialog_respond': {
998
+ const accept = p.accept === true;
999
+ const promptText = optStr('prompt_text');
1000
+ // No probing — if there is no dialog open, CDP returns an error.
1001
+ // We propagate it; the caller decides if "no dialog to respond to"
1002
+ // is a problem or a race they can ignore.
1003
+ const params = { accept };
1004
+ if (promptText !== undefined)
1005
+ params.promptText = promptText;
1006
+ await cdp(tabId, 'Page.handleJavaScriptDialog', params);
1007
+ return {
1008
+ kind: 'tool.response',
1009
+ id: msg.id,
1010
+ ok: true,
1011
+ result: { accepted: accept },
1012
+ };
1013
+ }
1014
+ case 'set_permission': {
1015
+ const origin = str('origin');
1016
+ const name = str('name');
1017
+ const state_ = str('state');
1018
+ // CDP `Browser.setPermission` requires a browser-level target,
1019
+ // which `chrome.debugger.attach({ tabId })` does NOT give us in
1020
+ // MV3. We use `chrome.contentSettings` instead — that surface IS
1021
+ // available to extensions and covers the realistic permissions
1022
+ // an agent needs to pre-set (geolocation, notifications, camera,
1023
+ // microphone, clipboard, sensors).
1024
+ const settingKey = CONTENT_SETTING_BY_PERMISSION[name];
1025
+ if (!settingKey) {
1026
+ return {
1027
+ kind: 'tool.response',
1028
+ id: msg.id,
1029
+ ok: false,
1030
+ error: `set_permission: '${name}' is not supported by chrome.contentSettings in MV3. Supported names: ${Object.keys(CONTENT_SETTING_BY_PERMISSION).join(', ')}.`,
1031
+ };
1032
+ }
1033
+ const setting = STATE_TO_CONTENT_SETTING[state_];
1034
+ if (!setting) {
1035
+ return {
1036
+ kind: 'tool.response',
1037
+ id: msg.id,
1038
+ ok: false,
1039
+ error: `set_permission: unknown state '${state_}' (expected granted | denied | prompt).`,
1040
+ };
1041
+ }
1042
+ // `chrome.contentSettings.<name>.set({ primaryPattern, setting })`
1043
+ // requires a URL pattern, not a bare origin. Append `/*` so the
1044
+ // pattern covers every path on the origin.
1045
+ const primaryPattern = origin.endsWith('/*') ? origin : `${origin}/*`;
1046
+ try {
1047
+ await applyContentSetting(settingKey, primaryPattern, setting);
1048
+ }
1049
+ catch (err) {
1050
+ return {
1051
+ kind: 'tool.response',
1052
+ id: msg.id,
1053
+ ok: false,
1054
+ error: `set_permission: ${err instanceof Error ? err.message : String(err)}`,
1055
+ };
1056
+ }
1057
+ return {
1058
+ kind: 'tool.response',
1059
+ id: msg.id,
1060
+ ok: true,
1061
+ result: { origin, name, state: state_, applied_as: settingKey },
1062
+ };
1063
+ }
904
1064
  default:
905
1065
  return { kind: 'tool.response', id: msg.id, ok: false, error: `Unknown tool: ${msg.tool}` };
906
1066
  }
@@ -1050,6 +1210,11 @@ async function connectTab(tabId) {
1050
1210
  return;
1051
1211
  if (msg.kind === 'tab.registered') {
1052
1212
  state.serverTabId = msg.payload.tabId;
1213
+ // serverVersion is optional on the wire so older servers that
1214
+ // predate the field still parse — narrow on `typeof string`.
1215
+ if (typeof msg.payload.serverVersion === 'string') {
1216
+ state.serverVersion = msg.payload.serverVersion;
1217
+ }
1053
1218
  // Remember this id so the next reconnect (after a primary swap)
1054
1219
  // asks the new primary to honour it. The primary emits
1055
1220
  // `tab-renamed` in the bridge event log if it can't.
@@ -1094,6 +1259,40 @@ function getTabStatus(tabId) {
1094
1259
  return { connected: false };
1095
1260
  return { connected: true, serverTabId: state.serverTabId };
1096
1261
  }
1262
+ /**
1263
+ * Compute the version-mismatch summary for the popup. Picks the
1264
+ * `serverVersion` reported by ANY currently-connected tab — they all come
1265
+ * from the same primary, so the first one is enough. When no tab has
1266
+ * registered yet (e.g. user just installed and hasn't pressed Connect),
1267
+ * `server` stays null and the popup hides the banner.
1268
+ */
1269
+ function getVersionCheck() {
1270
+ const extension = chrome.runtime.getManifest().version;
1271
+ let server = null;
1272
+ for (const s of tabStates.values()) {
1273
+ if (typeof s.serverVersion === 'string' && s.serverVersion.length > 0) {
1274
+ server = s.serverVersion;
1275
+ break;
1276
+ }
1277
+ }
1278
+ return {
1279
+ extension,
1280
+ server,
1281
+ aligned: server === null ? null : server === extension,
1282
+ };
1283
+ }
1284
+ async function respondToDialogFromPopup(tabId, accept, promptText) {
1285
+ try {
1286
+ const params = { accept };
1287
+ if (promptText !== undefined)
1288
+ params.promptText = promptText;
1289
+ await cdp(tabId, 'Page.handleJavaScriptDialog', params);
1290
+ return { ok: true };
1291
+ }
1292
+ catch (err) {
1293
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
1294
+ }
1295
+ }
1097
1296
  chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
1098
1297
  if (!isRuntimeMessage(msg))
1099
1298
  return false;
@@ -1105,6 +1304,19 @@ chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
1105
1304
  void disconnectTab(msg.tabId).then(sendResponse);
1106
1305
  return true;
1107
1306
  }
1307
+ if (msg.action === 'pendingDialog') {
1308
+ const state = tabStates.get(msg.tabId);
1309
+ sendResponse({ pending: state?.pendingDialog ?? null });
1310
+ return false;
1311
+ }
1312
+ if (msg.action === 'respondDialog') {
1313
+ void respondToDialogFromPopup(msg.tabId, msg.accept, msg.promptText).then(sendResponse);
1314
+ return true;
1315
+ }
1316
+ if (msg.action === 'versionCheck') {
1317
+ sendResponse(getVersionCheck());
1318
+ return false;
1319
+ }
1108
1320
  // 'status'
1109
1321
  sendResponse(getTabStatus(msg.tabId));
1110
1322
  return false;
@@ -1116,6 +1328,87 @@ chrome.tabs.onRemoved.addListener((tabId) => {
1116
1328
  // The Chrome tab is gone — drop any cached browser-link id for it.
1117
1329
  void forgetTabId(tabId);
1118
1330
  });
1331
+ /* Auto-connect tabs spawned by a connected tab.
1332
+ *
1333
+ * When a tab the user has connected via the popup opens a new tab
1334
+ * (window.open, target="_blank", a click handler doing window.open, etc.),
1335
+ * Chrome reports it via tabs.onCreated with `openerTabId` pointing at the
1336
+ * source. We use that link to:
1337
+ * 1. Wait for the new tab to settle on a real URL (the first onCreated
1338
+ * callback often reports `about:blank` even when a destination is set).
1339
+ * 2. Auto-connect the new tab through the same flow as the popup
1340
+ * "Connect" button — attach debugger, register with the server.
1341
+ * 3. Emit a `tab-created` bridge.event tagged with `opened_from = the
1342
+ * opener's server tab id`. The MCP `browser.wait_for_tab` tool reads
1343
+ * that event and auto-claims the new tab for the waiting agent.
1344
+ *
1345
+ * If the opener is not connected (regular browsing), we do nothing —
1346
+ * background tabs the user opens for themselves stay out of the bridge.
1347
+ */
1348
+ chrome.tabs.onCreated.addListener((tab) => {
1349
+ const newTabId = tab.id;
1350
+ const openerTabId = tab.openerTabId;
1351
+ if (typeof newTabId !== 'number')
1352
+ return;
1353
+ if (typeof openerTabId !== 'number')
1354
+ return;
1355
+ const openerState = tabStates.get(openerTabId);
1356
+ if (!openerState)
1357
+ return;
1358
+ const openedFrom = openerState.serverTabId;
1359
+ if (!openedFrom)
1360
+ return;
1361
+ void (async () => {
1362
+ // Wait until chrome.tabs.get returns a real `url`. `pendingUrl` alone
1363
+ // is NOT enough — connectTab's guard short-circuits on `!tab.url`.
1364
+ // Bound at 5 s so a never-navigating tab doesn't park us forever.
1365
+ const deadline = Date.now() + 5_000;
1366
+ let ready = false;
1367
+ while (Date.now() < deadline) {
1368
+ try {
1369
+ const t = await chrome.tabs.get(newTabId);
1370
+ if (t.url && t.url.length > 0) {
1371
+ ready = true;
1372
+ break;
1373
+ }
1374
+ }
1375
+ catch {
1376
+ return;
1377
+ }
1378
+ await sleep(50);
1379
+ }
1380
+ if (!ready)
1381
+ return;
1382
+ try {
1383
+ const result = await connectTab(newTabId);
1384
+ if (!result.ok || !result.serverTabId)
1385
+ return;
1386
+ const newState = tabStates.get(newTabId);
1387
+ if (!newState?.ws || newState.ws.readyState !== WebSocket.OPEN)
1388
+ return;
1389
+ let resolvedUrl = '';
1390
+ try {
1391
+ const settled = await chrome.tabs.get(newTabId);
1392
+ resolvedUrl = settled.url ?? settled.pendingUrl ?? '';
1393
+ }
1394
+ catch {
1395
+ // Tab vanished between attach and read.
1396
+ }
1397
+ send(newState.ws, {
1398
+ kind: 'bridge.event',
1399
+ eventKind: 'tab-created',
1400
+ tabId: newState.serverTabId,
1401
+ data: {
1402
+ opened_from: openedFrom,
1403
+ url: resolvedUrl,
1404
+ },
1405
+ });
1406
+ }
1407
+ catch {
1408
+ // Auto-connect is best-effort.
1409
+ }
1410
+ })();
1411
+ });
1119
1412
  chrome.debugger.onDetach.addListener((source) => {
1120
1413
  if (source.tabId === undefined)
1121
1414
  return;