← Commit history

The PowerShell deletion on ab 2.0.16 native verbs, closing the ab64 commitment: z-order, foreground reads, user-idle, window enumeration by pid and class, hwnd owner validation, parent-pid checks, send-to-back, lower-by-pid, and the taskbar attention clear are all precompiled-Rust ab calls now (roughly 20ms each versus 300ms runtime-compiled PowerShell spawns), the EnumWindows resolver and its temp-file EBUSY class are gone, the zero-caller osMinimizeToBackground and osBackgroundWatchdog are deleted, the synchronous PowerShell runner itself is deleted with zero callers remaining, internal identifiers adCommand and adPayload renamed to abCommand and abPayload, and the user-foreground doctrine got the fix John's question exposed: an ever-user-raised window stays hands-off for as long as it remains OS-foreground with no ten-minute clock, the recency window only applies once the user has left. Five scripts remain by design: the focus-raise dance x3 (works today, wishlisted for a native raise verb), base-icon extraction, and the credential import scan, all async-only

John Lauer ·269fb9148c ·2mo ago ·parent 070a50b
5 files changed +208−788
adom-bridge-puppeteer-manifest.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "puppeteer",-  "version": "2.0.26",-  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.26/adom-bridge-puppeteer-v2.0.26.zip",-  "sha256": "acad3b410632ca82dbfb7d5cf5c0ced7b44583067595f64d4105154e55691e8a",-  "size": 648278,+  "version": "2.0.27",+  "url": "https://wiki.adom.inc/download/adom/pup-bridge/2.0.27/adom-bridge-puppeteer-v2.0.27.zip",+  "sha256": "198a7e9f77df2291bb7863ec316afce2fde5d43ff472e4e433b6069af355d2d2",+  "size": 639100,   "verbPrefixes": [     "browser_",     "desktop_recorder_",
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-2.0.26+2.0.27
src/bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "puppeteer",   "displayName": "Puppeteer (Chrome for Testing + Native)",-  "version": "2.0.26",+  "version": "2.0.27",   "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. pup_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. pup_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. macOS (v1.9.74+): full parity with mac-native mechanics \u2014 background-by-default is the app-level hide (windows stay drivable/screenshottable while hidden), raise/lower map to unhide+activate/hide, pup_alert_window posts a native toast whose click focuses the window, pup_use {browser:'chrome',install:true} installs Chrome from the official dmg, and taskbar identity/badging remains Windows-only.",   "homepage": "https://wiki.adom.inc/adom/adom-bridge",   "author": "Adom Inc.",
src/chrome.js+7−7
@@ -546,7 +546,7 @@ function _resolveAdApiBase() {     // v1.9.75: ADOM_DIRECT_API_URL is NOT always AD. An HD-spawned bridge gets that env     // pointed at HD's control API (127.0.0.1:47084), which does not serve notify_user etc.     // So the env is a CANDIDATE, not the answer: _adApiCandidates() lists env → port-file →-    // default, and adCommand verifies the picked base actually serves the verb surface+    // default, and abCommand verifies the picked base actually serves the verb surface     // (via _probeAdNotifyCap-style /commands checks) before trusting it. Here we keep the     // historical single-pick for callers that just need "a base": env first, then the     // ~/.adom/direct-api-port file AD writes, then the documented default.@@ -622,7 +622,7 @@ async function _resolveVerifiedAdBase() { // identity when acting on its own behalf (our timers, sweeps and health polls pass no caller, so they // read honestly as pup's own work). All of it is self-reported and authorizes nothing. const AD_DELEGATE_NAME = 'pup';-function adCommand(command, args, opts = {}) {+function abCommand(command, args, opts = {}) {   let { target, timeoutMs = 8000, noToken = false, caller = null } = opts;   // #350: accept a bare thread string (opts.callerThread/Container/Reason) as shorthand for opts.caller,   // so a handler holding only _callerThread can attribute a callback without building an object. The@@ -674,7 +674,7 @@ function adCommand(command, args, opts = {}) {         (resp) => {           let d = ''; resp.on('data', c => d += c);           resp.on('end', () => {-            if (resp.statusCode === 403 && tok && !noToken) return resolve(adCommand(command, args, { ...opts, noToken: true }));+            if (resp.statusCode === 403 && tok && !noToken) return resolve(abCommand(command, args, { ...opts, noToken: true }));             try { resolve(JSON.parse(d)); } catch { resolve(null); }           });         }@@ -718,14 +718,14 @@ async function _probeAdNotifyCap() {   } catch {}   return _adNotifyCap; }-const adNotify = (args, target) => adCommand('notify_user', args, { target });-const adNotifyResponse = (id) => adCommand('notify_response', { id });+const adNotify = (args, target) => abCommand('notify_user', args, { target });+const adNotifyResponse = (id) => abCommand('notify_response', { id }); // Peer ADs on the same relay (OTHER machines the user might be sitting at). [] if none/old // AD. The direct-API `targets` returns {clients:[…]} and INCLUDES self, so we exclude our // own hostname/clientName. (Shape-tolerant: also accepts targets/data.* for other builds.) async function adPeerNames() {   try {-    const r = await adCommand('targets', {});+    const r = await abCommand('targets', {});     const list = (r && (r.clients || r.targets || (r.data && (r.data.clients || r.data.targets)))) || [];     let self = ''; try { self = String(os.hostname() || '').toLowerCase(); } catch {}     const names = list.map(t => t && (t.clientName || t.name || t.hostname)).filter(Boolean)@@ -1020,5 +1020,5 @@ module.exports = {   installChrome, ensureChromeReady, readiness, expectedBuildId, cacheDir, diskFreeMb,   setDefaultBrowser, readDefault, clearDefault, markVerified, pickSummary,   installChromeStable, chromeStableStatus, warmup,-  adCommand, // v1.8.40: reused by server.js to call AD verbs (e.g. desktop_taskbar) via the direct-API+  abCommand, // v1.8.40: reused by server.js to call AD verbs (e.g. desktop_taskbar) via the direct-API };
src/server.js+195−775
@@ -43,18 +43,10 @@ console.log = (...args) => { // you just burn a doomed process spawn on every call, forever. Guarding the primitive // instead of trusting every future caller is the same defense-in-depth as making a // module import-safe under the wrong interpreter: you don't own who calls you next.-// v2.0.23 (John): DO NOT ADD CALLERS. Synchronous PowerShell blocks the event loop (starved ab's-// health probe, got live bridges reaped — ab#61). All 7 former callers are async now; this stays-// only until ab ships the native window verbs and pup's PowerShell is deleted outright.-function runPsHidden(scriptPath, { timeout = 6000 } = {}) {-  if (process.platform !== 'win32') return '';-  return execFileSync('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-WindowStyle', 'Hidden', '-File', scriptPath], { encoding: 'utf8', timeout, windowsHide: true });-}+// v2.0.27: the SYNCHRONOUS PowerShell runner is DELETED — zero callers remain. Window+// management is native ab verbs now; the few remaining scripts (focus-raise dance, base-icon+// extraction, credential import scan) run through the ASYNC runner only. // Fire-and-forget async variant (never blocks the driving verb).-function runPsHiddenAsync(scriptPath, { timeout = 6000 } = {}) {-  if (process.platform !== 'win32') return;-  execFile('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-WindowStyle', 'Hidden', '-File', scriptPath], { timeout, windowsHide: true }, () => {});-} // Promise variant: resolves with stdout (trimmed) or '' on error. For PS whose RESULT matters // but which must not block the event loop (e.g. the background watchdog). function runPsHiddenPromise(scriptPath, { timeout = 8000 } = {}) {@@ -2168,7 +2160,7 @@ async function ensureSafeForNativeInput(sessionId, { reason = 'drive the window   }   // Warn BEFORE asking for the screen, and say the quiet part out loud: hands off the keyboard.   const msg = `Adom needs your "${sessionId}" window in front to ${reason}. Please DON'T type or click until I say done.`;-  try { await chrome.adCommand('notify_user', { title: 'Adom needs the keyboard', body: msg }, { timeoutMs: 5000 }); } catch (e) {}+  try { await chrome.abCommand('notify_user', { title: 'Adom needs the keyboard', body: msg }, { timeoutMs: 5000 }); } catch (e) {}   try { await pupCaption(msg, 15000, 'pup-native-guard'); } catch (e) {}   const ready = await waitForUserReady(sessionId, hwnd, { maxMs: 60000 });   if (!ready) {@@ -2200,7 +2192,7 @@ async function pupCaption(text, expiresInMs = PUP_CAPTION_MAX_MS, id = 'pup-assi   // clamp NEVER REACHED AD: current AD's desktop_caption takes `duration`, pup sent `expiresInMs`   // (an older AD spelling), so AD ignored it and used its 30s default. Send BOTH names so every AD   // build honors its own; the clamp finally bites.-  try { await chrome.adCommand('desktop_caption', { text, duration: expiresInMs, expiresInMs, id, position: 'bottom', size: 'medium' }, { timeoutMs: 4000 }); } catch (e) {}+  try { await chrome.abCommand('desktop_caption', { text, duration: expiresInMs, expiresInMs, id, position: 'bottom', size: 'medium' }, { timeoutMs: 4000 }); } catch (e) {} } async function sessionHwnd(sessionId) {   // v1.9.212: prefer the STORED handle — a title lookup cannot find a PDF-viewer window at all.@@ -2210,7 +2202,7 @@ async function sessionHwnd(sessionId) {     if (_s) { const h = await resolveSessionHwndByBounds(_s, sessionId); if (h) return h; }   } catch (e) {}   try {-    const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000, caller: sessionCaller(sessions.get(sessionId)) }));+    const fw = abPayload(await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000, caller: sessionCaller(sessions.get(sessionId)) }));     const b = fw && (fw.best || (fw.data && fw.data.best));     return b && (b.hwnd != null ? Number(b.hwnd) : null);   } catch (e) { return null; }@@ -2749,74 +2741,50 @@ function browserPickReport() { // drives it invisibly and only an explicit request ever brings it forward. Scoped to THIS // session's Chrome pid (+ its child chrome/msedge processes) so it never touches the // user's real browser windows. Windows-only; no-op elsewhere.-function osSendWindowToBack(profileName) {+async function osSendWindowToBack(profileName) {+  // v2.0.27: native + async (was a SYNC PowerShell that blocked the event loop and was MISSED by the+  // 2.0.23 sweep — its variable was named psScript, not scriptPath; the honest census found it).   if (process.platform !== 'win32') return false;   const be = browsers.get(profileName);   const pid = (be && be.browser && (be.browser._detachedPid || (be.browser.process() && be.browser.process().pid))) || null;   if (!pid) return false;   try {-    const psScript = path.join(require('os').tmpdir(), `_adom_bg_${pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public class WinBg { [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x, int y, int cx, int cy, uint f); }',-      '"@',-      `$targetPid = ${pid}`,-      '$BOTTOM = [IntPtr]1',                 // HWND_BOTTOM-      '$F = 0x1 -bor 0x2 -bor 0x10',         // SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE-      'function Back($h){ if($h -ne [IntPtr]::Zero){ [WinBg]::SetWindowPos($h,$BOTTOM,0,0,0,0,$F) | Out-Null } }',-      '$p = Get-Process -Id $targetPid -ErrorAction SilentlyContinue',-      'if ($p -and $p.MainWindowHandle -ne 0) { Back $p.MainWindowHandle }',-      'Get-CimInstance Win32_Process -Filter "ParentProcessId=$targetPid" -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("chrome.exe","msedge.exe") } | ForEach-Object { $cp = Get-Process -Id $_.ProcessId -ErrorAction SilentlyContinue; if ($cp -and $cp.MainWindowHandle -ne 0) { Back $cp.MainWindowHandle } }',-      'Write-Output "bg"',-    ].join('\r\n');-    fs.writeFileSync(psScript, ps);-    runPsHidden(psScript);-    return true;+    const kids = new Set([Number(pid)]);+    try {+      const pd = abPayload(await chrome.abCommand('process_list', { nameFilter: 'chrome' }, { timeoutMs: 5000 }));+      for (const p of ((pd && pd.processes) || [])) if (Number(p.parentPid) === Number(pid)) kids.add(Number(p.pid));+    } catch (e) {}+    const rows = await enumChromeWidgetWindows();+    let sent = false;+    for (const r of rows) {+      if (!kids.has(r.pid)) continue;+      try {+        const d = abPayload(await chrome.abCommand('desktop_set_window_state', { hwnd: r.h, state: 'bottom', force: false }, { timeoutMs: 5000 }));+        if (d && (d.sentToBack || d.ok)) sent = true;+      } catch (e) {}+    }+    return sent;   } catch (e) { console.error(`[bg] send-to-back failed for "${profileName}": ${e.message}`); return false; } }  // v1.8.34: capture the user's CURRENT foreground window (decimal HWND string) right // before we launch a pup browser, so the backgrounder can hand keyboard focus back to it. async function osIdleMs() {-  // v1.9.292 (John: differentiate HIS taskbar click from a JS/Chrome raise). Windows records the-  // time of the last user input (keyboard/mouse). A taskbar click that raised a window = very recent-  // input; a programmatic raise = none. Returns ms since the last input, or null if unknown.+  // v1.9.292 (John: differentiate HIS taskbar click from a JS/Chrome raise). v2.0.27: native ab verb+  // (GetLastInputInfo in precompiled Rust, ~20ms) — no more runtime-compiled PowerShell.   if (process.platform !== 'win32') return null;   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_idle_${process.pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; }',-      'public class WinIdle {',-      '  [DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO p);',-      '  [DllImport("kernel32.dll")] public static extern uint GetTickCount();',-      '  public static long Idle() { var l = new LASTINPUTINFO(); l.cbSize = (uint)Marshal.SizeOf(l); if (!GetLastInputInfo(ref l)) return -1; return (long)(GetTickCount() - l.dwTime); }',-      '}',-      '"@',-      'Write-Output ([WinIdle]::Idle())',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 4000 }) || '').trim();-    const ms = Number(out);-    return Number.isFinite(ms) && ms >= 0 ? ms : null;+    const d = abPayload(await chrome.abCommand('desktop_user_idle_ms', {}, { timeoutMs: 4000 }));+    return (d && d.ok && Number.isFinite(Number(d.idleMs))) ? Number(d.idleMs) : null;   } catch (e) { return null; } } async function osGetForegroundWindow() {+  // v2.0.27: native (desktop_get_foreground). Returns the decimal hwnd as a STRING (legacy shape) or null.   if (process.platform !== 'win32') return null;   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_fg_${process.pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public class WinFgG { [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); }',-      '"@',-      'Write-Output ([int64][WinFgG]::GetForegroundWindow())',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 4000 })).trim();-    return out && out !== '0' ? out : null;+    const d = abPayload(await chrome.abCommand('desktop_get_foreground', {}, { timeoutMs: 4000 }));+    const h = d && Number(d.hwnd);+    return h ? String(h) : null;   } catch (e) { return null; } } @@ -2841,27 +2809,12 @@ async function pageSetLifecycleActive(page) { // Force a REAL activation of a window (AttachThreadInput + ALT-nudge + SetForegroundWindow) — the // user-input-equivalent activation that actually recomputes Chrome's occlusion, unlike a plain raise. async function forceActivateHwnd(hwnd) {+  // v2.0.27: native — desktop_bring_to_front does the AttachThreadInput + SetForegroundWindow dance+  // (foreground-lock bypass) in precompiled Rust; confirmed equivalent by the ab thread on ab#64.   if (process.platform !== 'win32' || !hwnd) return false;   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_act_${process.pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public class WinAct {',-      '  [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern void keybd_event(byte k, byte s, uint f, UIntPtr x);',-      '}',-      '"@',-      // The ALT-nudge: a real (harmless) modifier keypress releases Windows' foreground lock so-      // SetForegroundWindow performs a TRUE activation instead of a taskbar flash.-      '[WinAct]::keybd_event(0xA4,0,0,[UIntPtr]::Zero); [WinAct]::keybd_event(0xA4,0,2,[UIntPtr]::Zero)',-      `$h=[IntPtr]${Number(hwnd)}`,-      '[void][WinAct]::BringWindowToTop($h); [void][WinAct]::SetForegroundWindow($h)',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    await runPsHiddenPromise(scriptPath, { timeout: 4000 });-    return true;+    const d = abPayload(await chrome.abCommand('desktop_bring_to_front', { hwnd: Number(hwnd) }, { timeoutMs: 5000 }));+    return !!(d && (d.ok || d.success || d.broughtToFront));   } catch (e) { return false; } } @@ -2958,12 +2911,12 @@ async function unstickIfHiddenWhileFront(sessionId, session, fgHwnd, hwnd) {     }     _unstickClickAt.set(sessionId, Date.now());     try {-      const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 }));+      const fw = abPayload(await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 }));       const r = fw && (fw.best || (fw.data && fw.data.best)); const rect = r && r.rect;       if (rect && rect.width > 600) {         const cx = Math.round(rect.left + rect.width - 300);         const cy = Math.round(rect.top + 10);-        await chrome.adCommand('desktop_click', { x: cx, y: cy, reason: `unstick frame-frozen pup window "${sessionId}" (real activation click on empty tab strip)` }, { timeoutMs: 8000 });+        await chrome.abCommand('desktop_click', { x: cx, y: cy, reason: `unstick frame-frozen pup window "${sessionId}" (real activation click on empty tab strip)` }, { timeoutMs: 8000 });         await new Promise(r2 => setTimeout(r2, 1200));         try { vis = await withTimeout(tab.page.evaluate('document.visibilityState'), 1500, 'vis-probe'); } catch (e) {}       }@@ -3016,13 +2969,13 @@ function _verLt(a, b) { } async function probeAdVersion() {   try {-    const r = await chrome.adCommand('update_status', {}, { timeoutMs: 6000 });+    const r = await chrome.abCommand('update_status', {}, { timeoutMs: 6000 });     const raw = r && (typeof r.output === 'string' && r.output ? JSON.parse(r.output) : r.output || r);     const v = (raw && (raw.currentVersion || (raw.data && raw.data.currentVersion))) || (r && r.currentVersion) || null;     if (v) {       _adVersion = v;       _adRaiseGateBypassed = _verLt(v, '1.9.124');-      console.log(`[adver] AD ${v}${_adRaiseGateBypassed ? ' — WARNING: <1.9.124 intercepts raise, the foreground gate is BYPASSED on this box; recommend updating Adom Bridge' : ''}`);+      console.log(`[abver] AD ${v}${_adRaiseGateBypassed ? ' — WARNING: <1.9.124 intercepts raise, the foreground gate is BYPASSED on this box; recommend updating Adom Bridge' : ''}`);     }   } catch (e) {} }@@ -3345,7 +3298,7 @@ async function ensurePupIdentityRegistered() {   if (process.platform !== 'win32' || _identitySupported === false) return false;   if (_identityRegistered) return true;   try {-    const r = await chrome.adCommand('desktop_register_app_identity', {+    const r = await chrome.abCommand('desktop_register_app_identity', {       appId: PUP_APP_ID, displayName: PUP_DISPLAY_NAME, iconPath: pupIconPath(),       args: 'pup_open_window {"sessionId":"pinned","owner":"pinned-launch","url":"https://wiki.adom.inc"}',     }, { timeoutMs: 8000 });@@ -3504,7 +3457,7 @@ async function stampPupIdentity(sessionId, opts) {     // Title stays as a fallback only for a window we somehow have no hwnd for.     if (sess && !sess._hwnd) { try { await resolveSessionHwndByBounds(sess, sessionId); } catch (e) {} }     const _stampHwnd = (sess && sess._hwnd && await hwndBelongsToPup(sess._hwnd, sess)) ? sess._hwnd : null;-    const r = await chrome.adCommand('desktop_set_window_identity', {+    const r = await chrome.abCommand('desktop_set_window_identity', {       ...(_stampHwnd ? { hwnd: _stampHwnd } : {}),       titleContains: `(${TITLE_LABEL}: ${sessionId}`, cacheKey: `pup-${sessionId}-${cat}`,       appId, displayName: pupDisplayName(sessionId), iconPath: pupIconPath(sessionId),@@ -3594,7 +3547,7 @@ async function registerPupAumid(appId, sessionId) {   // not write it (see writeAumidIcon), and an AUMID with no icon is what paints white.   writeAumidIcon(appId, pupIconPath(sessionId));   try {-    const r = await chrome.adCommand('desktop_register_app_identity', {+    const r = await chrome.abCommand('desktop_register_app_identity', {       appId, displayName: pupDisplayName(sessionId), iconPath: pupIconPath(sessionId), shortcut: false,     }, { timeoutMs: 6000 });     const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || ''));@@ -3677,9 +3630,9 @@ async function unregisterPupAumid(appId) {   // category flip mints a new AUMID and orphans the old one's list). Explorer resolving a button   // against a pile of stale-but-present jump lists is part of the first-right-click "blip".   if (_jumplistSupported !== false) {-    try { await chrome.adCommand('desktop_set_window_jumplist', { appId, tasks: [] }, { timeoutMs: 5000 }); } catch (e) {}+    try { await chrome.abCommand('desktop_set_window_jumplist', { appId, tasks: [] }, { timeoutMs: 5000 }); } catch (e) {}   }-  try { await chrome.adCommand('desktop_unregister_app_identity', { appId }, { timeoutMs: 5000 }); } catch (e) {}+  try { await chrome.abCommand('desktop_unregister_app_identity', { appId }, { timeoutMs: 5000 }); } catch (e) {} } // v1.9.320 (John: "i turned OFF jump lists in settings but i still see them in the taskbar. did you // ralph test this at all?"). No — I only tested ON. Toggling OFF never CLEARED the already-committed@@ -3694,7 +3647,7 @@ async function refreshAllJumplists() {     try {       const appId = s._curAppId; if (!appId) continue;       if (off) {-        await chrome.adCommand('desktop_set_window_jumplist', { appId, tasks: [] }, { timeoutMs: 5000 });+        await chrome.abCommand('desktop_set_window_jumplist', { appId, tasks: [] }, { timeoutMs: 5000 });         s._wikiJumplistKey = undefined; s._jlFrozen = false;   // so a later re-enable re-commits from scratch         console.log(`[jumplist] "${sid}" CLEARED (jumpLists turned off)`);       } else {@@ -3822,7 +3775,7 @@ async function updateWikiJumplist(session, sessionId, opts) {   // identity, and a jump-list task is a real CLI command that pup composes. Without --ai-thread John's   // click on "Switch to logged-in view" was refused with caller_identity_required and silently did   // NOTHING. Same root cause as the un-branded windows, in the one call path I failed to enumerate:-  // I fixed the bridge's OUTBOUND calls (adCommand) and forgot the commands pup hands to WINDOWS.+  // I fixed the bridge's OUTBOUND calls (abCommand) and forgot the commands pup hands to WINDOWS.   // The thread name is honest here — a human clicked a taskbar menu, so that is who is asking, and it   // is what the user will recognise in their own Activity Log.   // v1.9.121 — identity goes in the JSON ARGS, never as a CLI flag. The taskbar tasks invoke the@@ -3910,7 +3863,7 @@ async function updateWikiJumplist(session, sessionId, opts) {   try {     const payload = { appId, tasks };     if (hwnd) { payload.hwnd = hwnd; payload.headerIcon = pupIconPath(sessionId); }-    const r = await chrome.adCommand('desktop_set_window_jumplist', payload, { timeoutMs: 6000 });+    const r = await chrome.abCommand('desktop_set_window_jumplist', payload, { timeoutMs: 6000 });     const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || ''));     if (_isUnknownVerb(r, raw)) { _jumplistSupported = false; session._wikiJumplistKey = _prevJlKey; return; }     _jumplistSupported = true;@@ -4016,7 +3969,7 @@ async function setSessionProgress(sessionId, busy) {   } catch (e) {}   if (process.platform !== 'win32') return;   try {-    await chrome.adCommand('desktop_taskbar', {+    await chrome.abCommand('desktop_taskbar', {       ...(await windowTarget(sessions.get(sessionId), sessionId)),       progress: busy ? { state: 'indeterminate' } : { state: 'none' },     }, { timeoutMs: 4000 });@@ -4051,7 +4004,7 @@ async function toastForeground(sessionId, reason) {     if (now - (_fgToastAt.get(sessionId) || 0) < 4000) return;   // debounce a burst     _fgToastAt.set(sessionId, now);     const body = reason ? String(reason).slice(0, 140) : 'Adom opened a window on your screen.';-    await chrome.adCommand('notify_user', { title: 'Adom is showing you a window', body, focus: false }, { timeoutMs: 4000 });+    await chrome.abCommand('notify_user', { title: 'Adom is showing you a window', body, focus: false }, { timeoutMs: 4000 });   } catch (e) {} } function markSessionBusy(sessionId) {@@ -4158,7 +4111,7 @@ function buildThumbnailTooltip(session, sessionId) {   return lines.join('\n'); } // v1.9.104 — the caller to attribute a session-scoped AD callback to: the thread that OWNS this-// window (falling back to whoever last drove it). Returned as an adCommand opt so AD can render+// window (falling back to whoever last drove it). Returned as an abCommand opt so AD can render // "<thread> (via pup)" on the Activity Log + any approval prompt. Returns null for work that is // genuinely pup's own (timers, sweeps) — per the contract we must NOT forward a stale identity there. function sessionCaller(session) {@@ -4175,7 +4128,7 @@ async function updateThumbnailTooltip(session, sessionId) {   const tip = buildThumbnailTooltip(session, sessionId);   if (session._thumbTip === tip) return;   // idempotent: only push real changes   try {-    const r = await chrome.adCommand('desktop_taskbar', {+    const r = await chrome.abCommand('desktop_taskbar', {       ...(await windowTarget(sessions.get(sessionId), sessionId)), thumbnailTooltip: tip,     }, { timeoutMs: 5000, caller: sessionCaller(session) });     const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || ''));@@ -4241,7 +4194,7 @@ async function updateTabCountBadge(session, sessionId) {         const args2 = icon           ? { ...(await windowTarget(sessions.get(sid2), sid2)), overlay: { icon, tooltip: `Adom Pup — ${wins} window${wins === 1 ? '' : 's'}, ${totalTabs} tab${totalTabs === 1 ? '' : 's'}` } }           : { ...(await windowTarget(sessions.get(sid2), sid2)), overlay: { badge: 'none' } };-        try { await chrome.adCommand('desktop_taskbar', args2, { timeoutMs: 5000 }); } catch (e) {}+        try { await chrome.abCommand('desktop_taskbar', args2, { timeoutMs: 5000 }); } catch (e) {}       }       return;     }@@ -4257,12 +4210,12 @@ async function updateTabCountBadge(session, sessionId) {       const icon = tabBadgeIcon(count);       if (!icon) return;       session._overlayDesc = `count:${count} (no favicon on the active tab, so the tab-count badge)`;-      await chrome.adCommand('desktop_taskbar', {+      await chrome.abCommand('desktop_taskbar', {         ...(await windowTarget(sessions.get(sessionId), sessionId)),         overlay: { icon, tooltip: `Adom Pup — ${count} tabs` },       }, { timeoutMs: 5000 });     } else {-      await chrome.adCommand('desktop_taskbar', {+      await chrome.abCommand('desktop_taskbar', {         ...(await windowTarget(sessions.get(sessionId), sessionId)),         overlay: { badge: 'none' },       }, { timeoutMs: 5000 });@@ -5105,7 +5058,7 @@ async function applyAppOverlay(session, sessionId) {       fs.writeFileSync(_dbgPath, Buffer.from(overlay, 'base64'));       console.log(`[overlay-debug] "${sessionId}" PAINT ${Buffer.from(overlay, 'base64').length}B -> ${_dbgPath} | src=${(src && src.href) || '?'} | hwnd=${session._hwnd || '(none, using title)'}`);     } catch (e) { console.log(`[overlay-debug] dump failed: ${e.message}`); }-    await chrome.adCommand('desktop_taskbar', {+    await chrome.abCommand('desktop_taskbar', {       hwnd: session._hwnd,       overlay: { icon: overlay, tooltip: _tooltip },     }, { timeoutMs: 5000 });@@ -5157,7 +5110,7 @@ async function wikiCaption(text, expiresInMs) {     // NOTE the arg is `expiresInMs` (NOT `duration`) — default 30000, max 600000.     // This replaced the in-page DOM toast: with a real OS surface available, pup should not be     // injecting elements into the user's page.-    const r = await chrome.adCommand('desktop_caption', {+    const r = await chrome.abCommand('desktop_caption', {       text, duration: Math.min(Number(expiresInMs) || 2000, 2000), expiresInMs: Math.min(Number(expiresInMs) || 2000, 2000), id: 'pup-wiki-view', position: 'bottom', size: 'medium',     }, { timeoutMs: 4000 });     const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || r || ''));@@ -5210,10 +5163,10 @@ async function osRaiseSessionWindow(session, sessionId, reason) {     // exactly: resolve THIS session's hwnd by its "(session: <id>)" title, then have AD foreground     // that specific hwnd. Precise, browser-agnostic, and no PID guessing.     try {-      const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))}));+      const fw = abPayload(await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))}));       const hwnd = fw && fw.best && fw.best.hwnd;       if (hwnd) {-        await chrome.adCommand('desktop_bring_to_front', { hwnd }, { timeoutMs: 6000 });+        await chrome.abCommand('desktop_bring_to_front', { hwnd }, { timeoutMs: 6000 });         console.log(`[foreground] "${sessionId}" raised by hwnd=${hwnd}`);       } else {         console.log(`[foreground] "${sessionId}" could not resolve an hwnd to raise`);@@ -5291,7 +5244,7 @@ async function osRaiseSessionWindow(session, sessionId, reason) { // pup assumed the wrapped shape, so a bare payload silently became "" and every field read as // undefined — that is why the drag-out drain saw ZERO events while a manual call saw dozens. This // has now bitten twice (desktop_caption, desktop_ui_events), so parse defensively, once, here.-function adPayload(r) {+function abPayload(r) {   if (!r || typeof r !== 'object') return null;   let raw = r.output;   if (raw === undefined || raw === null) {@@ -5316,7 +5269,7 @@ async function ensureWindowOpenedWatch() {     // restart used to subscribe again and never unsubscribe, leaking watches (seen live: w1..w4).     // Events land in ONE shared ring drained by seq, so any existing watch serves us fine.     try {-      const ep = adPayload(await chrome.adCommand('desktop_ui_events', { sinceSeq: 0, max: 1 }, { timeoutMs: 5000 }));+      const ep = abPayload(await chrome.abCommand('desktop_ui_events', { sinceSeq: 0, max: 1 }, { timeoutMs: 5000 }));       if (ep) {         const existing = ((ep.activeWatches) || []).find(w => w.event === 'window-opened' && w.scope === 'global');         if (existing && existing.watchId) {@@ -5326,7 +5279,7 @@ async function ensureWindowOpenedWatch() {         }       }     } catch (e) {}-    const r = await chrome.adCommand('desktop_ui_watch', { event: 'window-opened' }, { timeoutMs: 6000 });+    const r = await chrome.abCommand('desktop_ui_watch', { event: 'window-opened' }, { timeoutMs: 6000 });     const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || ''));     if (_isUnknownVerb(r, raw)) { _uiWatchSupported = false; return; }     const o = raw ? JSON.parse(raw) : {};@@ -5381,47 +5334,16 @@ function learnConfirmedPid(profileName, pid) {   } catch (e) {} } async function hwndOwnerPid(hwnd) {-  // v1.9.297 (John: "why is there no overlay on this taskbar icon?"): return the owner pid ONLY when-  // the handle is a REAL top-level Chrome browser FRAME — the window that owns the taskbar button —-  // not merely any window owned by the profile's Chrome process. Chrome spawns small same-process-  // utility/message HWNDs; one of those (handle 18, in John's case) got cached as a session's _hwnd.-  // The old pid-only check PASSED it forever (right process, wrong window), so hwndBelongsToPup never-  // rejected it, the overlay painted onto a non-taskbar window (invisible), and the enforcer just-  // re-composed the same dead badge in a loop — no overlay ever appeared. Requiring a top-level-  // visible Chrome_WidgetWin_1 frame rejects those handles and forces a proper re-resolve.+  // v1.9.297 semantics preserved natively (v2.0.27): the owner pid ONLY for a REAL top-level visible+  // Chrome browser frame. desktop_enum_windows enumerates top-level windows filtered by class, so a+  // child/utility HWND simply is not in the result — same rejection, zero PowerShell.   if (process.platform !== 'win32' || !hwnd) return null;   try {-    const sp = path.join(require('os').tmpdir(), `_adom_hpid_${process.pid}.ps1`);-    fs.writeFileSync(sp, [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text;',-      'public class HPid {',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetAncestor(IntPtr h, uint f);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int n);',-      '  [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern int GetWindowText(IntPtr h, StringBuilder s, int n); }',-      '"@',-      `$h = [IntPtr]${Number(hwnd)}`,-      'if (-not [HPid]::IsWindow($h)) { Write-Output "0|"; exit }',-      'if (-not [HPid]::IsWindowVisible($h)) { Write-Output "0|"; exit }',-      // Must be the ROOT window (GA_ROOT = 2) — utility/child HWNDs resolve to a different root.-      'if ([HPid]::GetAncestor($h, 2) -ne $h) { Write-Output "0|"; exit }',-      // Must be a Chrome browser frame — the class that carries the taskbar button.-      '$cn = New-Object System.Text.StringBuilder 64; [void][HPid]::GetClassName($h, $cn, 64)',-      'if ($cn.ToString() -ne "Chrome_WidgetWin_1") { Write-Output "0|"; exit }',-      '$p = 0; [void][HPid]::GetWindowThreadProcessId($h, [ref]$p)',-      // v1.9.350: also return the window TITLE — a pup window carries this session's unique-      // "(ai-thread: <sid>)" tag, which hwndBelongsToPup uses as a title anchor of ownership.-      '$tb = New-Object System.Text.StringBuilder 512; [void][HPid]::GetWindowText($h, $tb, 512)',-      'Write-Output ("" + $p + "|" + $tb.ToString())',-    ].join(String.fromCharCode(13, 10)));-    const out = (runPsHidden(sp, { timeout: 4000 }) || '').trim();-    const bar = out.indexOf('|');-    const pid = Number(bar >= 0 ? out.slice(0, bar) : out);-    const title = bar >= 0 ? out.slice(bar + 1).trim() : '';-    return Number.isFinite(pid) && pid > 0 ? { pid, title } : null;+    const d = abPayload(await chrome.abCommand('desktop_enum_windows', { className: 'Chrome_WidgetWin_1', includeOffscreen: true }, { timeoutMs: 6000 }));+    const row = ((d && d.windows) || []).find(w => Number(w.hwnd) === Number(hwnd));+    if (!row || row.visible === false) return null;+    const pid = Number(row.pid);+    return Number.isFinite(pid) && pid > 0 ? { pid, title: String(row.title || '') } : null;   } catch (e) { return null; } } // Confirm an hwnd is a LIVE window owned by a pup browser process. Used as the hard gate before any@@ -5439,9 +5361,10 @@ async function hwndBelongsToPup(hwnd, session) {   const own = pupBrowserPidSet(prof || undefined);   if (own.has(pid)) return true;   try {-    const sp = path.join(require('os').tmpdir(), `_adom_ppid_${process.pid}.ps1`);-    fs.writeFileSync(sp, `try { (Get-CimInstance Win32_Process -Filter "ProcessId=${pid}" -EA Stop).ParentProcessId } catch { 0 }`);-    const par = Number((runPsHidden(sp, { timeout: 4000 }) || '0').trim());+    // v2.0.27: parent pid natively via ab process_list (was a SYNC CIM PowerShell that blocked the loop)+    const pd = abPayload(await chrome.abCommand('process_list', { pidFilter: pid }, { timeoutMs: 5000 }));+    const row = ((pd && pd.processes) || []).find(p => Number(p.pid) === Number(pid));+    const par = row && Number(row.parentPid);     if (par && own.has(par)) { learnConfirmedPid(prof, pid); return true; }   } catch (e) {}   // v1.9.350 (John: "why does the taskbar pup icon have no overlay?"). The shared adom-you profile@@ -5466,43 +5389,17 @@ async function hwndBelongsToPup(hwnd, session) { // v1.9.304: enumerate every visible top-level Chrome browser frame with its owner pid + rect. Shared // by birth-time resolution (createPageInNewWindow) and the resolver. Returns [{h,pid,L,T,W,H}]. async function enumChromeWidgetWindows() {+  // v2.0.27: native (desktop_enum_windows, ab 2.0.16+) — the EnumWindows-by-class PS is gone. Keeps+  // the legacy row shape {h,pid,L,T,W,H}; includeOffscreen so a just-born window at -32000 resolves.   if (process.platform !== 'win32') return [];   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_enumcw_${process.pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text; using System.Collections.Generic;',-      'public class WEnum2 {',-      '  public delegate bool Proc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(Proc p, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int n);',-      '  public struct RECT { public int L, T, R, B; }',-      '  public static List<string> Find() {',-      '    var outp = new List<string>();',-      '    EnumWindows((h, l) => {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint pid; GetWindowThreadProcessId(h, out pid);',-      '      var cn = new StringBuilder(128); GetClassName(h, cn, 128);',-      '      if (cn.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r);',-      '      outp.Add(((long)h).ToString() + "," + pid + "," + r.L + "," + r.T + "," + (r.R - r.L) + "," + (r.B - r.T));',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return outp;',-      '  } }',-      '"@',-      '[WEnum2]::Find() | ForEach-Object { Write-Output $_ }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 9000 }) || '').trim();-    if (!out) return [];+    const d = abPayload(await chrome.abCommand('desktop_enum_windows', { className: 'Chrome_WidgetWin_1', includeOffscreen: true }, { timeoutMs: 8000 }));     const rows = [];-    for (const line of out.split(/\r?\n/)) {-      const p = line.split(',').map(Number);-      if (p[0] && Number.isFinite(p[4])) rows.push({ h: p[0], pid: p[1], L: p[2], T: p[3], W: p[4], H: p[5] });+    for (const w of ((d && d.windows) || [])) {+      if (w.visible === false) continue;+      const r = w.rect || [];+      const h = Number(w.hwnd);+      if (h && Number.isFinite(Number(r[2]))) rows.push({ h, pid: Number(w.pid), L: Number(r[0]), T: Number(r[1]), W: Number(r[2]) - Number(r[0]), H: Number(r[3]) - Number(r[1]) });     }     return rows;   } catch (e) { return []; }@@ -5571,7 +5468,7 @@ async function resolveSessionHwndByBounds(session, sessionId) {     // recycle yields >1), and we fall through to the wiggle — never guessing. This is what the earlier     // titleTag gate blocked: the resolver could see the tag but was told not to use it.     try {-      const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000, caller: sessionCaller(session) }));+      const fw = abPayload(await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000, caller: sessionCaller(session) }));       const cnt = fw && (fw.count != null ? fw.count : (fw.data && fw.data.count));       const b = fw && (fw.best || (fw.data && fw.data.best));       if (cnt === 1 && b && b.hwnd) { session._hwnd = Number(b.hwnd); persistSessionHwnd(sessionId, Number(b.hwnd)); console.log(`[hwnd] "${sessionId}" resolved by unique TITLE tag -> ${b.hwnd}`); return Number(b.hwnd); }@@ -5603,48 +5500,11 @@ async function resolveSessionHwndByBounds(session, sessionId) {     // the sole-window-of-a-profile check below — none of which touch window geometry. A window none of     // those can resolve is left BARE (no overlay), which is fine; mangling the user's window is not.     // markerW stays null, so the matching loop below is pure read-only geometry (no setWindowBounds).-    // v2.0.13 (John): UNIQUE temp file per invocation. This used a single `_adom_hwnd_<pid>.ps1`, so-    // two concurrent hwnd resolutions (e.g. the startup brandSweep touching several windows at once)-    // collided on the same path and threw `EBUSY: resource busy or locked`. On a shared-profile window-    // that never resolved (many wiggle-matches), the retry hammered that same file in a tight loop,-    // spamming EBUSY and burning CPU (John's laptop-load report). A per-call filename removes the race.-    const scriptPath = path.join(require('os').tmpdir(), `_adom_hwnd_${process.pid}_${Date.now().toString(36)}_${Math.floor(Math.random() * 1e6).toString(36)}.ps1`);-    // CSS bounds -> physical px via the DPI scale, then match a top-level window of ANY chrome.exe-    // in this profile's process tree by position (a small tolerance absorbs frame/DPI rounding).-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text; using System.Collections.Generic;',-      'public class WEnum {',-      '  public delegate bool Proc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(Proc p, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int n);',-      '  public struct RECT { public int L, T, R, B; }',-      '  public static List<string> Find() {',-      '    var outp = new List<string>();',-      '    EnumWindows((h, l) => {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint pid; GetWindowThreadProcessId(h, out pid);',-      '      var cn = new StringBuilder(128); GetClassName(h, cn, 128);',-      '      if (cn.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r);',-      '      outp.Add(((long)h).ToString() + "," + pid + "," + r.L + "," + r.T + "," + (r.R - r.L) + "," + (r.B - r.T));',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return outp;',-      '  } }',-      '"@',-      '[WEnum]::Find() | ForEach-Object { Write-Output $_ }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    // v2.0.13 (John): unique per-call filename (above) means we MUST clean it up or a persistent bridge-    // leaks a tiny .ps1 into tmpdir on every resolution. Unlink in finally regardless of outcome.-    let out = '';-    try { out = (await runPsHiddenPromise(scriptPath, { timeout: 9000 }) || '').trim(); }-    finally { try { fs.unlinkSync(scriptPath); } catch (e) {} }-    if (!out) return null;+    // v2.0.27: NATIVE enumeration (ab desktop_enum_windows) — the EnumWindows PowerShell, its+    // unique temp files, and the EBUSY class are all gone. Same read-only geometry doctrine as+    // v1.9.308 (the width-wiggle stays deleted; bare > wrong, forever).+    const rows = await enumChromeWidgetWindows();+    if (!rows.length) { if (_releaseWiggle) { try { _releaseWiggle(); } catch (e) {} } try { if (cdp) await cdp.detach(); } catch (e) {} return null; }     // Every chrome.exe under this profile counts (renderers have no windows, so PID may be the parent     // or a sibling in the tree — accept any, then disambiguate purely on geometry).     // v1.9.302: collect ALL matching windows and demand EXACTLY ONE. The old code broke on the first@@ -5652,8 +5512,7 @@ async function resolveSessionHwndByBounds(session, sessionId) {     // ours, so we LEAVE IT BARE rather than paint a wrong window (John's rule: bare > wrong, forever     // after the Edge-overlay incident). A bare window self-heals on the next resolve; a wrong one lies.     const matches = new Set();-    for (const line of out.split(/\r?\n/)) {-      const [h, , L, T, W, H] = line.split(',').map(Number);+    for (const { h, L, T, W } of rows) {       if (!h || !Number.isFinite(W)) continue;       for (const sc of [1, 1.25, 1.5, 1.75, 2]) {         if (markerW != null) {@@ -5674,7 +5533,7 @@ async function resolveSessionHwndByBounds(session, sessionId) {     // exactly ONE such window, that IS this session's window, maximized or not — no geometry guessing.     const _profPids = pupBrowserPidSet(session.profileName);     const _profWins = new Set();-    for (const line of out.split(/\r?\n/)) { const p = line.split(','); const h = Number(p[0]); const wpid = Number(p[1]); if (h && _profPids.has(wpid)) _profWins.add(h); }+    for (const r of rows) { if (r.h && _profPids.has(r.pid)) _profWins.add(r.h); }     let resolved = null, how = '';     if (matches.size === 1) { resolved = [...matches][0]; how = markerW != null ? 'unique-width wiggle' : 'window bounds'; }     else if (_profWins.size === 1) { resolved = [..._profWins][0]; how = 'sole window of profile process (wiggle-free)'; }@@ -5690,7 +5549,7 @@ async function resolveSessionHwndByBounds(session, sessionId) {     session._hwndFailStreak = (session._hwndFailStreak || 0) + 1;     if (session._hwndFailStreak >= 3) {       session._hwndBackoffUntil = Date.now() + 5 * 60000;-      console.log(`[hwnd] "${sessionId}" NOT resolved — ${_profWins.size} windows on this profile, ${matches.size} wiggle-matches; leaving bare + BACKING OFF resolution for 5 min (${session._hwndFailStreak} straight misses — stop hammering PowerShell for an answer that isn't changing)`);+      console.log(`[hwnd] "${sessionId}" NOT resolved — ${_profWins.size} windows on this profile, ${matches.size} wiggle-matches; leaving bare + BACKING OFF resolution for 5 min (${session._hwndFailStreak} straight misses — stop hammering enumeration for an answer that isn't changing)`);     } else {       console.log(`[hwnd] "${sessionId}" NOT resolved — ${_profWins.size} windows on this profile, ${matches.size} wiggle-matches; leaving bare rather than guessing`);     }@@ -6163,7 +6022,7 @@ async function drainWindowOpenedEvents() {   await ensureWindowOpenedWatch();   if (!_uiWatchId) { console.log('[drag] drain skipped: no watchId'); return; }   try {-    const data = adPayload(await chrome.adCommand('desktop_ui_events', { sinceSeq: _uiWatchSeq, max: 200 }, { timeoutMs: 6000 }));+    const data = abPayload(await chrome.abCommand('desktop_ui_events', { sinceSeq: _uiWatchSeq, max: 200 }, { timeoutMs: 6000 }));     if (!data) { console.log('[drag] drain: unparseable response'); return; }     const evs = data.events || [];     if (typeof data.nextSeq === 'number') _uiWatchSeq = data.nextSeq;@@ -6296,7 +6155,7 @@ async function badgePupTaskbar(sessionId) {   // when AD rejected/failed the call (e.g. window title not yet resolvable), the badge just   // silently never appeared and every later attempt was debounced away.   try {-    const r = await chrome.adCommand('desktop_taskbar', {+    const r = await chrome.abCommand('desktop_taskbar', {       ...(await windowTarget(sessions.get(sessionId), sessionId)),       overlay: { icon, tooltip: 'Adom pup — driven from the cloud' },     }, { timeoutMs: 6000 });@@ -6327,398 +6186,52 @@ async function badgePupTaskbar(sessionId) { // cdpPort (the browser's CDP debug port) resolves the real browser via its LISTENING // process — reliable across the launcher→browser pid relaunch that Edge/Chrome do. async function osBackgroundWindowByPid(pid, cdpPort, restoreHwnd, respectUser, targetHwnd) {-  if (process.platform !== 'win32' || (!pid && !cdpPort)) return 'error';-  try {-    const port = Number(cdpPort) || 0;-    const restore = (restoreHwnd && /^-?\d+$/.test(String(restoreHwnd))) ? String(restoreHwnd) : '0';-    const scriptPath = path.join(require('os').tmpdir(), `_adom_bgpid_${pid || port}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text;',-      'public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; }',-      'public class WinBgP {',-      '  public delegate bool EnumProc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int m);',-      '  public struct RECT { public int L; public int T; public int R; public int B; }',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);',-      '  [DllImport("kernel32.dll")] public static extern uint GetTickCount();',-      '  [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x, int y, int cx, int cy, uint f);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',-      '  [DllImport("user32.dll")] public static extern int GetSystemMetrics(int i);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint a, uint b, bool f);',-      '  [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);',-      '  [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();',-      // Find the REAL browser window for a set of pids: the largest VISIBLE top-level-      // Chrome_WidgetWin_1 window. MainWindowHandle returns a hidden helper on some boxes-      // (that was the "park silently fails, window stuck off-screen" bug) — enumerate instead.-      '  public static IntPtr BestWindow(int[] pids) {',-      '    IntPtr best = IntPtr.Zero; long bestArea = -1;',-      '    EnumWindows(delegate(IntPtr h, IntPtr l) {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint wp; GetWindowThreadProcessId(h, out wp);',-      '      bool m = false; foreach (int p in pids) { if ((uint)p == wp) { m = true; break; } }',-      '      if (!m) return true;',-      '      StringBuilder sb = new StringBuilder(256); GetClassName(h, sb, 256);',-      '      if (sb.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r); long a = (long)(r.R - r.L) * (r.B - r.T);',-      '      if (a > bestArea) { bestArea = a; best = h; }',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return best;',-      '  }',-      '}',-      '"@',-      `$targetPid = ${Number(pid) || 0}`,-      `$cdpPort = ${port}`,-      `$restore = [IntPtr]${restore}`,-      '$BOTTOM = [IntPtr]1',                 // HWND_BOTTOM-      '$SWP = 0x10',                          // SWP_NOACTIVATE (allow move+size)-      'Add-Type -AssemblyName System.Windows.Forms',   // v1.9.136 (John): WORK AREA, not raw resolution — taskbar-aware on any edge-      '$wa = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',-      '$waX = $wa.X + 10', '$waY = $wa.Y + 10',   // v1.9.137 (John): 10px inset on ALL sides — visible proof the placement is deliberate-      '$scrW = $wa.Width - 20', // SM_CXSCREEN (primary monitor)-      '$scrH = $wa.Height - 20',-      '$pidList = New-Object System.Collections.ArrayList',-      'if ($targetPid -ne 0) { [void]$pidList.Add([int]$targetPid) }',-      // The process LISTENING on the CDP port is unambiguously the real browser.-      'if ($cdpPort -ne 0) { try { $own = Get-NetTCPConnection -LocalPort $cdpPort -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess; if ($own) { [void]$pidList.Add([int]$own) } } catch {} }',-      // Include child chrome/msedge pids — the real top-level window may belong to a child.-      '$anchors = @($pidList.ToArray())',-      'foreach ($tp in $anchors) { Get-CimInstance Win32_Process -Filter "ParentProcessId=$tp" -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("chrome.exe","msedge.exe") } | ForEach-Object { [void]$pidList.Add([int]$_.ProcessId) } }',-      // Resolve the ONE real browser window (largest visible Chrome_WidgetWin_1), not a helper.-      // v1.9.253 (the adom-theme disruption): BestWindow = "largest visible window of the process"-      // picked the WRONG window whenever the shared profile had several - the background call then-      // claimed success while the actual new window kept its creation focus. When the caller knows-      // the session's own hwnd, use it; BestWindow only as the no-hwnd fallback.-      `$explicit = [IntPtr]${Number(targetHwnd) || 0}`,-      '$pup = if ($explicit -ne [IntPtr]::Zero) { $explicit } else { [WinBgP]::BestWindow([int[]]@($pidList.ToArray())) }',-      'if ($pup -eq [IntPtr]::Zero) { Write-Output "no-window"; exit }',-      // respectUser (v1.8.49): used ONLY by LATE re-parks (post-resize etc.), never the launch-      // passes. Rationale: after startup, Chrome does NOT self-raise — so if the pup window is-      // foreground later, the USER took it (clicked its taskbar button). Leave it exactly as they-      // have it. NO input-timing heuristics: GetLastInputInfo measures input ANYWHERE on the-      // system, so "recent input" false-fires whenever the user is typing while a window opens —-      // that bug shipped in 1.8.44-48 and mis-shoved fresh windows into a small centered state.-      `$respectUser = ${respectUser ? 1 : 0}`,-      'if ($respectUser -eq 1) {',-      '  $fg0 = [WinBgP]::GetForegroundWindow()',-      '  if ($fg0 -eq $pup) { Write-Output "user-foreground"; exit }',-      '}',-      // ORDER MATTERS (v1.8.46): the browser grabbed the foreground on launch while it's still-      // OFF-SCREEN (invisible). Hand focus back to the user FIRST — deactivating the pup window-      // while it is off-screen — and ONLY THEN move it on-screen at z-bottom. If we moved it-      // on-screen first, it would flash visible on TOP for a moment (an active window stays-      // topmost until it is deactivated) = the "I saw the window open" pop. Deactivate, then park.-      // SetForegroundWindow is BLOCKED by the foreground lock, so use the AttachThreadInput trick:-      // attach the (current-foreground = pup) window's input thread to ours, SetForegroundWindow-      // the user's window, detach. This is what makes background-by-default NOT steal keystrokes.-      '$fg = [WinBgP]::GetForegroundWindow()',-      'if ($fg -eq $pup -and $restore -ne [IntPtr]::Zero) {',-      '  $procId = [uint32]0',-      '  $pupTid = [WinBgP]::GetWindowThreadProcessId($fg, [ref]$procId)',-      '  $myTid = [WinBgP]::GetCurrentThreadId()',-      '  [WinBgP]::AttachThreadInput($pupTid, $myTid, $true) | Out-Null',-      '  [WinBgP]::SetForegroundWindow($restore) | Out-Null',-      '  [WinBgP]::BringWindowToTop($restore) | Out-Null',-      '  [WinBgP]::AttachThreadInput($pupTid, $myTid, $false) | Out-Null',-      '}',-      // NOW pup is deactivated (still off-screen). Move it on-screen sized to the monitor at the-      // BOTTOM of the z-order (SWP_NOACTIVATE): fully behind the user's windows (invisible, never-      // covering) but reachable via its taskbar button. Because it is no longer the active-      // window, dropping it to HWND_BOTTOM keeps it hidden — no pop.-      '[WinBgP]::SetWindowPos($pup, $BOTTOM, $waX, $waY, $scrW, $scrH, $SWP) | Out-Null',-      // Re-verify: the user's window (not pup) should be foreground.-      '$fg2 = [WinBgP]::GetForegroundWindow()',-      'if ($fg2 -eq $pup) { Write-Output "still-foreground" } else { Write-Output "backgrounded" }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 6000 })).trim();-    return out || 'error';-  } catch (e) { console.error(`[bg] pid ${pid} port ${cdpPort}: ${e.message}`); return 'error'; }-}--// v1.8.50: THE background algorithm — ONE event-driven watchdog, no blind timers.-// Replaces the "park + re-park at 300/700/1200ms" kludge. What it does, in order:-//   1. WAIT for the real browser window to EXIST (poll EnumWindows @50ms, up to ~4s — reacting-//      to the event "window created", not guessing a delay). The window is OFF-SCREEN, invisible.-//   2. The moment it exists: hand keyboard focus back to the user's window (AttachThreadInput-//      dance — only if Chrome actually took the foreground), THEN move it on-screen at z-bottom-//      (deactivate-first order = no visible pop). ONE park.-//   3. STABILITY WATCH: for up to 2s, check the foreground @50ms. If Chrome re-grabs it-//      (startup self-raise), hand back + re-park INSTANTLY (50ms reaction, not a 400ms timer-//      gap). Exit as soon as the foreground has been non-pup for 500ms straight — typically-//      well under a second after first paint.-//   4. EXIT. After this process ends, NOTHING ever re-parks the window. A user click on the-//      taskbar button brings it up full-size and pup never touches it again. No input-timing-//      heuristics anywhere (GetLastInputInfo false-fired while the user typed — removed).-// Returns: 'backgrounded' | 'still-foreground' | 'no-window' | 'error' (self-verified).-async function osBackgroundWatchdog(pid, cdpPort, restoreHwnd) {-  if (process.platform !== 'win32' || (!pid && !cdpPort)) return 'error';-  try {-    const port = Number(cdpPort) || 0;-    const restore = (restoreHwnd && /^-?\d+$/.test(String(restoreHwnd))) ? String(restoreHwnd) : '0';-    const scriptPath = path.join(require('os').tmpdir(), `_adom_bgwd_${pid || port}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text;',-      'public class WinWd {',-      '  public delegate bool EnumProc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int m);',-      '  public struct RECT { public int L; public int T; public int R; public int B; }',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x, int y, int cx, int cy, uint f);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',-      '  [DllImport("user32.dll")] public static extern int GetSystemMetrics(int i);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint a, uint b, bool f);',-      '  [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);',-      '  [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();',-      '  public static IntPtr BestWindow(int[] pids) {',-      '    IntPtr best = IntPtr.Zero; long bestArea = -1;',-      '    EnumWindows(delegate(IntPtr h, IntPtr l) {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint wp; GetWindowThreadProcessId(h, out wp);',-      '      bool m = false; foreach (int p in pids) { if ((uint)p == wp) { m = true; break; } }',-      '      if (!m) return true;',-      '      StringBuilder sb = new StringBuilder(256); GetClassName(h, sb, 256);',-      '      if (sb.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r); long a = (long)(r.R - r.L) * (r.B - r.T);',-      '      if (a > bestArea) { bestArea = a; best = h; }',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return best;',-      '  }',-      '}',-      '"@',-      `$targetPid = ${Number(pid) || 0}`,-      `$cdpPort = ${port}`,-      `$restore = [IntPtr]${restore}`,-      '$BOTTOM = [IntPtr]1',-      '$SWP = 0x10',                            // SWP_NOACTIVATE-      'Add-Type -AssemblyName System.Windows.Forms',   // v1.9.136 (John): WORK AREA, not raw resolution — taskbar-aware on any edge-      '$wa = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',-      '$waX = $wa.X + 10', '$waY = $wa.Y + 10',   // v1.9.137 (John): 10px inset on ALL sides — visible proof the placement is deliberate-      '$scrW = $wa.Width - 20',-      '$scrH = $wa.Height - 20',-      '$myTid = [WinWd]::GetCurrentThreadId()',-      // Focus handback: only acts when pup IS the foreground (Chrome stole it); else a no-op.-      'function HandBack([IntPtr]$pup) {',-      '  $fg = [WinWd]::GetForegroundWindow()',-      '  if ($fg -eq $pup -and $restore -ne [IntPtr]::Zero) {',-      '    $procId = [uint32]0',-      '    $pupTid = [WinWd]::GetWindowThreadProcessId($fg, [ref]$procId)',-      '    [WinWd]::AttachThreadInput($pupTid, $myTid, $true) | Out-Null',-      '    [WinWd]::SetForegroundWindow($restore) | Out-Null',-      '    [WinWd]::BringWindowToTop($restore) | Out-Null',-      '    [WinWd]::AttachThreadInput($pupTid, $myTid, $false) | Out-Null',-      '  }',-      '}',-      // 1. Wait for the window to EXIST (the event, not a guessed delay). BestWindow (cheap-      //    EnumWindows) runs @50ms; the EXPENSIVE pid-list resolution (Get-NetTCPConnection +-      //    Get-CimInstance) refreshes only every ~500ms — running it every tick overran the-      //    process budget when several windows opened at once (the wiki3-4 'error').-      'function ResolvePids {',-      '  $l = New-Object System.Collections.ArrayList',-      '  if ($targetPid -ne 0) { [void]$l.Add([int]$targetPid) }',-      '  if ($cdpPort -ne 0) { try { $own = Get-NetTCPConnection -LocalPort $cdpPort -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess; if ($own) { [void]$l.Add([int]$own) } } catch {} }',-      '  $anchors = @($l.ToArray())',-      '  foreach ($tp in $anchors) { Get-CimInstance Win32_Process -Filter "ParentProcessId=$tp" -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("chrome.exe","msedge.exe") } | ForEach-Object { [void]$l.Add([int]$_.ProcessId) } }',-      '  return ,[int[]]@($l.ToArray())',-      '}',-      '$pup = [IntPtr]::Zero',-      '$pids = ResolvePids',-      '$deadline = [Environment]::TickCount + 4000',-      '$nextResolve = [Environment]::TickCount + 500',-      'while ([Environment]::TickCount -lt $deadline) {',-      '  $pup = [WinWd]::BestWindow($pids)',-      '  if ($pup -ne [IntPtr]::Zero) { break }',-      '  if ([Environment]::TickCount -ge $nextResolve) { $pids = ResolvePids; $nextResolve = [Environment]::TickCount + 500 }',-      '  Start-Sleep -Milliseconds 50',-      '}',-      'if ($pup -eq [IntPtr]::Zero) { Write-Output "no-window"; exit }',-      // 2. Park ONCE — with a user-click escape hatch that is now UNAMBIGUOUS: because-      //    --no-startup-window means Chrome cannot raise itself, "pup window is foreground"-      //    can only mean THE USER clicked its taskbar button during the launch gap (while the-      //    window was still at its off-screen coords, where activating it shows nothing). In-      //    that case: place it on-screen at the TOP full-size, keep the user's focus on it,-      //    and report user-foreground. Otherwise: single SetWindowPos to on-screen z-bottom.-      //    Park, verify, EXIT — nothing runs after this either way.-      '$fg1 = [WinWd]::GetForegroundWindow()',-      'if ($fg1 -eq $pup) {',-      '  [WinWd]::SetWindowPos($pup, [IntPtr]0, $waX, $waY, $scrW, $scrH, 0x40) | Out-Null', // HWND_TOP, SWP_SHOWWINDOW-      '  Write-Output "user-foreground"; exit',-      '}',-      'HandBack $pup',-      '[WinWd]::SetWindowPos($pup, $BOTTOM, $waX, $waY, $scrW, $scrH, $SWP) | Out-Null',-      // 3. Self-verify and exit. Nothing runs after this — the user owns the window now.-      '$fg2 = [WinWd]::GetForegroundWindow()',-      'if ($fg2 -eq $pup) { Write-Output "still-foreground" } else { Write-Output "backgrounded" }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = await runPsHiddenPromise(scriptPath, { timeout: 9000 });-    return out || 'error';-  } catch (e) { console.error(`[bgwd] pid ${pid} port ${cdpPort}: ${e.message}`); return 'error'; }-}--// v1.8.47: THE background primitive, rebuilt around MINIMIZE (replaces the on-screen-z-bottom-// park + its re-park retry loop, which fought the user's clicks). Why minimize is correct:-//  • Minimizing a foreground window hands the foreground back to the user's window AUTOMATICALLY-//    (no foreground-lock fight, no AttachThreadInput) — R4 (no focus steal) for free.-//  • We set the window's RESTORE rectangle on-screen (SetWindowPlacement rcNormalPosition), so a-//    taskbar click restores it centered + visible — and it STAYS, because there is NO re-park loop-//    to yank it back. This is exactly the user↔AI handoff John demanded.-//  • Screenshots keep working (R3) because Chrome launches with occlusion detection disabled-//    (--disable-features=CalculateNativeWinOcclusion + --disable-backgrounding-occluded-windows),-//    so a minimized window still composites frames for Page.captureScreenshot.-//  • No visible pop (R1): the window launched OFF-SCREEN, so minimizing it is never seen.-// respectUser (on the safety re-passes): if the window is NOT minimized and a real user input-// happened in the last ~1.5s, the USER restored it → return "user-foreground", do NOT re-minimize.-// Returns "minimized" | "user-foreground" | "still-foreground" | "no-window" | "error".-async function osMinimizeToBackground(pid, cdpPort, respectUser) {-  if (process.platform !== 'win32' || (!pid && !cdpPort)) return 'error';+  // v2.0.27: native. Resolve the pid tree's real frame (or use the caller's hwnd) and z-bottom it via+  // ab. respectUser maps to ab's force flag: an explicit lower verb may demote a foreground window+  // (deliberate user-requested action through the AI), a respectful one skips it. restoreHwnd/cdpPort+  // kept for signature compatibility; the native path never steals focus so there is nothing to restore.+  if (process.platform !== 'win32') return 'error';   try {-    const port = Number(cdpPort) || 0;-    const scriptPath = path.join(require('os').tmpdir(), `_adom_min_${pid || port}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text;',-      'public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; }',-      'public class WinMin {',-      '  public delegate bool EnumProc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int m);',-      '  public struct RECT { public int L; public int T; public int R; public int B; }',-      '  public struct POINT { public int X; public int Y; }',-      '  [StructLayout(LayoutKind.Sequential)] public struct WP { public int length; public int flags; public int showCmd; public POINT ptMin; public POINT ptMax; public RECT rc; }',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern bool GetWindowPlacement(IntPtr h, ref WP p);',-      '  [DllImport("user32.dll")] public static extern bool SetWindowPlacement(IntPtr h, ref WP p);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',-      '  [DllImport("user32.dll")] public static extern int GetSystemMetrics(int i);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);',-      '  [DllImport("kernel32.dll")] public static extern uint GetTickCount();',-      '  public static IntPtr BestWindow(int[] pids) {',-      '    IntPtr best = IntPtr.Zero; long bestArea = -1;',-      '    EnumWindows(delegate(IntPtr h, IntPtr l) {',-      '      if (!IsWindowVisible(h) && !IsIconic(h)) return true;',-      '      uint wp; GetWindowThreadProcessId(h, out wp);',-      '      bool m = false; foreach (int p in pids) { if ((uint)p == wp) { m = true; break; } }',-      '      if (!m) return true;',-      '      StringBuilder sb = new StringBuilder(256); GetClassName(h, sb, 256);',-      '      if (sb.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r); long a = (long)(r.R - r.L) * (r.B - r.T);',-      '      if (a > bestArea) { bestArea = a; best = h; }',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return best;',-      '  }',-      '}',-      '"@',-      `$targetPid = ${Number(pid) || 0}`,-      `$cdpPort = ${port}`,-      'Add-Type -AssemblyName System.Windows.Forms',   // v1.9.136 (John): WORK AREA, not raw resolution — taskbar-aware on any edge-      '$wa = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',-      '$waX = $wa.X + 10', '$waY = $wa.Y + 10',   // v1.9.137 (John): 10px inset on ALL sides — visible proof the placement is deliberate-      '$scrW = $wa.Width - 20',-      '$scrH = $wa.Height - 20',-      '$pidList = New-Object System.Collections.ArrayList',-      'if ($targetPid -ne 0) { [void]$pidList.Add([int]$targetPid) }',-      'if ($cdpPort -ne 0) { try { $own = Get-NetTCPConnection -LocalPort $cdpPort -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess; if ($own) { [void]$pidList.Add([int]$own) } } catch {} }',-      '$anchors = @($pidList.ToArray())',-      'foreach ($tp in $anchors) { Get-CimInstance Win32_Process -Filter "ParentProcessId=$tp" -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("chrome.exe","msedge.exe") } | ForEach-Object { [void]$pidList.Add([int]$_.ProcessId) } }',-      '$pup = [WinMin]::BestWindow([int[]]@($pidList.ToArray()))',-      'if ($pup -eq [IntPtr]::Zero) { Write-Output "no-window"; exit }',-      // Already minimized = already parked. Never re-touch it (that would fight a user who is-      // about to/just restored it). This is what makes the design not yank the window.-      'if ([WinMin]::IsIconic($pup)) { Write-Output "minimized"; exit }',-      `$respectUser = ${respectUser ? 1 : 0}`,-      'if ($respectUser -eq 1) {',-      '  $fg0 = [WinMin]::GetForegroundWindow()',-      '  if ($fg0 -eq $pup) {',-      '    $lii = New-Object LASTINPUTINFO',-      '    $lii.cbSize = [uint32][System.Runtime.InteropServices.Marshal]::SizeOf($lii)',-      '    [WinMin]::GetLastInputInfo([ref]$lii) | Out-Null',-      '    $idle = [WinMin]::GetTickCount() - $lii.dwTime',-      '    if ($idle -lt 1500) { Write-Output "user-foreground"; exit }',-      '  }',-      '}',-      // Minimize WITHOUT activating (SW_SHOWMINNOACTIVE=7) and set the RESTORE rect on-screen-      // (centered ~80%), so a taskbar click restores it visible. PowerShell can only mutate a-      // struct field on the top-level variable, so build RECT separately and assign the whole rc.-      '$wp = New-Object -TypeName "WinMin+WP"',-      '$wp.length = [int][System.Runtime.InteropServices.Marshal]::SizeOf($wp)',-      '[WinMin]::GetWindowPlacement($pup, [ref]$wp) | Out-Null',-      '$vw = [int]($scrW * 0.8); $vh = [int]($scrH * 0.8); $vx = [int](($scrW - $vw)/2); $vy = [int](($scrH - $vh)/2)',-      '$rc = New-Object -TypeName "WinMin+RECT"',-      '$rc.L = $vx; $rc.T = $vy; $rc.R = $vx + $vw; $rc.B = $vy + $vh',-      '$wp.showCmd = 7',-      '$wp.rc = $rc',-      '[WinMin]::SetWindowPlacement($pup, [ref]$wp) | Out-Null',-      '$fg2 = [WinMin]::GetForegroundWindow()',-      'if ($fg2 -eq $pup) { Write-Output "still-foreground" } else { Write-Output "minimized" }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 6000 })).trim();-    return out || 'error';-  } catch (e) { console.error(`[min] pid ${pid} port ${cdpPort}: ${e.message}`); return 'error'; }+    let target = Number(targetHwnd) || null;+    if (!target && pid) target = await largestChromeWindowOfPidTree(pid);+    if (!target) return 'no-window';+    const d = abPayload(await chrome.abCommand('desktop_set_window_state', { hwnd: Number(target), state: 'bottom', force: !respectUser }, { timeoutMs: 5000 }));+    return (d && (d.sentToBack || d.ok)) ? 'backgrounded' : 'error';+  } catch (e) { return 'error'; } } +// v2.0.27: osBackgroundWatchdog DELETED — zero callers (superseded by the park + re-assert+// doctrine in dev-skills/pup-user-foreground).+++// v2.0.27: osMinimizeToBackground DELETED — zero callers, and minimize-based backgrounding is+// banned by the pup-user-foreground doctrine (background means BEHIND, never hidden).++ // v1.8.53: send ONE hwnd to the bottom of the z-order. This is the ONLY Win32 call left with // no direct API (CDP has no z-order; AD has no send-to-back verb yet — issue filed). Minimal // PS: one P/Invoke signature, no window-finding, no pid guessing, hwnd comes from AD's native // desktop_find_window. Everything else in the park is CDP/AD direct.-async function osBottomUnlessForeground(hwnd, force) {+async function osBottomUnlessForeground(hwnd, force, sess) {+  // v2.0.27: NATIVE (was the last big PowerShell in the z-order path). Three ab calls at ~20ms each+  // replace one ~300ms runtime-compiled PS spawn, and the user-protection doctrine rides along:+  //  - not force: an OS-foreground target is left alone ('foreground').+  //  - force (Chrome self-raise override): a target that is OS-foreground AND was EVER user-raised+  //    stays hands-off for AS LONG AS it remains foreground (John 2026-08-09: "why do you need so+  //    long?" — the 10-min flag is only the memory horizon for after the user LEAVES the window;+  //    while they are on it, there is no clock). Fresh input (<5s) attributes a raise not yet+  //    flagged. A self-raised window with idle hands and no user history still gets demoted.   if (process.platform !== 'win32' || !hwnd) return 'error';   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_zbot_${hwnd}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices;',-      'public class ZBot {',-      '  [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x, int y, int cx, int cy, uint f);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',-      '  [StructLayout(LayoutKind.Sequential)] public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; }',-      '  [DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);',-      '}',-      '"@',-      // THE OS truth: GetForegroundWindow. (document.hasFocus() via CDP LIES for CDP-created-      // windows — it reports internal focus even when the OS never foregrounded them, which-      // false-fired 'user-foreground' on every open in the first 1.8.53 build.) With-      // --no-startup-window, OS-foreground == the user clicked; then do NOT bottom it.-      `$h = [IntPtr]${Number(hwnd)}`,-      `$force = ${force ? 1 : 0}`,-      'if ($force -eq 0 -and [ZBot]::GetForegroundWindow() -eq $h) { Write-Output "foreground"; exit }',-      // v2.0.26 (John clicked the taskbar button and pup yanked the window back down): force exists-      // for Chrome SELF-activations (the PDF-viewer pop), but it cannot tell a PDF pop from a USER-      // click — and the session-flag guards lag the click by seconds, so the +2.5s/+3s re-asserts-      // kept demoting a window the user had just raised. Discriminator: RECENT USER INPUT. A window-      // that is OS-foreground while the user's hands were active in the last 5s was raised by a-      // HUMAN — respect it even under force. A PDF self-pop happens with idle hands and still gets-      // demoted. Same script, zero extra process spawns.-      'if ($force -eq 1 -and [ZBot]::GetForegroundWindow() -eq $h) {',-      '  $lii = New-Object ZBot+LASTINPUTINFO; $lii.cbSize = [uint32][System.Runtime.InteropServices.Marshal]::SizeOf($lii)',-      '  if ([ZBot]::GetLastInputInfo([ref]$lii)) {',-      '    $idleMs = [uint32]([Environment]::TickCount - $lii.dwTime)',-      '    if ($idleMs -lt 5000) { Write-Output "user-foreground"; exit }',-      '  }',-      '}',-      '[ZBot]::SetWindowPos($h, [IntPtr]1, 0, 0, 0, 0, 0x13) | Out-Null', // HWND_BOTTOM; SWP_NOSIZE|NOMOVE|NOACTIVATE-      'Write-Output "bottomed"',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 5000 })).trim();-    return out || 'error';+    const fg = abPayload(await chrome.abCommand('desktop_get_foreground', {}, { timeoutMs: 4000 }));+    if (fg && Number(fg.hwnd) === Number(hwnd)) {+      if (!force) return 'foreground';+      if (sess && sess._userActiveAt) { sess._userActiveAt = Date.now(); return 'user-foreground'; }+      const idle = await osIdleMs();+      if (idle != null && idle < 5000) { if (sess) sess._userActiveAt = Date.now(); return 'user-foreground'; }+    }+    const d = abPayload(await chrome.abCommand('desktop_set_window_state', { hwnd: Number(hwnd), state: 'bottom', force: true }, { timeoutMs: 5000 }));+    return (d && (d.sentToBack || d.ok)) ? 'bottomed' : 'error';   } catch (e) { return 'error'; } } @@ -6936,7 +6449,7 @@ async function parkSessionWindowDirect(page, sessionId) {     // must not be topmost. Returns true only on CONFIRMED not-on-top.     const zConfirmedBelow = async (targetHwnd) => {       try {-        const r = await chrome.adCommand('desktop_list_windows', {}, { timeoutMs: 5000 });+        const r = await chrome.abCommand('desktop_list_windows', {}, { timeoutMs: 5000 });         const raw = r && (typeof r.output === 'string' && r.output ? JSON.parse(r.output) : r.output || r);         const ws = ((raw && (raw.data || raw)).windows) || [];         if (!ws.length) return false;@@ -6973,7 +6486,7 @@ async function parkSessionWindowDirect(page, sessionId) {         // At launch, foreground is NOT a user signal (post-restart reassignment), so pup always         // forces. On AD 1.9.114 the arg is ignored (skip-on-foreground) and the wasForeground         // fallback below covers it; that fallback auto-obsoletes as desktops update.-        const r = await chrome.adCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: true }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});+        const r = await chrome.abCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: true }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});         if (r && r.success === false) return { ok: false, err: r.error || 'error' };         const raw = r && (typeof r.output === 'string' ? r.output : JSON.stringify(r.output || ''));         const o = raw ? JSON.parse(raw) : {};@@ -6995,12 +6508,12 @@ async function parkSessionWindowDirect(page, sessionId) {       if (z.wasForeground || /invalid|unknown|must be one of|maximize\|minimize/i.test(lastErr)) {         let hwnd = null;         try {-          const r = await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 4000 , caller: sessionCaller(sessions.get(sessionId))});+          const r = await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 4000 , caller: sessionCaller(sessions.get(sessionId))});           const o = r && (typeof r.output === 'string' ? JSON.parse(r.output) : r.output || r);           hwnd = (o && ((o.best && o.best.hwnd) || o.hwnd)) || null;         } catch (e) {}         {-          const zr = hwnd ? await osBottomUnlessForeground(hwnd, true) : 'error';+          const zr = hwnd ? await osBottomUnlessForeground(hwnd, true, sessions.get(sessionId)) : 'error';           if (zr === 'bottomed') { bottomed = true; parkHwnd = hwnd; break; }           // v2.0.26: the user raised it while we were parking — respect it, remember it, stop parking.           if (zr === 'user-foreground') {@@ -7019,7 +6532,7 @@ async function parkSessionWindowDirect(page, sessionId) {     // On-screen full-size WITHOUT activation — AD MoveWindow preserves z-order (we're at bottom).     if (!parkHwnd) {       try {-        const r = await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 4000 , caller: sessionCaller(sessions.get(sessionId))});+        const r = await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 4000 , caller: sessionCaller(sessions.get(sessionId))});         const o = r && (typeof r.output === 'string' ? JSON.parse(r.output) : r.output || r);         parkHwnd = (o && ((o.best && o.best.hwnd) || o.hwnd)) || null;       } catch (e) {}@@ -7087,7 +6600,7 @@ async function reassertBottomAfterNav(sessionId) {   let bottomed = false;   try {     const hwnd = await cachedSessionHwnd(sessionId);-    const zr = hwnd ? await osBottomUnlessForeground(hwnd, true) : 'error';+    const zr = hwnd ? await osBottomUnlessForeground(hwnd, true, sessions.get(sessionId)) : 'error';     if (zr === 'bottomed') bottomed = true;     // v2.0.26 (John: "you took it back to the bg... that fights with the user"): a re-assert that     // finds the window user-foregrounded (recent input) STOPS — no retry, no ab fallback — and@@ -7105,7 +6618,7 @@ async function reassertBottomAfterNav(sessionId) {   try {     await new Promise(r => setTimeout(r, 1200));     const hwnd2 = await cachedSessionHwnd(sessionId);-    const zr2 = hwnd2 ? await osBottomUnlessForeground(hwnd2, true) : 'error';+    const zr2 = hwnd2 ? await osBottomUnlessForeground(hwnd2, true, sessions.get(sessionId)) : 'error';     if (zr2 === 'bottomed') {       console.log(`[park] "${sessionId}" (post-nav re-assert, retry): bottomed`);       return;@@ -7117,7 +6630,7 @@ async function reassertBottomAfterNav(sessionId) {     }   } catch (e) {}   try {-    await chrome.adCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: false }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});+    await chrome.abCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: false }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});   } catch (e) {} } @@ -7156,96 +6669,20 @@ async function healOffscreenWindow(session, sessionId) { // at z-bottom, then hand focus straight back to whatever the user was in (AttachThreadInput). // Net effect: the flash clears, nothing pops, focus is never stolen. Returns "cleared" / // "cleared-still-foreground" / "already-foreground" (user already had it) / "no-window".-async function osClearFlashByActivate(pid, cdpPort) {-  if (process.platform !== 'win32' || (!pid && !cdpPort)) return 'error';+async function osClearFlashByActivate(pid, cdpPort, hwnd) {+  // v2.0.27: native — ab desktop_clear_window_attention does the whole tint-clear dance in+  // precompiled Rust (FLASHW_STOP + AttachThreadInput activate + focus handback, net-zero focus;+  // pixel-verified on ab#64 after pup's FLASHW_STOP-alone caveat). The ~60-line PS is gone.+  if (process.platform !== 'win32' || (!pid && !cdpPort && !hwnd)) return 'error';   try {-    const port = Number(cdpPort) || 0;-    const scriptPath = path.join(require('os').tmpdir(), `_adom_clrflash_${pid || port}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text;',-      'public class WinClr {',-      '  public delegate bool EnumProc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int m);',-      '  public struct RECT { public int L; public int T; public int R; public int B; }',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x, int y, int cx, int cy, uint f);',-      '  [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',-      '  [DllImport("user32.dll")] public static extern int GetSystemMetrics(int i);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint a, uint b, bool f);',-      '  [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);',-      '  [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();',-      '  public static IntPtr BestWindow(int[] pids) {',-      '    IntPtr best = IntPtr.Zero; long bestArea = -1;',-      '    EnumWindows(delegate(IntPtr h, IntPtr l) {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint wp; GetWindowThreadProcessId(h, out wp);',-      '      bool m = false; foreach (int p in pids) { if ((uint)p == wp) { m = true; break; } }',-      '      if (!m) return true;',-      '      StringBuilder sb = new StringBuilder(256); GetClassName(h, sb, 256);',-      '      if (sb.ToString() != "Chrome_WidgetWin_1") return true;',-      '      RECT r; GetWindowRect(h, out r); long a = (long)(r.R - r.L) * (r.B - r.T);',-      '      if (a > bestArea) { bestArea = a; best = h; }',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return best;',-      '  }',-      '}',-      '"@',-      `$targetPid = ${Number(pid) || 0}`,-      `$cdpPort = ${port}`,-      '$BOTTOM = [IntPtr]1',                  // HWND_BOTTOM-      '$NOACT = 0x10',                         // SWP_NOACTIVATE-      'Add-Type -AssemblyName System.Windows.Forms',   // v1.9.136 (John): WORK AREA, not raw resolution — taskbar-aware on any edge-      '$wa = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',-      '$waX = $wa.X + 10', '$waY = $wa.Y + 10',   // v1.9.137 (John): 10px inset on ALL sides — visible proof the placement is deliberate-      '$scrW = $wa.Width - 20',-      '$scrH = $wa.Height - 20',-      '$pidList = New-Object System.Collections.ArrayList',-      'if ($targetPid -ne 0) { [void]$pidList.Add([int]$targetPid) }',-      'if ($cdpPort -ne 0) { try { $own = Get-NetTCPConnection -LocalPort $cdpPort -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess; if ($own) { [void]$pidList.Add([int]$own) } } catch {} }',-      '$anchors = @($pidList.ToArray())',-      'foreach ($tp in $anchors) { Get-CimInstance Win32_Process -Filter "ParentProcessId=$tp" -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @("chrome.exe","msedge.exe") } | ForEach-Object { [void]$pidList.Add([int]$_.ProcessId) } }',-      '$pup = [WinClr]::BestWindow([int[]]@($pidList.ToArray()))',-      'if ($pup -eq [IntPtr]::Zero) { Write-Output "no-window"; exit }',-      '$myTid = [WinClr]::GetCurrentThreadId()',-      // Snapshot the user's current foreground so we can restore it. If it's ALREADY the pup-      // window, the user has it up (flash is moot) — do nothing.-      '$userFg = [WinClr]::GetForegroundWindow()',-      'if ($userFg -eq $pup) { Write-Output "already-foreground"; exit }',-      // 1. Move the window OFF-SCREEN (invisible), without activating.-      '[WinClr]::SetWindowPos($pup, $BOTTOM, $waX, $waY, $scrW, $scrH, $NOACT) | Out-Null',   // v1.9.134 (John): on-screen, BOTTOM z, no-activate, FULL work-area size — background means BEHIND, not off-screen or tiny-      // 2. Activate the pup window off-screen → clears the taskbar attention tint. Bypass the-      //    foreground lock by attaching our input thread to the current foreground's thread.-      '$uProc = [uint32]0',-      '$uTid = [WinClr]::GetWindowThreadProcessId($userFg, [ref]$uProc)',-      '[WinClr]::AttachThreadInput($uTid, $myTid, $true) | Out-Null',-      '[WinClr]::SetForegroundWindow($pup) | Out-Null',-      '[WinClr]::BringWindowToTop($pup) | Out-Null',-      '[WinClr]::AttachThreadInput($uTid, $myTid, $false) | Out-Null',-      'Start-Sleep -Milliseconds 60',-      // 3. Park back on-screen at z-bottom (invisible behind the user's windows).-      '[WinClr]::SetWindowPos($pup, $BOTTOM, $waX, $waY, $scrW, $scrH, $NOACT) | Out-Null',-      // 4. Hand focus back to the user's window.-      '$pProc = [uint32]0',-      '$pTid = [WinClr]::GetWindowThreadProcessId($pup, [ref]$pProc)',-      '[WinClr]::AttachThreadInput($pTid, $myTid, $true) | Out-Null',-      '[WinClr]::SetForegroundWindow($userFg) | Out-Null',-      '[WinClr]::BringWindowToTop($userFg) | Out-Null',-      '[WinClr]::AttachThreadInput($pTid, $myTid, $false) | Out-Null',-      '$fg2 = [WinClr]::GetForegroundWindow()',-      '$stillPup = $false',-      'foreach($h in $handles){ if($h -eq $fg2){ $stillPup = $true } }',-      'if ($stillPup) { Write-Output "cleared-still-foreground" } else { Write-Output "cleared" }',-    ].join('\r\n');-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 6000 })).trim();-    return out || 'error';-  } catch (e) { console.error(`[clrflash] pid ${pid} port ${cdpPort}: ${e.message}`); return 'error'; }+    let target = Number(hwnd) || null;+    if (!target && pid) target = await largestChromeWindowOfPidTree(pid);+    if (!target) return 'no-window';+    const fg = abPayload(await chrome.abCommand('desktop_get_foreground', {}, { timeoutMs: 4000 }));+    if (fg && Number(fg.hwnd) === Number(target)) return 'already-foreground';+    const d = abPayload(await chrome.abCommand('desktop_clear_window_attention', { hwnd: Number(target) }, { timeoutMs: 8000 }));+    return (d && (d.cleared || d.ok)) ? 'cleared' : 'error';+  } catch (e) { return 'error'; } }  // NOTE: localhost-URL reprimand (container-vs-desktop) is handled by AD CORE, which@@ -7288,7 +6725,7 @@ async function flashViaAD(sessionId, opts) {   const tgt = _flashHwndOk ? { hwnd: session._hwnd } : { titleContains: `(${TITLE_LABEL}: ${sessionId}` };   if (!opts.stop && session && session._hwnd) _flashedHwnds.add(session._hwnd);   const args = opts.stop ? { ...tgt, stop: true } : { ...tgt, mode: 'count', count: 4 };-  try { return await chrome.adCommand('desktop_flash_window', args, { timeoutMs: 6000 }); }+  try { return await chrome.abCommand('desktop_flash_window', args, { timeoutMs: 6000 }); }   catch (e) { return null; } } const _flashedHwnds = new Set(); // every hwnd pup ever flashed this boot — the clear-all sweep list@@ -7300,7 +6737,28 @@ let _wiggleLock = Promise.resolve();   // v1.9.291: serialize wiggle resolves (e // on it: enumerate every visible top-level window of every pup-managed Chrome process (same PS enum // the badge resolver uses) and stop them ALL. Filtered to pup's own browser PIDs so the user's // personal Chrome is never touched.+// v2.0.27: the "which window carries this process's taskbar button" resolver, native. Largest+// visible real (>=80x60) Chrome frame owned by the pid or its direct chrome children.+async function largestChromeWindowOfPidTree(pid) {+  if (!pid) return null;+  const kids = new Set([Number(pid)]);+  try {+    const pd = abPayload(await chrome.abCommand('process_list', { nameFilter: 'chrome' }, { timeoutMs: 5000 }));+    for (const p of ((pd && pd.processes) || [])) if (Number(p.parentPid) === Number(pid)) kids.add(Number(p.pid));+  } catch (e) {}+  const rows = await enumChromeWidgetWindows();+  let best = null;+  for (const r of rows) {+    if (!kids.has(r.pid) || r.W < 80 || r.H < 60) continue;+    const area = r.W * r.H;+    if (!best || area > best.area) best = { h: r.h, area };+  }+  return best ? best.h : null;+}+ async function enumAllPupChromeHwnds() {+  // v2.0.27: native. The >=80x60 size filter survives (v1.9.273: every Chrome process carries a+  // hidden helper window that reports visible with no real size — the phantom "UNTRACKED" criers).   if (process.platform !== 'win32') return [];   const pupPids = new Set();   for (const [, be] of browsers) {@@ -7308,46 +6766,8 @@ async function enumAllPupChromeHwnds() {   }   if (!pupPids.size) return [];   try {-    const scriptPath = path.join(require('os').tmpdir(), `_adom_allhwnd_${process.pid}.ps1`);-    const ps = [-      'Add-Type @"',-      'using System; using System.Runtime.InteropServices; using System.Text; using System.Collections.Generic;',-      'public class WEnumF {',-      '  public delegate bool Proc(IntPtr h, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool EnumWindows(Proc p, IntPtr l);',-      '  [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);',-      '  [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);',-      '  [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int n);',-      '  public struct RECT { public int L, T, R, B; }',-      '  [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);',-      '  public static List<string> Find() {',-      '    var outp = new List<string>();',-      '    EnumWindows((h, l) => {',-      '      if (!IsWindowVisible(h)) return true;',-      '      uint pid; GetWindowThreadProcessId(h, out pid);',-      '      var cn = new StringBuilder(128); GetClassName(h, cn, 128);',-      '      if (cn.ToString() != "Chrome_WidgetWin_1") return true;',-      // v1.9.273: every Chrome process carries a hidden helper window that still reports visible;-      // it has no real size. Only REAL windows (>= 80x60) count, else the untracked detector cries-      // wolf with exactly one phantom per pup process (John saw "3 UNTRACKED" against 3 processes).-      '      RECT r; GetWindowRect(h, out r);',-      '      if ((r.R - r.L) < 80 || (r.B - r.T) < 60) return true;',-      '      outp.Add(((long)h).ToString() + "," + pid);',-      '      return true;',-      '    }, IntPtr.Zero);',-      '    return outp;',-      '  } }',-      '"@',-      '[WEnumF]::Find() | ForEach-Object { Write-Output $_ }',-    ].join(String.fromCharCode(13,10));-    fs.writeFileSync(scriptPath, ps);-    const out = (await runPsHiddenPromise(scriptPath, { timeout: 9000 }) || '').trim();-    const hwnds = [];-    for (const line of out.split(/\r?\n/)) {-      const [h, pid] = line.split(',').map(Number);-      if (h && pupPids.has(pid)) hwnds.push(h);-    }-    return hwnds;+    const rows = await enumChromeWidgetWindows();+    return rows.filter(r => pupPids.has(r.pid) && r.W >= 80 && r.H >= 60).map(r => r.h);   } catch (e) { return []; } } @@ -10217,7 +9637,7 @@ const server = http.createServer(async (req, res) => {         }         if (act === 'import-run') {           // AD >= 1.9.220 ships desktop_decrypt_pup_credentials (the SYSTEM-elevated ABE decrypt,-          // adom/adom-bridge #51). It MUST be called LOCALLY: chrome.adCommand routes over AD's+          // adom/adom-bridge #51). It MUST be called LOCALLY: chrome.abCommand routes over AD's           // direct API (127.0.0.1), which is exactly the loopback path AD requires — a relayed call is           // refused with errorCode:relay_forbidden and pops no UAC. AD fires its OWN consent dialog +           // UAC prompt (that IS the user's permission for the decrypt). Plaintext returns ONCE over@@ -10229,10 +9649,10 @@ const server = http.createServer(async (req, res) => {           console.log(`[import] decrypt requested for ${sel.length} profile(s) across ${browsers.join(', ')} — calling AD helper locally (consent + UAC will prompt on the desktop)`);           let resp;           try {-            resp = await chrome.adCommand('desktop_decrypt_pup_credentials',+            resp = await chrome.abCommand('desktop_decrypt_pup_credentials',               { browsers, include: ['passwords'] }, { timeoutMs: 180000 });           } catch (e) { return done({ ok: false, error: 'decrypt helper call failed: ' + (e && e.message || e) }); }-          const payload = adPayload(resp) || {};+          const payload = abPayload(resp) || {};           const ec = payload.errorCode || (resp && resp.errorCode);           if (ec) {             const emap = {@@ -10323,11 +9743,11 @@ const server = http.createServer(async (req, res) => {             const swept = new Set();             try {               for (const h of await enumAllPupChromeHwnds()) {-                try { await chrome.adCommand('desktop_flash_window', { hwnd: h, stop: true }, { timeoutMs: 6000 }); swept.add(h); } catch (e) {}+                try { await chrome.abCommand('desktop_flash_window', { hwnd: h, stop: true }, { timeoutMs: 6000 }); swept.add(h); } catch (e) {}               }             } catch (e) {}             for (const h of [..._flashedHwnds]) {-              if (!swept.has(h)) { try { await chrome.adCommand('desktop_flash_window', { hwnd: h, stop: true }, { timeoutMs: 6000 }); } catch (e) {} }+              if (!swept.has(h)) { try { await chrome.abCommand('desktop_flash_window', { hwnd: h, stop: true }, { timeoutMs: 6000 }); } catch (e) {} }               _flashedHwnds.delete(h);             }             console.log(`[flash] clear-all swept ${swept.size} enumerated pup Chrome windows + tracked set`);@@ -11154,7 +10574,7 @@ const server = http.createServer(async (req, res) => {           // force:false touches nothing but z, and respects a user-held window.           if (!foreground && sized) {             try {-              await chrome.adCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: false }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});+              await chrome.abCommand('desktop_set_window_state', { ...(await windowTarget(sessions.get(sessionId), sessionId)), state: 'bottom', force: false }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});             } catch (e) {}           }           // v1.8.26: record whether this window is meant to be on screen — gates every@@ -11565,7 +10985,7 @@ const server = http.createServer(async (req, res) => {           if (session._lastTakeoverBy) lines.push(`⚠ last takeover: by "${session._lastTakeoverBy}" ${_fmtAge(Math.round((Date.now() - (session._takenOverAt || Date.now())) / 60000))} ago`);           let captionShown = false;           try {-            const r = await chrome.adCommand('desktop_caption', {+            const r = await chrome.abCommand('desktop_caption', {               id: `pup-info-${sid}`, text: lines.join('\n'),               position: 'bottom', size: 'medium', duration: 12000,             }, { timeoutMs: 8000, caller: sessionCaller(session) });@@ -11841,7 +11261,7 @@ const server = http.createServer(async (req, res) => {           let _visible = false;           for (let i = 0; i < 8 && !_visible; i++) {             try {-              const fr = await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});+              const fr = await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))});               const fraw = fr && (typeof fr.output === 'string' ? fr.output : JSON.stringify(fr.output || ''));               const fo = fraw ? JSON.parse(fraw) : {};               _visible = !!((fo.data || fo).best);@@ -12088,13 +11508,13 @@ const server = http.createServer(async (req, res) => {               const toastId = `pup-alert-${sid}`;               let applied = false;               if (stop) {-                try { const r2 = await chrome.adCommand('notify_dismiss', { id: toastId }, { timeoutMs: 5000 }); applied = !!r2; } catch (e) {}+                try { const r2 = await chrome.abCommand('notify_dismiss', { id: toastId }, { timeoutMs: 5000 }); applied = !!r2; } catch (e) {}                 sendJSON(res, { success: true, output: JSON.stringify({ ok: true, sessionId, alerted: false, cleared: applied, applied, clearMethod: applied ? 'toast-dismissed' : null, _hint: applied ? 'Alert toast dismissed.' : 'No toast to dismiss (or Bridge unreachable).' }) });                 return;               }               try { await macSetAppHiddenByPid(macSessionPid(session), false); } catch (e) {}               try {-                const r2 = await chrome.adCommand('notify_user', {+                const r2 = await chrome.abCommand('notify_user', {                   id: toastId, level: 'info', scenario: 'reminder',                   title: 'A pup window wants your attention',                   body: `Session "${sid}" has something to show — click to bring it up.`,@@ -12117,7 +11537,7 @@ const server = http.createServer(async (req, res) => {             if (stop && process.platform === 'win32') {               try {                 const br = browsers.get(session.profileName) && browsers.get(session.profileName).browser;-                if (br && (br._detachedPid || br._cdpPort)) clearMethod = await osClearFlashByActivate(br._detachedPid, br._cdpPort);+                if (br && (br._detachedPid || br._cdpPort || session._hwnd)) clearMethod = await osClearFlashByActivate(br._detachedPid, br._cdpPort, session._hwnd);               } catch (e) {}               try { _flashState.delete(session._sessionId || sessionId); } catch (e) {}             }@@ -12155,7 +11575,7 @@ const server = http.createServer(async (req, res) => {             ok = await macSetAppHiddenByPid(macSessionPid(session), true);           } else {             if (!session._hwnd) { try { await resolveSessionHwndByBounds(session, sessionId); } catch (e) {} }-            ok = (be && be.browser) ? ((await osBackgroundWindowByPid(be.browser._detachedPid, be.browser._cdpPort, be.browser._priorForeground, false, session._hwnd)) === 'backgrounded') : osSendWindowToBack(session.profileName);+            ok = (be && be.browser) ? ((await osBackgroundWindowByPid(be.browser._detachedPid, be.browser._cdpPort, be.browser._priorForeground, false, session._hwnd)) === 'backgrounded') : await osSendWindowToBack(session.profileName);           }           session._foreground = false;           session._fgWatchUntil = 0;   // v1.9.260: a deliberate lower is not a "surfaced without pup" event - z-bottom keeps OS focus and the no-fault watch was mislabeling it@@ -12257,7 +11677,7 @@ const server = http.createServer(async (req, res) => {                 // raise resolves the SAME window regardless of what its title currently says.                 let hwnd = await sessionHwnd(sessionId);                 if (!hwnd) {-                  const fw = adPayload(await chrome.adCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))}));+                  const fw = abPayload(await chrome.abCommand('desktop_find_window', { titleContains: `(${TITLE_LABEL}: ${sessionId}` }, { timeoutMs: 5000 , caller: sessionCaller(sessions.get(sessionId))}));                   hwnd = fw && fw.best && fw.best.hwnd;                 }                 if (hwnd) {@@ -12280,7 +11700,7 @@ const server = http.createServer(async (req, res) => {                     `[WinFocusH]::Raise([IntPtr]${hwnd})`,                     "Write-Output 'focused'",                   ].join('\n'), 'utf8');-                  const out = runPsHidden(psPath, { timeout: 8000 });+                  const out = await runPsHiddenPromise(psPath, { timeout: 8000 });                   // v1.9.68: PS reports 'focused' even when Windows IGNORED the call. SetForegroundWindow is                   // subject to the FOREGROUND LOCK: a process that does not already own the foreground cannot                   // steal it, so it silently no-ops (measured: log said FOCUSED, screen unchanged). Use PS only@@ -12288,7 +11708,7 @@ const server = http.createServer(async (req, res) => {                   // which owns a foreground-capable path, do the real raise on the SAME hwnd.                   const _styleCleared = /focused/.test(out || '');                   try {-                    const br = adPayload(await chrome.adCommand('desktop_bring_to_front', { hwnd, state: 'restore' }, { timeoutMs: 6000 }));+                    const br = abPayload(await chrome.abCommand('desktop_bring_to_front', { hwnd, state: 'restore' }, { timeoutMs: 6000 }));                     _raisedByHwnd = !!(br && (br.ok === undefined || br.ok));                   } catch (e) { _raisedByHwnd = false; }                   console.log(`[foreground] "${sessionId}" hwnd=${hwnd} styleCleared=${_styleCleared} adRaise=${_raisedByHwnd}`);@@ -12337,7 +11757,7 @@ const server = http.createServer(async (req, res) => {               ].join('\r\n');               fs.writeFileSync(psScript, psContent);               try {-                const result = runPsHidden(psScript, { timeout: 8000 }).toString().trim();+                const result = (await runPsHiddenPromise(psScript, { timeout: 8000 })).toString().trim();                 console.log(`Focused session "${sessionId}" via SetForegroundWindow: ${result}`);               } catch (e) {                 console.error(`SetForegroundWindow failed for session "${sessionId}":`, e.message);@@ -12861,7 +12281,7 @@ const server = http.createServer(async (req, res) => {           const _label = String(args.label || 'the highlighted control').slice(0, 80);           try {             await pupCaption(`Adom: ${_reason} I will bring this window up and WAIT until you are ready before clicking ${_label}.`, 9000);-            try { await chrome.adCommand('notify_user', { title: 'Adom needs one click', body: `${_label} — ${_reason} I will wait until you are on the window.`, focus: false }, { timeoutMs: 4000 }); } catch (e) {}+            try { await chrome.abCommand('notify_user', { title: 'Adom needs one click', body: `${_label} — ${_reason} I will wait until you are on the window.`, focus: false }, { timeoutMs: 4000 }); } catch (e) {}             session._foreground = true; session._lastForeground = { ts: Date.now(), verb: command, reason: _reason };             try { await osRaiseSessionWindow(session, resolvedId, null); } catch (e) {}   // assisted_click narrates its own captions             const hwnd = await sessionHwnd(resolvedId);@@ -12872,13 +12292,13 @@ const server = http.createServer(async (req, res) => {               return;             }             await pupCaption(`Adom is clicking ${_label} now.`, 5000);-            const shot = adPayload(await chrome.adCommand('desktop_screenshot_window', { ...(await windowTarget(sessions.get(resolvedId), resolvedId)) }, { timeoutMs: 8000, caller: sessionCaller(session) }));+            const shot = abPayload(await chrome.abCommand('desktop_screenshot_window', { ...(await windowTarget(sessions.get(resolvedId), resolvedId)) }, { timeoutMs: 8000, caller: sessionCaller(session) }));             const shotId = shot && (shot.shotId || (shot.screenshots && shot.screenshots[0] && shot.screenshots[0].shotId));             if (!shotId) { sendJSON(res, { success: false, error: 'could not capture the window to aim the click' }); return; }             const X = Math.round(Number(args.x)), Y = Math.round(Number(args.y));-            try { await chrome.adCommand('desktop_hover', { space: 'image', shotId, x: X, y: Y }, { timeoutMs: 6000, caller: sessionCaller(session) }); } catch (e) {}+            try { await chrome.abCommand('desktop_hover', { space: 'image', shotId, x: X, y: Y }, { timeoutMs: 6000, caller: sessionCaller(session) }); } catch (e) {}             await new Promise(r => setTimeout(r, 900));-            try { await chrome.adCommand('desktop_click', { space: 'image', shotId, x: X, y: Y }, { timeoutMs: 6000, caller: sessionCaller(session) }); } catch (e) {}+            try { await chrome.abCommand('desktop_click', { space: 'image', shotId, x: X, y: Y }, { timeoutMs: 6000, caller: sessionCaller(session) }); } catch (e) {}             await pupCaption(`Adom clicked ${_label}. Continuing.`, 5000);             sendJSON(res, { success: true, output: JSON.stringify({ ok: true, clicked: _label, x: X, y: Y, sessionId: resolvedId }), _hint: `Assisted click done after the user was confirmed on the window. Verify the effect with a screenshot before assuming it advanced.` });           } catch (e) {