← Commit history

Update 3 file(s)

John Lauer ·0572dee7e3 ·2mo ago ·parent 67686bf
3 files changed +17−3
CHANGELOG.md+9
@@ -1,5 +1,14 @@ # Changelog — Puppeteer Bridge +## 2.0.438 — 2026-09-06 — pup_open_window honours `owner`; every thread tile re-rendered++Found while recreating all of John's windows on AdomLapper as proof: pup_open_window ignored the declared+`owner` (Node: ownerSource "declared"), so windows recreated on another thread's behalf wore the caller's+tile. Fixed. The tile cache generation is bumped (t7 to t8) so every existing thread name is re-rendered+by the 2.0.437 multi-size renderer instead of reusing a cached single-size ICO. (The build container's+volume filled during this release; two source files were truncated by the failed writes and restored+from the wiki repo copies.)+ ## 2.0.437 — 2026-09-06 — badges that load under CSP, tiles rendered at every size, one button born with the tile  Three of John's findings in one release:
rust/identity/src/lib.rs+2−2
@@ -9,7 +9,7 @@ use std::path::{Path, PathBuf};  pub const APP_ID: &str = "Adom.Pup"; pub const DISPLAY_NAME: &str = "Adom Pup";-pub const TILE_GEN: &str = "t7";+pub const TILE_GEN: &str = "t8"; pub const ICON_GEN: &str = "9"; pub const TITLE_LABEL: &str = "ai-thread"; @@ -358,7 +358,7 @@ mod tests {         // Node: threadSlug('pup-bridge') = 'pup-bridge-' + sha1('pup-bridge')[..6]         assert_eq!(thread_slug("pup-bridge"), format!("pup-bridge-{}", &sha1_hex(b"pup-bridge")[..6]));         assert!(thread_slug("My Thread / x").starts_with("my-thread-x-"));-        assert_eq!(thread_aumid("t", "iabc123"), format!("Adom.Pup.thread.t-{}.t7iabc123", &sha1_hex(b"t")[..6]));+        assert_eq!(thread_aumid("t", "iabc123"), format!("Adom.Pup.thread.t-{}.{}iabc123", &sha1_hex(b"t")[..6], TILE_GEN));     }     #[test] fn classify() { assert_eq!(classify_url("https://wiki.adom.inc/adom/x"), Some("wiki")); assert_eq!(classify_url("http://localhost:3000/"), Some("app")); assert_eq!(classify_url("https://x.adom.cloud/proxy/1/"), Some("app")); assert_eq!(classify_url("https://example.com"), Some("web")); assert_eq!(classify_url("about:blank"), None); }     #[test] fn ico_wraps_png() { let png = [0x89, b'P', b'N', b'G', b'\r', b'\n', 0x1a, b'\n', 0,0,0,13, b'I',b'H',b'D',b'R', 0,0,1,0, 0,0,1,0, 8,6,0,0,0]; assert_eq!(png_size(&png), Some((256, 256))); let ico = png_to_ico(&png, 256, 256); assert_eq!(&ico[..4], &[0,0,1,0]); assert_eq!(ico.len(), png.len() + 22); }
rust/verbs/src/lib.rs+6−1
@@ -668,7 +668,12 @@ fn open_window(ctx: &Ctx, caller: &Caller, args: &Value) -> Value {     let before: std::collections::HashSet<i64> = ctx.host.windows_for_pids(&[], Some("Chrome_WidgetWin_1")).into_iter().map(|w| w.hwnd).collect();     let prev_fg = ctx.host.foreground();   // Node v1.9.253: measure whether creation steals focus, and hand it straight back     let target = match b.cdp.create_target("about:blank", true, Some((OFFSCREEN, OFFSCREEN, bw, bh))) { Ok(t) => t, Err(e) => return err("cdp_create_target_failed", format!("Target.createTarget: {e}"), Some("The browser is up but refused a new window; pup_readiness shows its state, pup_close {} restarts it.")) };-    let mut s = Session::new(&sid, &profile, if caller.thread.is_empty() { None } else { Some(&caller.thread) }, Some(&caller.container), b.launched.cdp_port, if b.launched.pid > 0 { Some(b.launched.pid) } else { None });+    // Node: an explicit `owner` declares the owning thread (ownerSource "declared"); else the caller's thread.+    // The Rust port ignored `owner` until 2.0.438, so a window recreated on another thread's behalf wore the+    // recreating thread's tile (John's AdomLapper proof run, 2026-09-06).+    let declared_owner = args.get("owner").and_then(|o| o.as_str()).map(|o| o.trim().to_string()).filter(|o| !o.is_empty());+    let owner: Option<&str> = declared_owner.as_deref().or(if caller.thread.is_empty() { None } else { Some(caller.thread.as_str()) });+    let mut s = Session::new(&sid, &profile, owner, Some(&caller.container), b.launched.cdp_port, if b.launched.pid > 0 { Some(b.launched.pid) } else { None });     s.owner_from_caller = s.owner.as_deref() == Some(caller.thread.as_str()) && !caller.thread.is_empty() && args.get("owner").is_none();     let tab_id = match attach_tab(&mut s, &b.cdp, &target) { Ok(t) => t, Err(e) => return e };     // park: on-screen rect via CDP (moves without z-order change), then bottom + tag via the host