← Commit history

v1.9.16: wiki login state as the favicon plate colour, keeping the favicon in the overlay slot

John Lauer ·1c012c0c6e ·3mo ago ·parent 4faa08a
5 files changed +50−16
CHANGELOG.md+16
@@ -1,5 +1,21 @@ # Changelog — Adom Desktop Puppeteer Bridge +## 1.9.16 — 2026-07-20 — Wiki login state = the favicon's PLATE COLOUR (John's idea, the right one)++John: "why don't you just use a different background than the background you place onto the favicon+in the overlay?" Exactly right, and better than everything I tried. The overlay already composites+each site favicon onto a dark rounded plate (#0b2325), so that backdrop was free real estate:+  dark plate  = logged out / public / any non-Adom site (unchanged)+  GREEN plate = signed in to the Adom wiki+The favicon KEEPS the slot - you still see which site the active tab is on - and the plate is a far+bigger colour target at 16px than any glyph tucked into the 24px base icon. Cache key now includes+the plate state, the tooltip says "Adom wiki: SIGNED IN", and a login-state flip repaints the+overlay. .ico favicons (which sharp cannot decode) fall back to drawing the green plate alone+rather than losing the signal.++The 1.9.14 main-icon variant (solid green browser glyph) stays as a second, redundant signal for+Alt-Tab and the flyout header, where taskbar overlays are not painted.+ ## 1.9.15 — 2026-07-20 — Retry the icon re-stamp (the flip silently lost a race)  1.9.14 tracked login state correctly but the taskbar icon did not visibly change. Cause: after a
adom-bridge-puppeteer-manifest.json+5−5
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "1.9.15",-  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.15/adom-bridge-puppeteer-v1.9.15.zip",-  "sha256": "d921a7198726f8f73dda16674cebf2be9ec03ad7509554c1d253d9609bbedaab",-  "size": 235958,+  "version": "1.9.16",+  "url": "https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.9.16/adom-bridge-puppeteer-v1.9.16.zip",+  "sha256": "79173f7410a21c485f2396857e43d4fdb972b26249bb0e5114e0efe17caca447",+  "size": 236402,   "verbPrefixes": [     "browser_",     "desktop_recorder_",@@ -12,5 +12,5 @@   ],   "healthEndpoint": "/status",   "statusVerb": "browser_readiness",-  "released_at": "2026-07-20T00:15:00Z"+  "released_at": "2026-07-20T00:30:00Z" }
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-1.9.15\ No newline at end of file+1.9.16\ No newline at end of file
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "1.9.15",+  "version": "1.9.16",   "description": "Drives a browser ALREADY on the machine \u2014 installed Chrome, else Microsoft Edge (every Windows PC ships with Edge) \u2014 launched with a FRESH isolated profile, so the common case has NO ~150 MB Chrome-for-Testing download and it never touches the user's real tabs/logins. Binds its local server to LOOPBACK (127.0.0.1) only, so no Windows Firewall 'allow Node through the firewall' prompt ever pops. Chrome for Testing is fetched only as a LAST RESORT if the machine has no Chromium browser at all. SPAWN-VERIFIED fallback: pup tries each detected browser (Chrome \u2192 Edge \u2192 CfT) and actually launches it, falling through to the next if one won't start (and handling browsers like Edge that relaunch onto another PID), so a corrupt/partial install never hard-fails an open. The browser that launches is cached as the default (persisted across restarts) so it isn't re-probed each time. On spawn the bridge SELF-WARMS: detects browsers + disk, and only if the box has no Chrome/Edge and no cached CfT does it background-fetch CfT so the first open is instant. browser_use pins a specific browser (chrome | edge | cft | auto); {browser:'chrome',install:true} downloads & installs REAL Google Chrome (user-scoped, no admin) on an Edge-only box. browser_readiness (READ-ONLY) reports which browser will be used + the full candidate list + the default + free disk. Every failure returns a specific errorCode + _hint (chrome_install_no_disk, chrome_download_network, chrome_install_permission, chrome_stable_not_detected, \u2026). Launches with FULL browser permissions by default for full debug (strictPermissions:true opts out). Headful automation: open/close windows+tabs, navigate, screenshot, eval JS, record. pup is a GENERIC, non-profile browser only \u2014 every session is a fresh isolated Chrome/Edge process, never the user's real signed-in browser; profile defaults to sessionId. To drive the user's REAL Chrome/Edge (their profile, cookies, SSO), use the Adom browser EXTENSION's nbrowser_* verbs \u2014 a separate bridge, not pup's job.",   "homepage": "https://wiki.adom.inc/adom/adom-desktop",   "author": "Adom Inc.",
src/server.js+27−9
@@ -1834,6 +1834,7 @@ async function setWikiAuthedState(session, sessionId, authed) {   }   if (!stamped) console.log(`[identity] "${sessionId}" icon re-stamp FAILED after retries — window title never matched`);   try { await registerPerSessionAumid(`${PUP_APP_ID}.${sessionId}`); } catch (e) {}+  try { await updateTabCountBadge(session, sessionId); } catch (e) {} // repaint favicon on the new plate colour   return true; } // v1.9.3 (AD #208 — desktop_set_window_jumplist, AD ≥1.9.139): give each WIKI pup window a@@ -2099,26 +2100,43 @@ async function applyAppOverlay(session, sessionId) {     let src = session._appIconB64 ? { b64: session._appIconB64, mime: session._appIconMime || 'image/png' } : null;     if (!src) src = await fetchPageFavicon(activePage);     if (!src || !src.b64) { session._appOverlay = false; return false; }-    let overlay = _appOverlayCache.get(sessionId + ':' + (src.href || 'explicit'));+    // v1.9.16 (John's idea, and the right one): the favicon KEEPS the overlay slot — we only+    // recolour the PLATE it sits on. Signed in to the Adom wiki -> green plate; everything else+    // -> the normal dark plate. You still see which site you're on AND the wiki login state, and+    // at 16px the plate is a far bigger colour target than any glyph tucked in the base icon.+    const plateAuthed = !!session._wikiAuthed && isAdomUrl((() => { try { return activePage.url(); } catch (e) { return null; } })());+    const plateFill = plateAuthed ? '#16a34a' : '#0b2325';+    const cacheKey = sessionId + ':' + (src.href || 'explicit') + ':' + (plateAuthed ? 'auth' : 'plain');+    let overlay = _appOverlayCache.get(cacheKey);     if (!overlay) {-      if (/x-icon|vnd\.microsoft\.icon/.test(src.mime) || (src.href || '').endsWith('.ico')) {+      let sharpMod = null;+      try { sharpMod = require('sharp'); } catch (e) { sharpMod = null; }+      const isIco = /x-icon|vnd\.microsoft\.icon/.test(src.mime) || (src.href || '').endsWith('.ico');+      if (isIco && !plateAuthed) {         overlay = src.b64; // AD accepts ico base64 directly; no compositing possible (sharp can't read ico)+      } else if (!sharpMod) {+        overlay = src.b64;       } else {-        let sharpMod = null;-        try { sharpMod = require('sharp'); } catch (e) { return false; }         try {-          const iconPng = await sharpMod(Buffer.from(src.b64, 'base64')).resize(22, 22, { fit: 'inside' }).png().toBuffer();-          const plate = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect x="0" y="0" width="32" height="32" rx="8" fill="#0b2325" fill-opacity="0.92"/></svg>`);-          overlay = (await sharpMod(plate).resize(32, 32).composite([{ input: iconPng, gravity: 'centre' }]).png().toBuffer()).toString('base64');+          // .ico can't be decoded by sharp — when we NEED the green plate, fall back to drawing+          // the plate alone rather than losing the signal entirely.+          let iconPng = null;+          if (!isIco) {+            try { iconPng = await sharpMod(Buffer.from(src.b64, 'base64')).resize(22, 22, { fit: 'inside' }).png().toBuffer(); } catch (e) { iconPng = null; }+          }+          const plate = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect x="0" y="0" width="32" height="32" rx="8" fill="${plateFill}" fill-opacity="${plateAuthed ? '1' : '0.92'}"/></svg>`);+          let img = sharpMod(plate).resize(32, 32);+          if (iconPng) img = img.composite([{ input: iconPng, gravity: 'centre' }]);+          overlay = (await img.png().toBuffer()).toString('base64');         } catch (e) { return false; }       }-      _appOverlayCache.set(sessionId + ':' + (src.href || 'explicit'), overlay);+      _appOverlayCache.set(cacheKey, overlay);     }     const tabs = (session.tabs || []).length;     const nm = session._appName ? `${session._appName} — ` : '';     await chrome.adCommand('desktop_taskbar', {       titleContains: `(session: ${sessionId}`,-      overlay: { icon: overlay, tooltip: `Adom Pup — ${nm}${tabs} tab${tabs === 1 ? '' : 's'}${tabs > 1 ? ' (icon = active tab)' : ''}` },+      overlay: { icon: overlay, tooltip: `Adom Pup — ${nm}${plateAuthed ? 'Adom wiki: SIGNED IN · ' : ''}${tabs} tab${tabs === 1 ? '' : 's'}${tabs > 1 ? ' (icon = active tab)' : ''}` },     }, { timeoutMs: 5000 });     session._appOverlay = true;     return true;