app
Shotlog - Screenshot Log
Public Made by Adomby adom
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 Bridge child-window arrays via --meta.
← Commit history
Publish 0.19.0
9 files changed
+50−6
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 {