← Commit history
Cargo.lock+1−1
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-shotlog"-version = "0.18.2"+version = "0.19.0" dependencies = [  "axum",  "base64",
Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "adom-shotlog"-version = "0.18.2"+version = "0.19.0" edition = "2021" description = "Screenshot log viewer and CLI for Adom" license = "MIT"
VERSION+1−1
@@ -1 +1 @@-0.18.2+0.19.0
bin/adom-shotlog
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.18.2",+  "version": "0.19.0",   "type": "app",   "title": "Adom Shotlog",   "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Desktop child-window arrays via --meta.",
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.18.2",+  "version": "0.19.0",   "type": "app",   "title": "Adom Shotlog",   "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Desktop child-window arrays via --meta.",
skills/adom-shotlog-surfacing/SKILL.md+7−1
@@ -32,7 +32,13 @@ On a new shot, the broker pulls that channel's tab to the front IN ITS OWN PANE (`workspace active-tab`, never a tab move) and paints an **orange update alert** on it. It never touches other panes, so the human's typing is never interrupted. -### Pup - gentle orange taskbar flash, never foreground (AUTOMATIC)+### Pup - auto tab-switch + gentle taskbar flash, never foreground (AUTOMATIC)++On every new shot the broker also SWITCHES the shotlog pup window's active tab+to the updated channel (the pup mirror of the webview pull-to-front) - a shot+never lands in a buried background tab. Tab switching happens INSIDE our own+window; window focus/state is never touched.+  Open the pup canvas with `shotlog open -c <ch> --pup`: one shared pup window (session `shotlog`), a tab per channel, idempotent. The URL carries
src/open.rs+28
@@ -288,3 +288,31 @@ pub fn close_pup_tab(channel: &str) -> bool {     let Some(tid) = tab.get("tabId").or_else(|| tab.get("id")).and_then(|x| x.as_str()) else { return false };     ad(&["browser_close_tab", &format!("{{\"sessionId\":\"shotlog\",\"tabId\":\"{tid}\"}}")]).0 }++/// Switch the shared shotlog pup window's ACTIVE tab to this channel's tab+/// (no create, no window state change). The pup mirror of the webview+/// pull-to-front: a new shot should be what the user sees when they look.+pub fn switch_pup_tab(channel: &str) -> bool {+    let ad = |args: &[&str]| -> (bool, String) {+        let mut cmd = Command::new("adom-desktop");+        if let Ok(t) = std::env::var("SHOTLOG_AD_TARGET") {+            cmd.args(["--target", &t]);+        }+        match cmd.args(args).output() {+            Ok(o) => (o.status.success() && !String::from_utf8_lossy(&o.stdout).contains("\"error\""),+                String::from_utf8_lossy(&o.stdout).to_string()),+            Err(e) => (false, e.to_string()),+        }+    };+    let needle = format!("/log/{channel}/");+    let (ok, out) = ad(&["browser_list_tabs", "{\"sessionId\":\"shotlog\"}"]);+    if !ok { return false; }+    let Ok(v) = serde_json::from_str::<serde_json::Value>(&out) else { return false };+    let tabs = v.get("tabs").and_then(|t| t.as_array());+    let Some(tabs) = tabs else { return false };+    let Some(tab) = tabs.iter().find(|t| t.get("url").and_then(|u| u.as_str()).map(|u| u.contains(&needle)).unwrap_or(false)) else { return false };+    // already front?+    let tid = tab.get("tabId").or_else(|| tab.get("id")).and_then(|x| x.as_str()).unwrap_or("");+    if v.get("activeTabId").and_then(|a| a.as_str()) == Some(tid) { return true; }+    ad(&["browser_switch_tab", &format!("{{\"sessionId\":\"shotlog\",\"tabId\":\"{tid}\"}}")]).0+}
src/server.rs+10
@@ -598,11 +598,21 @@ fn notify_surface(channel: &str, port: u16, infos: &[crate::store::ViewerInfo],         .filter(|i| i.surface == "pup")         .filter_map(|i| i.session.clone())         .collect();+    let has_pup = infos.iter().any(|i| i.surface == "pup");     if alerts {         for s in pup_sessions {             flash_pup_session(&s);         }     }+    // Pup mirror of the webview pull-to-front: switch the shotlog pup window's+    // active tab to this channel so the update is what the user sees. (Tab+    // switch INSIDE our own window - never touches window focus/state.)+    if has_pup && debounce_ok(&format!("pupswitch:{channel}"), 3) {+        let ch = channel.to_string();+        std::thread::spawn(move || {+            crate::open::switch_pup_tab(&ch);+        });+    }      let has_webview = infos.iter().any(|i| i.surface == "webview");     if has_webview {