← Commit history

v0.16.36 (insiders): nb-bridge#53: the profile_required guard now runs BEFORE the session pin is written, so an unnamed open is actually refused when several identities are connected

John Lauer ·5df4f1d57e ·28d ago ·parent a0dd997
7 files changed +23−21
bin/nb-dashboard+1−1
@@ -20,7 +20,7 @@ const { execFile, spawn } = require('child_process'); const fs = require('fs'); const crypto = require('crypto'); -const VERSION = '0.16.35';           // keep in lockstep with package.json (pkg version)+const VERSION = '0.16.36';           // keep in lockstep with package.json (pkg version) // SEND TO AI IS UN-PARKED (John: "yeah, we are re-enabling the send to ai. it seems to be good now"). // The ah build thread certified the crash family dead on the gate-fixed build and the delivery leg is // proven end to end. The park const is DELETED rather than flipped, so no dead branch can resurrect it.
bridge/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.16.35\ No newline at end of file+0.16.36\ No newline at end of file
bridge/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "native-browser",   "displayName": "Adom Native Browser",-  "version": "0.16.35",+  "version": "0.16.36",   "expectedExtensionVersion": "0.2.16",   "description": "Drives the user's REAL signed-in Chrome/Edge, in two layers. Layer 1 (nb) needs NOTHING installed and works on any machine: nbrowser_open_os_window (open a URL in the user's real profile, background+flashing, the OAuth/consent path), nbrowser_os_windows, nbrowser_profiles, nbrowser_wake_profile, nbrowser_force_close. Layer 2 (nbe, the Adom Native Browser Extension) unlocks the rest: CDP driving (navigate/click/read/screenshot) inside their logged-in profile. The bridge binds an ephemeral loopback port and the native-messaging host pumps stdio <-> bridge.",   "homepage": "https://wiki.adom.inc/adom/nb-bridge",
bridge/package.json+1−1
@@ -1,6 +1,6 @@ {   "name": "adom-native-browser-bridge",-  "version": "0.16.35",+  "version": "0.16.36",   "private": true,   "description": "Native-browser bridge for Bridge (ab): layer 1 (nb) plus layer 2 via nbe, the Adom Native Browser Extension (Chrome + Edge).",   "main": "server.js",
bridge/server.js+15−15
@@ -2981,21 +2981,6 @@ function dispatch(verb, args) {       activityStart(id, verb, args && args.sessionId);       sock.write(JSON.stringify({ id, verb, args: args || {} }) + '\n');     };-    // PIN the session to whatever profile this window opened in, so every later verb carrying this-    // sessionId auto-routes back to the SAME profile (no cross-profile mistakes) even without `profile:`.-    if (verb === 'nbrowser_open_window' && args && args.sessionId) { if (tgt.key && !/^pending-/.test(tgt.key)) sessionProfile.set(args.sessionId, tgt.key); if (args.thread) sessionThread.set(args.sessionId, args.thread); if (args.purpose) sessionPurpose.set(args.sessionId, args.purpose); const _c = callerLabel(); if (_c) sessionCaller.set(args.sessionId, _c); persistSessions(); }-    // CONCURRENT-AGENT ARBITRATION (wiki #345 ask 2): ~20 AI threads share one desktop. If a DIFFERENT-    // thread drives a session someone else registered, warn and NAME the owner so they can coordinate.-    // A warning, not a refusal - the owning-thread refusal already exists for destructive cross-thread-    // ops (force_close). Self-asserted identity: never an authorization decision.-    if (args && args.sessionId && verb !== 'nbrowser_open_window') {-      const owner = sessionCaller.get(args.sessionId);-      const nowCaller = callerLabel();-      if (owner && nowCaller && owner !== nowCaller) {-        crossThreadWarn = `⚠️ CONCURRENT AGENTS: session '${args.sessionId}' was opened by AI thread "${owner}", but this call came from "${nowCaller}". You are driving another thread's window - coordinate with them or open your own window (nbrowser_open_window) instead of sharing one. Allowed, but the other thread may be mid-task.`;-        logActivity({ verb: '_cross_thread', sessionId: args.sessionId, ok: true, ops: `${nowCaller} -> ${owner}`, internal: true });-      }-    }     // WRONG-ACCOUNT GUARD (John, nb-bridge#53, 2026-10-14): an agent opened a window with no `profile`,     // landed in whichever identity happened to be active ([email protected]), and got as far as Google's     // account chooser for a sign-in meant to be John's. Driving the wrong account is a worse mistake than@@ -3017,6 +3002,21 @@ function dispatch(verb, args) {           _next: choices.map((x) => `retry with profile:"${x.profile}"${x.displayName ? ` (${x.displayName})` : ''}`) });       }     }+    // PIN the session to whatever profile this window opened in, so every later verb carrying this+    // sessionId auto-routes back to the SAME profile (no cross-profile mistakes) even without `profile:`.+    if (verb === 'nbrowser_open_window' && args && args.sessionId) { if (tgt.key && !/^pending-/.test(tgt.key)) sessionProfile.set(args.sessionId, tgt.key); if (args.thread) sessionThread.set(args.sessionId, args.thread); if (args.purpose) sessionPurpose.set(args.sessionId, args.purpose); const _c = callerLabel(); if (_c) sessionCaller.set(args.sessionId, _c); persistSessions(); }+    // CONCURRENT-AGENT ARBITRATION (wiki #345 ask 2): ~20 AI threads share one desktop. If a DIFFERENT+    // thread drives a session someone else registered, warn and NAME the owner so they can coordinate.+    // A warning, not a refusal - the owning-thread refusal already exists for destructive cross-thread+    // ops (force_close). Self-asserted identity: never an authorization decision.+    if (args && args.sessionId && verb !== 'nbrowser_open_window') {+      const owner = sessionCaller.get(args.sessionId);+      const nowCaller = callerLabel();+      if (owner && nowCaller && owner !== nowCaller) {+        crossThreadWarn = `⚠️ CONCURRENT AGENTS: session '${args.sessionId}' was opened by AI thread "${owner}", but this call came from "${nowCaller}". You are driving another thread's window - coordinate with them or open your own window (nbrowser_open_window) instead of sharing one. Allowed, but the other thread may be mid-task.`;+        logActivity({ verb: '_cross_thread', sessionId: args.sessionId, ok: true, ops: `${nowCaller} -> ${owner}`, internal: true });+      }+    }     // For open_window, snapshot the Chrome window list BEFORE forwarding so the post-open diff reliably     // catches the new window (the old fire-and-forget snapshot raced the window appearing).     if (verb === 'nbrowser_open_window') {
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "nb-bridge",-  "version": "0.16.35",+  "version": "0.16.36",   "type": "app",   "title": "NB - Native Browser Bridge",   "description": "This package installs the SKILLS into your container so your AI knows how to drive your real signed-in Chrome and Edge; Bridge loads the bridge runtime itself from the release zip.",
tools/verb-battery.mjs+3−1
@@ -86,7 +86,9 @@ const T = {   open_minimized: () => {     const sid = SID + '-min';     const o = call('nbrowser_open_window', { sessionId: sid, thread: THREAD, purpose: 'battery: minimized open', profile: PROFILE, url: HARNESS, state: 'minimized' });-    const st = o.ok === true ? call('nbrowser_window_state', { sessionId: sid }) : {};+    // nbrowser_window_state is a SETTER (no args = fullscreen), so read the state from the window list.+    const lw = o.ok === true ? call('nbrowser_list_windows', { profile: PROFILE }) : {};+    const st = { state: ((lw.windows || []).find((w) => w.sessionId === sid) || {}).state };     const ev = o.ok === true ? call('nbrowser_eval', { sessionId: sid, expression: '1+1' }) : {};     if (o.ok === true) call('nbrowser_close_window', { sessionId: sid });     return A(o.ok === true && String(st.state || '').toLowerCase() === 'minimized' && (ev.result === 2 || ev.ok === true), `opened minimized (state:${st.state}) and still drivable`, JSON.stringify({ o: String(o.error || o.ok), st: st.state, ev: ev.result }).slice(0, 200));