← Commit history

Publish 1.9.115

John Lauer ·526c5b8e32 ·3mo ago ·parent f0fead1
6 files changed +18−12
SKILL.md+5−2
@@ -1467,8 +1467,11 @@ If you don't have the suffix handy, just ask the user. Or if the file you wanted - `desktop_bring_to_front` -- Bring a window to the foreground by HWND or title substring. Uses keybd_event + AttachThreadInput to bypass Windows foreground lock. Preserves maximized state.   - Args: `hwnd` (int) OR `titleContains` (string, case-insensitive). One required.   - Example: `adom-desktop desktop_bring_to_front '{"titleContains": "Fusion"}'`-- `desktop_set_window_state` -- Change a window's show state without bringing it to the foreground (or both, if combined with `desktop_bring_to_front`). Args: `hwnd` (int) OR `titleContains` (string), plus `state` (one of `"maximize"`, `"minimize"`, `"restore"`, `"show"`, `"hide"`). Use to ensure Fusion or KiCad windows are maximized for screenshots, or to hide noisy background windows during demos.+- `desktop_set_window_state` -- Change a window's show state without bringing it to the foreground (or both, if combined with `desktop_bring_to_front`). Args: `hwnd` (int) OR `titleContains` (string) OR `cacheKey`, plus `state` (one of `"maximize"`, `"minimize"`, `"restore"`, `"show"`, `"hide"`, `"bottom"`). Use to ensure Fusion or KiCad windows are maximized for screenshots, or to hide noisy background windows during demos.   - Example: `adom-desktop desktop_set_window_state '{"hwnd":133560,"state":"maximize"}'`+  - **`state:"bottom"` (v1.9.114) -- z-order send-to-back, background.** Drops the window BEHIND all others without focusing, moving, or resizing it (`SetWindowPos HWND_BOTTOM` + `SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE`); works even on an off-screen window. It's an ATOMIC check-and-demote: it reads `GetForegroundWindow()` first, and if the target IS the OS foreground (the user is interacting with it) it SKIPS the demotion and returns `wasForeground:true, sentToBack:false` so the caller backs off with no race; otherwise `wasForeground:false, sentToBack:true`. Use to park a background window behind the user's windows (still on-screen, taskbar-clickable, rendering for screenshots) without stealing focus.+  - **`force:true` (v1.9.115)** sends it to back EVEN IF the window is currently the OS foreground (still no activation change; `sentToBack:true` always, `wasForeground` still reported). Use at window-LAUNCH time: Windows reassigns the foreground to a brand-new window when the previous foreground is destroyed, so "foreground at launch" is not a real user signal.+  - Example: `adom-desktop desktop_set_window_state '{"titleContains":"(session: abc","state":"bottom","force":true}'`  #### Real OS input — mouse + keyboard (v1.8.170+) @@ -1563,7 +1566,7 @@ Two ways to use it: - **`display: {virtualScreen, primary{w,h,dpi,scale}, monitors[], monitorOfWindow}`** — the full monitor topology: total virtual bounds, and per-monitor `bounds`/`dpi`/`scale`/`primary`. `monitorOfWindow` indexes into `monitors[]`. (Same data as the standalone `desktop_display` verb, folded in.) - **`drive: "background"`** — screenshots never foreground the window (PrintWindow/WGC). The companion `_related` field lists sibling screenshot/window verbs. -**Screenshot cache is self-cleaning + self-describing (v1.9.107/108/113):** the CLI auto-pulls every screenshot to ONE user-visible, namespaced dir on the caller's machine (`~/project/screenshots/adom-desktop/`, else `~/.adom/screenshots/`; `ADOM_SHOTS_DIR` overrides) — never `/tmp` anymore. Shots are **bucketed by kind into subfolders**: `window/` (a specific window / app / owned popup) and `screen/` (a full-desktop grab). **Human-readable filenames (v1.9.113):** `<YYYY-MM-DDThh-mm-ss.mmm>[-<hwnd>].{full,safe}.png` — a sortable ISO stamp (lexicographic == chronological), plus the `hwnd` for a window capture; the `window`/`screen` kind is NOT repeated in the name because the folder already says it. Each shot gets a **`<stem>.json` sidecar** (shotlog-style: `source`, `timestamp`, `kind`, dims + `bytes`, `coordMap`, `rect`; a full+safe pair shares one). **Parent/child grouping (v1.9.111/113):** when `desktop_screenshot_window` returns owned popups in `screenshots[]`, the parent AND each pulled child share the same stem, and each child gets a **`.popup-NN` label** — e.g. parent `2026-07-15T01-14-16.937-986710.safe.png` and children `2026-07-15T01-14-16.937-986710.popup-01.safe.png`, `...popup-02...`. So a plain `ls` shows the whole capture grouped (shared stem) and the role (`.popup-NN`) without opening a sidecar; the sidecar also carries `parent` + `popupIndex`. (`kicad_screenshot_all` returns sibling windows with no parent, so those keep their own names.) A janitor prunes it (7 days / 2 GB / newest kept; sidecars follow their PNG, orphans swept) and drains the old `/tmp/ad-shots` + `/tmp/adom-desktop-screenshots` backlogs, running opportunistically at most once/24h on any CLI call. **You do not need to clean it up or write your own cron.** Every screenshot response carries a `_cacheHint`; verify coverage with **`adom-desktop janitor`** (status: each subfolder, size, policy, last sweep) or force a sweep with **`adom-desktop janitor '{"sub":"run"}'`**. It never touches other tools' files under `~/project/screenshots/` (e.g. shotlog). Tune via `ADOM_SHOTS_MAX_AGE_DAYS` / `ADOM_SHOTS_MAX_GB` / `ADOM_SHOTS_MAX_FILES`, or disable with `ADOM_JANITOR=0`.+**Screenshot cache is self-cleaning + self-describing (v1.9.107/108/113):** the CLI auto-pulls every screenshot to ONE user-visible, namespaced dir on the caller's machine (`~/project/screenshots/adom-desktop/`, else `~/.adom/screenshots/`; `ADOM_SHOTS_DIR` overrides) — never `/tmp` anymore. Shots are **bucketed by kind into subfolders**: `window/` (a specific window / app / owned popup) and `screen/` (a full-desktop grab). **Human-readable filenames (v1.9.113):** `<YYYY-MM-DDThh-mm-ss.mmm>[-<hwnd>].png` — a sortable ISO stamp (lexicographic == chronological), plus the `hwnd` for a window capture; the `window`/`screen` kind is NOT repeated in the name because the folder already says it. **One file when small (v1.9.114):** if the shot was already within the safe size cap (the common case) it's a single `<stem>.png` and `localFullPath == localSafePath` — no redundant re-encoded copy. Only a shot large enough to be downscaled produces a `<stem>.full.png` + `<stem>.safe.png` pair (Read the `.safe` one for image analysis; use `.full` for archive). Each shot gets a **`<stem>.json` sidecar** (shotlog-style: `source`, `timestamp`, `kind`, dims + `bytes`, `coordMap`, `rect`; a full+safe pair shares one). **Parent/child grouping (v1.9.111/113):** when `desktop_screenshot_window` returns owned popups in `screenshots[]`, the parent AND each pulled child share the same stem, and each child gets a **`.popup-NN` label** — e.g. parent `2026-07-15T01-14-16.937-986710.safe.png` and children `2026-07-15T01-14-16.937-986710.popup-01.safe.png`, `...popup-02...`. So a plain `ls` shows the whole capture grouped (shared stem) and the role (`.popup-NN`) without opening a sidecar; the sidecar also carries `parent` + `popupIndex`. (`kicad_screenshot_all` returns sibling windows with no parent, so those keep their own names.) A janitor prunes it (7 days / 2 GB / newest kept; sidecars follow their PNG, orphans swept) and drains the old `/tmp/ad-shots` + `/tmp/adom-desktop-screenshots` backlogs, running opportunistically at most once/24h on any CLI call. **You do not need to clean it up or write your own cron.** Every screenshot response carries a `_cacheHint`; verify coverage with **`adom-desktop janitor`** (status: each subfolder, size, policy, last sweep) or force a sweep with **`adom-desktop janitor '{"sub":"run"}'`**. It never touches other tools' files under `~/project/screenshots/` (e.g. shotlog). Tune via `ADOM_SHOTS_MAX_AGE_DAYS` / `ADOM_SHOTS_MAX_GB` / `ADOM_SHOTS_MAX_FILES`, or disable with `ADOM_JANITOR=0`.  **Background vs foreground driving (v1.8.178):** every desktop driving verb carries a structured **`drive`** field (`"background"` | `"foreground"` | `"n/a"`) — in `GET /commands`, in `adom-desktop help <verb>`, and echoed in the verb's own response. **Background** (no foreground / focus steal / cursor move — UIA + capture): `desktop_ui_click`, `desktop_ui_set`, `desktop_navigate`, `desktop_find_control`, `desktop_screenshot_window/_screen`, `desktop_record_window_start`. **Foreground** (SendInput → goes to the focused window, so AD foregrounds first): `desktop_click`/`_double_click`/`_right_click`/`_hover`, `desktop_type`, `desktop_press_key`, `desktop_bring_to_front`. Run **`adom-desktop help background`** for the full grouping. Rule: to act without disturbing the user's window, drive by NAME (`desktop_find_control` → `desktop_ui_click`/`ui_set`); fall back to coordinate clicks/keys only when the control isn't in the UIA tree. 
dist/linux/adom-desktop
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -1,6 +1,6 @@ {
   "slug": "adom-desktop",
-  "version": "1.9.113",
+  "version": "1.9.115",
   "type": "app",
   "description": "Laptop bridge: file transfer, screenshots, notifications, KiCad + Fusion 360 control, real-Chrome (Puppeteer) automation, and Hydrogen Desktop proxy. One install gives Claude every desktop verb it needs.",
   "discovery_pitch": "Use when a cloud AI needs to reach a real Windows desktop: run shell commands, capture screenshots, drive native apps and browsers, transfer files, and control KiCad / Fusion 360 / third-party bridges.",
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-desktop",-  "version": "1.9.113",+  "version": "1.9.115",   "type": "app",   "description": "Laptop bridge: file transfer, screenshots, notifications, KiCad + Fusion 360 control, real-Chrome (Puppeteer) automation, and Hydrogen Desktop proxy. One install gives Claude every desktop verb it needs.",   "keywords": [
skills/adom-desktop/SKILL.md+5−2
@@ -1467,8 +1467,11 @@ If you don't have the suffix handy, just ask the user. Or if the file you wanted - `desktop_bring_to_front` -- Bring a window to the foreground by HWND or title substring. Uses keybd_event + AttachThreadInput to bypass Windows foreground lock. Preserves maximized state.   - Args: `hwnd` (int) OR `titleContains` (string, case-insensitive). One required.   - Example: `adom-desktop desktop_bring_to_front '{"titleContains": "Fusion"}'`-- `desktop_set_window_state` -- Change a window's show state without bringing it to the foreground (or both, if combined with `desktop_bring_to_front`). Args: `hwnd` (int) OR `titleContains` (string), plus `state` (one of `"maximize"`, `"minimize"`, `"restore"`, `"show"`, `"hide"`). Use to ensure Fusion or KiCad windows are maximized for screenshots, or to hide noisy background windows during demos.+- `desktop_set_window_state` -- Change a window's show state without bringing it to the foreground (or both, if combined with `desktop_bring_to_front`). Args: `hwnd` (int) OR `titleContains` (string) OR `cacheKey`, plus `state` (one of `"maximize"`, `"minimize"`, `"restore"`, `"show"`, `"hide"`, `"bottom"`). Use to ensure Fusion or KiCad windows are maximized for screenshots, or to hide noisy background windows during demos.   - Example: `adom-desktop desktop_set_window_state '{"hwnd":133560,"state":"maximize"}'`+  - **`state:"bottom"` (v1.9.114) -- z-order send-to-back, background.** Drops the window BEHIND all others without focusing, moving, or resizing it (`SetWindowPos HWND_BOTTOM` + `SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE`); works even on an off-screen window. It's an ATOMIC check-and-demote: it reads `GetForegroundWindow()` first, and if the target IS the OS foreground (the user is interacting with it) it SKIPS the demotion and returns `wasForeground:true, sentToBack:false` so the caller backs off with no race; otherwise `wasForeground:false, sentToBack:true`. Use to park a background window behind the user's windows (still on-screen, taskbar-clickable, rendering for screenshots) without stealing focus.+  - **`force:true` (v1.9.115)** sends it to back EVEN IF the window is currently the OS foreground (still no activation change; `sentToBack:true` always, `wasForeground` still reported). Use at window-LAUNCH time: Windows reassigns the foreground to a brand-new window when the previous foreground is destroyed, so "foreground at launch" is not a real user signal.+  - Example: `adom-desktop desktop_set_window_state '{"titleContains":"(session: abc","state":"bottom","force":true}'`  #### Real OS input — mouse + keyboard (v1.8.170+) @@ -1563,7 +1566,7 @@ Two ways to use it: - **`display: {virtualScreen, primary{w,h,dpi,scale}, monitors[], monitorOfWindow}`** — the full monitor topology: total virtual bounds, and per-monitor `bounds`/`dpi`/`scale`/`primary`. `monitorOfWindow` indexes into `monitors[]`. (Same data as the standalone `desktop_display` verb, folded in.) - **`drive: "background"`** — screenshots never foreground the window (PrintWindow/WGC). The companion `_related` field lists sibling screenshot/window verbs. -**Screenshot cache is self-cleaning + self-describing (v1.9.107/108/113):** the CLI auto-pulls every screenshot to ONE user-visible, namespaced dir on the caller's machine (`~/project/screenshots/adom-desktop/`, else `~/.adom/screenshots/`; `ADOM_SHOTS_DIR` overrides) — never `/tmp` anymore. Shots are **bucketed by kind into subfolders**: `window/` (a specific window / app / owned popup) and `screen/` (a full-desktop grab). **Human-readable filenames (v1.9.113):** `<YYYY-MM-DDThh-mm-ss.mmm>[-<hwnd>].{full,safe}.png` — a sortable ISO stamp (lexicographic == chronological), plus the `hwnd` for a window capture; the `window`/`screen` kind is NOT repeated in the name because the folder already says it. Each shot gets a **`<stem>.json` sidecar** (shotlog-style: `source`, `timestamp`, `kind`, dims + `bytes`, `coordMap`, `rect`; a full+safe pair shares one). **Parent/child grouping (v1.9.111/113):** when `desktop_screenshot_window` returns owned popups in `screenshots[]`, the parent AND each pulled child share the same stem, and each child gets a **`.popup-NN` label** — e.g. parent `2026-07-15T01-14-16.937-986710.safe.png` and children `2026-07-15T01-14-16.937-986710.popup-01.safe.png`, `...popup-02...`. So a plain `ls` shows the whole capture grouped (shared stem) and the role (`.popup-NN`) without opening a sidecar; the sidecar also carries `parent` + `popupIndex`. (`kicad_screenshot_all` returns sibling windows with no parent, so those keep their own names.) A janitor prunes it (7 days / 2 GB / newest kept; sidecars follow their PNG, orphans swept) and drains the old `/tmp/ad-shots` + `/tmp/adom-desktop-screenshots` backlogs, running opportunistically at most once/24h on any CLI call. **You do not need to clean it up or write your own cron.** Every screenshot response carries a `_cacheHint`; verify coverage with **`adom-desktop janitor`** (status: each subfolder, size, policy, last sweep) or force a sweep with **`adom-desktop janitor '{"sub":"run"}'`**. It never touches other tools' files under `~/project/screenshots/` (e.g. shotlog). Tune via `ADOM_SHOTS_MAX_AGE_DAYS` / `ADOM_SHOTS_MAX_GB` / `ADOM_SHOTS_MAX_FILES`, or disable with `ADOM_JANITOR=0`.+**Screenshot cache is self-cleaning + self-describing (v1.9.107/108/113):** the CLI auto-pulls every screenshot to ONE user-visible, namespaced dir on the caller's machine (`~/project/screenshots/adom-desktop/`, else `~/.adom/screenshots/`; `ADOM_SHOTS_DIR` overrides) — never `/tmp` anymore. Shots are **bucketed by kind into subfolders**: `window/` (a specific window / app / owned popup) and `screen/` (a full-desktop grab). **Human-readable filenames (v1.9.113):** `<YYYY-MM-DDThh-mm-ss.mmm>[-<hwnd>].png` — a sortable ISO stamp (lexicographic == chronological), plus the `hwnd` for a window capture; the `window`/`screen` kind is NOT repeated in the name because the folder already says it. **One file when small (v1.9.114):** if the shot was already within the safe size cap (the common case) it's a single `<stem>.png` and `localFullPath == localSafePath` — no redundant re-encoded copy. Only a shot large enough to be downscaled produces a `<stem>.full.png` + `<stem>.safe.png` pair (Read the `.safe` one for image analysis; use `.full` for archive). Each shot gets a **`<stem>.json` sidecar** (shotlog-style: `source`, `timestamp`, `kind`, dims + `bytes`, `coordMap`, `rect`; a full+safe pair shares one). **Parent/child grouping (v1.9.111/113):** when `desktop_screenshot_window` returns owned popups in `screenshots[]`, the parent AND each pulled child share the same stem, and each child gets a **`.popup-NN` label** — e.g. parent `2026-07-15T01-14-16.937-986710.safe.png` and children `2026-07-15T01-14-16.937-986710.popup-01.safe.png`, `...popup-02...`. So a plain `ls` shows the whole capture grouped (shared stem) and the role (`.popup-NN`) without opening a sidecar; the sidecar also carries `parent` + `popupIndex`. (`kicad_screenshot_all` returns sibling windows with no parent, so those keep their own names.) A janitor prunes it (7 days / 2 GB / newest kept; sidecars follow their PNG, orphans swept) and drains the old `/tmp/ad-shots` + `/tmp/adom-desktop-screenshots` backlogs, running opportunistically at most once/24h on any CLI call. **You do not need to clean it up or write your own cron.** Every screenshot response carries a `_cacheHint`; verify coverage with **`adom-desktop janitor`** (status: each subfolder, size, policy, last sweep) or force a sweep with **`adom-desktop janitor '{"sub":"run"}'`**. It never touches other tools' files under `~/project/screenshots/` (e.g. shotlog). Tune via `ADOM_SHOTS_MAX_AGE_DAYS` / `ADOM_SHOTS_MAX_GB` / `ADOM_SHOTS_MAX_FILES`, or disable with `ADOM_JANITOR=0`.  **Background vs foreground driving (v1.8.178):** every desktop driving verb carries a structured **`drive`** field (`"background"` | `"foreground"` | `"n/a"`) — in `GET /commands`, in `adom-desktop help <verb>`, and echoed in the verb's own response. **Background** (no foreground / focus steal / cursor move — UIA + capture): `desktop_ui_click`, `desktop_ui_set`, `desktop_navigate`, `desktop_find_control`, `desktop_screenshot_window/_screen`, `desktop_record_window_start`. **Foreground** (SendInput → goes to the focused window, so AD foregrounds first): `desktop_click`/`_double_click`/`_right_click`/`_hover`, `desktop_type`, `desktop_press_key`, `desktop_bring_to_front`. Run **`adom-desktop help background`** for the full grouping. Rule: to act without disturbing the user's window, drive by NAME (`desktop_find_control` → `desktop_ui_click`/`ui_set`); fall back to coordinate clicks/keys only when the control isn't in the UIA tree. 
version.json+6−6
@@ -1,14 +1,14 @@ {   "manifest_version": 1,-  "version": "1.9.113",+  "version": "1.9.115",   "released_at": "2026-07-15T00:00:00Z",   "windows": {-    "installer_url": "https://wiki.adom.inc/download/adom/adom-desktop/1.9.113/Adom.Desktop_1.9.113_windows_x64-setup.exe",-    "installer_filename": "Adom.Desktop_1.9.113_windows_x64-setup.exe",-    "installer_sha256": "0ffd595640fd83b77718c1332a59f64d4364d5143a7faa73c9330d0bb2d25971",-    "installer_size": 10562976+    "installer_url": "https://wiki.adom.inc/download/adom/adom-desktop/1.9.115/Adom.Desktop_1.9.115_windows_x64-setup.exe",+    "installer_filename": "Adom.Desktop_1.9.115_windows_x64-setup.exe",+    "installer_sha256": "d793afd81089649756b15dcfe1686a95496c2a209b9a95a4bfbcf9ab9f5cfc47",+    "installer_size": 10576408   },   "changelog_url": "https://wiki.adom.inc/adom/adom-desktop",   "minimum_required": "1.3.30",-  "note": "Container CLI: pulled-screenshot filenames are now human-readable. The window/screen prefix is dropped (the folder already names the kind), the trailing epoch becomes a sortable ISO stamp (2026-07-15T01-14-16.937), and the hwnd is kept. Owned-popup children share the parent's stem with a .popup-NN tag, so a plain ls groups the whole capture. Windows GUI unchanged from 1.9.112."+  "note": "Screenshot dedup: a capture already within the safe size cap is written ONCE (localFullPath == localSafePath); only a downscaled shot gets a .full+.safe pair. Window z-order send-to-back: desktop_set_window_state state:\"bottom\" drops a window behind all others in the background (no focus/move/resize), with an atomic check-and-skip when it's the OS foreground and an optional force:true to override at window-launch time." }