← Commit history
nb 0.4.2: reap zombie hosts on EVIDENCE (unanswered probes), never on age alone
5 files changed
+27−11
bridge/BRIDGE_VERSION+1−1@@ -1 +1 @@-0.4.1+0.4.2
bridge/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "native-browser", "displayName": "Adom Native Browser",- "version": "0.4.1",+ "version": "0.4.2", "expectedExtensionVersion": "0.2.5", "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.4.1",+ "version": "0.4.2", "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+19−3@@ -734,8 +734,17 @@ let _lastResolveNudge = 0; // offering the install, and the user's other thread reported "nb opens windows but nbe says not // connected". A pending conn that has ignored several whoami nudges is not resolving, it is dead: say so // and reap it, so state falls through to the honest needs-extension.-const PENDING_GRACE_MS = 45000;-const isZombie = (c) => !!(c && c.provisional && c.since && (Date.now() - c.since) > PENDING_GRACE_MS);+// ⛔ REAP ON EVIDENCE, NOT ON AGE. The first cut of this reaper used age alone and immediately killed+// HEALTHY connections on John's laptop: after a bridge restart the native host reconnects its socket but+// the extension does not spontaneously re-announce, so a perfectly drivable profile sits at pending-N+// with no hello and looked exactly like a corpse. A pending conn is only dead if it has IGNORED repeated+// whoami probes - silence we actually asked for. Any frame at all on the socket (hello, reply, pong)+// clears the strike count, so a live-but-quiet extension is never reaped.+const PENDING_GRACE_MS = 120000; // never reap inside the first 2 minutes, whatever the probes say+const PENDING_MAX_STRIKES = 4; // 4 unanswered whoami nudges (~40s at the 10s cadence)+const isZombie = (c) => !!(c && c.provisional && c.since+ && (Date.now() - c.since) > PENDING_GRACE_MS+ && (c.probeStrikes || 0) >= PENDING_MAX_STRIKES); function resolvePendingProfiles() { const now = Date.now(); if (_lastResolveNudge + 10000 > now) return; _lastResolveNudge = now; for (const [k, c] of conns) {@@ -749,7 +758,12 @@ function resolvePendingProfiles() { if (activeProfile === k) activeProfile = null; continue; }- try { const id = ++seq; pending.set(id, { resolve: () => {}, timer: setTimeout(() => pending.delete(id), 4000), verb: 'nbrowser_whoami', profileKey: k, _internal: true }); c.sock.write(JSON.stringify({ id, verb: 'nbrowser_whoami', args: {} }) + '\n'); } catch {}+ try {+ const id = ++seq;+ pending.set(id, { resolve: () => {}, timer: setTimeout(() => pending.delete(id), 4000), verb: 'nbrowser_whoami', profileKey: k, _internal: true });+ c.sock.write(JSON.stringify({ id, verb: 'nbrowser_whoami', args: {} }) + '\n');+ c.probeStrikes = (c.probeStrikes || 0) + 1; // cleared by ANY inbound frame on this socket+ } catch {} } } // Paint the "Adom is driving" badge: our composite (circle avatar + favicon corner) or NOTHING yet.@@ -2560,6 +2574,8 @@ const hostSrv = net.createServer((sock) => { registerProvisional(sock); let buf = ''; sock.on('data', (chunk) => {+ // ANY inbound byte proves something is alive behind this socket - clear its zombie strikes.+ for (const [, c] of conns) if (c.sock === sock) { c.probeStrikes = 0; break; } buf += chunk.toString('utf8'); let nl; while ((nl = buf.indexOf('\n')) >= 0) {
native-browser-bridge-manifest.json+5−5@@ -1,8 +1,8 @@ { "manifest_version": 1,- "version": "0.4.1",- "url": "https://wiki.adom.inc/download/adom/nb-bridge/0.4.1/native-browser-bridge-v0.4.1.zip",- "sha256": "67ee216a27030a2a7985852d80dab2e63cee92631f50a12c2f44861e8b9b422b",- "size": 104250,- "released_at": "2026-08-22T14:03:25Z"+ "version": "0.4.2",+ "url": "https://wiki.adom.inc/download/adom/nb-bridge/0.4.2/native-browser-bridge-v0.4.2.zip",+ "sha256": "7807d3166aae85c0f004f8f56511fcd7a560748560576999dfbe0916b11b5845",+ "size": 104737,+ "released_at": "2026-08-22T14:06:07Z" }