← Commit history

v0.1.37: lone-OK dialogs carry no decision - reaper clears them without needing the text

John Lauer ·c56dc01c5d ·1mo ago ·parent 1671744
7 files changed +27−7
CHANGELOG.md+6
@@ -1,5 +1,11 @@ # Changelog +## 0.1.37 — 2026-09-01+- **Altium's dialog text is unreadable — so the reaper stops relying on it.** Measured: the VaultExplorer warning's entire UIA subtree is `Window "Warning" -> panes -> Button "OK"`. The message is PAINTED pixels, absent from `WM_GETTEXT` and from the accessibility tree, so no amount of text classification will ever see it.+- **The rule that does work: a dialog whose ONLY button is OK carries no decision.** Dismissing it can acknowledge, never choose. Everything that asks something of the user has two or more buttons — a save prompt (Save / Don't Save / Cancel), a licence chooser (Choose a license / Continue), a confirm (Yes / No). The standing reaper now clears lone-OK dialogs even when their text is unreadable, logging them as `single_ok_acknowledgement`.+- Multi-button dialogs are still never improvised on: if the catalog's safe action is not literally one of the dialog's buttons, the reaper leaves it alone.+- This is what finally makes `Could not start Vault Explorer` — and any future painted, single-OK Altium warning — invisible to the user.+ ## 0.1.36 — 2026-09-01 - **The bridge can finally READ Altium's dialog messages.** Altium PAINTS its dialog text instead of using Static controls, so `WM_GETTEXT` returned nothing but the BUTTON labels — `Could not start Vault Explorer…` came back as a body of just `"OK"`. Every such dialog therefore classified as `unknown`, which is why the standing reaper (correctly, per its own rules) refused to touch the exact warning it was built for. - `_body_of()` now strips the button labels and, when what is left is too short to be a message, asks UIA (`desktop_ui_text`) for the painted text. Classification, the reaper, `check_dialogs` and every `_hint` that quotes a dialog all get the real message.
adom-bridge-altium-manifest.json+4−4
@@ -1,9 +1,9 @@ {   "name": "altium",-  "version": "0.1.36",-  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.36/adom-bridge-altium-v0.1.36.zip",-  "sha256": "8f549ccaf75788c179fe76112f17243a6a74ab83f6180ee1519f059eae8f5b94",-  "size": 134889,+  "version": "0.1.37",+  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.37/adom-bridge-altium-v0.1.37.zip",+  "sha256": "fa20a659046ef5f8d7a24ff13c871cc0b54885b1ea8e1dbcfbc58f1f64f2c8d4",+  "size": 135280,   "verbPrefixes": [     "altium_"   ],
adom-bridge-altium-v0.1.37.zipadded
⋯ 1 unchanged line ⋯
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "altium",   "displayName": "Altium Designer",-  "version": "0.1.36",+  "version": "0.1.37",   "description": "Drive Altium Designer from Adom: a resident DelphiScript agent (eval + the 1,100-command process launcher), the X2 -R command line, UIA over the VCL shell, dialogs by PID, screenshots of every Altium window, and Altium 365.",   "homepage": "https://wiki.adom.inc/adom/altium-bridge",   "docs": "https://wiki.adom.inc/adom/altium-bridge",
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "altium-bridge",-  "version": "0.1.36",+  "version": "0.1.37",   "type": "app",   "description": "Skills for your container so your AI knows how to drive the Altium Designer bridge (altium_* verbs). The bridge runtime itself is the release zip; Adom Bridge loads that.",   "tags": [
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.36+0.1.37
src/handlers/dialogs.py+14
@@ -269,8 +269,22 @@ def _reap_once() -> int:             act, cat = c.get("safeAction"), c.get("category")         else:             cat = d.get("category")+        # Altium PAINTS its dialog messages: they are in neither WM_GETTEXT nor the UIA tree (the+        # subtree of the VaultExplorer warning is literally Window "Warning" -> panes -> Button+        # "OK"). So text classification cannot see them. What CAN be trusted is the button set:+        #+        #   A dialog whose ONLY button is OK carries NO DECISION. Dismissing it can acknowledge,+        #   never choose. Every dialog that asks something of the user has >= 2 buttons — a save+        #   prompt (Save / Don't Save / Cancel), a licence chooser (Choose a license / Continue), a+        #   confirm (Yes / No). So a lone OK is safe to press even when the text is unreadable.+        labels = [str((b or {}).get("text") or "").strip().lower() for b in (d.get("buttons") or [])]+        lone_ok = labels == ["ok"]+        if not act and lone_ok:+            act, cat = "OK", "single_ok_acknowledgement"         if not act or cat in (None, "unknown", "save_prompt"):             continue+        if cat != "single_ok_acknowledgement" and len(labels) > 1 and act not in labels:+            continue  # the catalog's action is not even on this dialog — do not improvise         hw = d.get("hwnd")         if hw in _REAPED_HWNDS:             continue