app
Grok Bot
Public Made by Adomby adom
Grok Bridge lets Adom talk to Grok Bot. Adom's AI environment is for electrical engineers: any provider, any desktop power tool, one place.
← Commit history
v1.3.8 (insiders): Hidden Grok Bot window: chat verbs read it in place, grok_open no longer re-shows it on its own (showing takes focus), only with foreground and a reason.
6 files changed
+59−29
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.3.7+1.3.8
CLAUDE.md+1−1@@ -71,7 +71,7 @@ auto-update relaunch drops them; `host_launch_flags_ok()` spots that and `grok_o Windows + approval (1.3.5, wiki #5 items 5-6): `pick_grok_window` skips strays (< 400x300), takes the largest, remembers the main hwnd in `~/.adom/grok-main-window.json`; `main_window_hidden`-when only strays are visible, `grok_open` re-shows it (show + bottom). `grok_webhook_fire+when hidden; chat verbs read it in place by hwnd (`read_target_hwnd`), and `grok_open` re-shows it only with foreground+foregroundReason (ab's `show` activates; there is no show-without-activate). `grok_webhook_fire {requireApproval, approvalSummary}` waits on a notify_user Allow/Deny toast and stamps `payload.approval`; caller-supplied approval fields are always stripped.
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "grok", "displayName": "Grok Bot",- "version": "1.3.7",+ "version": "1.3.8", "description": "Drive Grok Bot (standalone Electron app, Grok Bot.exe) from Adom Bridge: open/close/resize/screenshot/record the app, read thinking vs idle and the visible transcript of the focused thread, queue messages, bind the Grok Bridge webhook and create bots/channels. No public Grok HTTP API \u2014 the runtime talks back to ab over desktop_* callbacks. Cursor is last-resort fallback only if Grok Bot.exe is missing.", "homepage": "https://wiki.adom.inc/adom/grok-bridge", "author": "Adom Inc.",
handlers/chat.py+18−10@@ -19,6 +19,7 @@ from handlers.windows import ( grok_hwnd, host_launch_flags_ok, main_window_state,+ read_target_hwnd, ) # Proven UIA on Grok Bot.exe hwnd (AdomLapper): Document named "Grok Bot",@@ -182,8 +183,9 @@ def _window_missing(verb: str) -> dict: "agentName": None, "hwnd": None, "title": None, "hostApp": HOST_APP, "windowEtiquette": "background", "_hint": "Grok Bot's main window is hidden (only small secondary windows are visible). "- f"grok_open {{}} shows it behind the user's work, then grok_{verb} {{}}.",- "_next": f"grok_open {{}} then grok_{verb} {{}}"}+ "Its hwnd is not remembered on this PC, so it cannot be read in place. "+ "grok_open {\"restart\":true,\"reason\":\"...\"} relaunches it in the background.",+ "_next": "grok_open {\"restart\":true,\"reason\":\"...\"}"} out.update(ms) return out return {@@ -424,9 +426,9 @@ def _select_sidebar_thread(hwnd: int, name: str) -> dict: def handle_chat_status(_args: dict) -> dict: """thinking=true when UIA exposes '<agent> is working' / working chip. Never steals focus."""- hwnd, win = grok_hwnd(allow_cursor=False)+ hwnd, win, hidden = read_target_hwnd(allow_cursor=False) if not hwnd:- hwnd, win = grok_hwnd(allow_cursor=True)+ hwnd, win, hidden = read_target_hwnd(allow_cursor=True) if not hwnd: return _window_missing("chat_status") @@ -458,7 +460,11 @@ def handle_chat_status(_args: dict) -> dict: ), } if agent is None:- out["focusedThreadReason"] = "no conversation heading on the page"+ out["focusedThreadReason"] = ("main window is hidden: the heading and the working chip are not "+ "readable until it is shown" if hidden else "no conversation heading on the page")+ out["mainWindowHidden"] = hidden+ if hidden:+ out["thinking"] = None; out["idle"] = None out.update(computer_fields(probe["state"], probe["banner"])) return out @@ -473,9 +479,9 @@ def handle_chat_read(args: dict) -> dict: Always returns focusedThread (heading / agent name). After cold launch the focused thread may not be grok-bridge — callers should pass thread/agent or wait after grok_open. """- hwnd, win = grok_hwnd(allow_cursor=False)+ hwnd, win, hidden = read_target_hwnd(allow_cursor=False) if not hwnd:- hwnd, win = grok_hwnd(allow_cursor=True)+ hwnd, win, hidden = read_target_hwnd(allow_cursor=True) if not hwnd: miss = _window_missing("chat_read") miss["text"] = ""@@ -490,7 +496,7 @@ def handle_chat_read(args: dict) -> dict: wanted = str(args.get("thread") or args.get("agent") or "").strip() select_attempt = None- if wanted:+ if wanted and not hidden: select_attempt = _select_sidebar_thread(hwnd, wanted) thinking, working_name = _find_working(hwnd)@@ -504,7 +510,7 @@ def handle_chat_read(args: dict) -> dict: # transcript is empty/tiny, try the grok-bridge sidebar row once. tiny = len((raw or "").strip()) < 40 agent_l = (agent or "").strip().lower()- if not wanted and tiny and "grok-bridge" not in agent_l and "grok bridge" not in agent_l:+ if not hidden and not wanted and tiny and "grok-bridge" not in agent_l and "grok bridge" not in agent_l: select_attempt = _select_sidebar_thread(hwnd, "grok-bridge") thinking, working_name = _find_working(hwnd) agent = _read_agent_name(hwnd, working_name)@@ -602,8 +608,10 @@ def handle_chat_read(args: dict) -> dict: } out.update(limit_meta) out.update(computer_fields(*computer_state_from_text(raw)))+ out["mainWindowHidden"] = hidden if focused is None:- out["focusedThreadReason"] = "no conversation heading on the page"+ out["focusedThreadReason"] = ("main window is hidden; read in place (thread switching needs it shown)"+ if hidden else "no conversation heading on the page") if err and not text.strip(): out["success"] = False out["errorCode"] = err
handlers/describe.py+1−1@@ -53,7 +53,7 @@ VERB_CATALOG = { "screenshot": { "summary": "Screenshot a Grok Bot window via ab desktop_screenshot_window.", "long": False,- "hint": "Captures the picked MAIN window by hwnd (largest visible Grok Bot window, never one under 400x300); explicit titleContains only when you pass it. main_window_hidden when only strays are visible: grok_open {} re-shows it behind the user's work. Does not raise the window.",+ "hint": "Captures the picked MAIN window by hwnd (largest visible Grok Bot window, never one under 400x300); explicit titleContains only when you pass it. main_window_hidden when the main window is hidden (a hidden window cannot be captured; showing it takes focus, so only grok_open {foreground:true, foregroundReason}). grok_chat_read still reads it hidden. Does not raise the window.", "related": ["grok_list_windows", "grok_open", "grok_record_start"], "pitfalls": [ "Needs a live window — grok_open first if hostAppRunning is false.",
handlers/windows.py+37−15@@ -371,6 +371,19 @@ def grok_hwnd(*, allow_cursor: bool = True) -> tuple[int | None, dict | None]: return _hwnd_of(win), win +def read_target_hwnd(*, allow_cursor: bool = True) -> tuple[int | None, dict | None, bool]:+ """(hwnd, win, hidden) for READ verbs: the visible main window, else the remembered hidden+ main window (its page text stays readable through the hwnd while hidden)."""+ hwnd, win = grok_hwnd(allow_cursor=allow_cursor)+ if hwnd:+ return hwnd, win, False+ if main_window_state()["mainWindowHidden"]:+ h = remembered_main_hwnd()+ if h:+ return h, {"hwnd": h, "title": HOST_APP}, True+ return None, None, False++ def main_window_state() -> dict: """Fields for callers when no main window is visible. Hidden = only strays visible, or no window at all while Grok Bot runs and a main hwnd is remembered (grok_close hides it)."""@@ -386,18 +399,15 @@ def main_window_state() -> dict: def show_hidden_main() -> tuple[int | None, dict | None, dict | None]:- """Re-show the remembered main window BEHIND the user's work (show, then bottom)."""+ """Re-show the remembered main window. This ACTIVATES it: callers gate on foregroundReason.""" h = remembered_main_hwnd() if not h: return None, None, None res = _cb("desktop_set_window_state", {"hwnd": h, "state": "show"}) if not _callback_ok(res) or (isinstance(res, dict) and res.get("error")): return None, None, res- # show is asynchronous: a bottom sent at once lands before the window is up and it- # surfaces just under the foreground app. Wait, send it to the back, then once more.- for _ in range(2):- time.sleep(0.5)- _cb("desktop_set_window_state", {"hwnd": h, "state": "bottom"})+ _cb("desktop_set_window_state", {"hwnd": h, "state": "restore"})+ time.sleep(0.5) hwnd, win = grok_hwnd(allow_cursor=False) return hwnd, win, res @@ -656,9 +666,10 @@ def handle_screenshot(args: dict) -> dict: if ms["mainWindowHidden"]: out = {"success": False, "errorCode": "main_window_hidden", "error": "Grok Bot's main window is hidden; only small secondary windows are visible.",- "_hint": ("Not capturing a stray strip. grok_open {} shows the main window again, behind "- "the user's other windows (no focus steal), then retry grok_screenshot."),- "_next": "grok_open {} then grok_screenshot {}"}+ "_hint": ("A hidden window cannot be captured, and a stray strip is not Grok Bot. Showing "+ "it takes focus, so only if the user needs it: grok_open {\"foreground\":true,"+ "\"foregroundReason\":\"...\"}, then grok_screenshot. grok_chat_read still reads it hidden."),+ "_next": "grok_chat_read {} (works hidden), or grok_open {\"foreground\":true,\"foregroundReason\":\"...\"}"} out.update(ms) return out return {@@ -736,7 +747,12 @@ def handle_open(args: dict) -> dict: hidden_fix = None if proc0 and not hwnd0 and not fallback and restarted is None: hidden_state = main_window_state()- h2, w2, res = show_hidden_main()+ # Showing a hidden window activates it (ab has no show-without-activate), so it+ # is a foreground action: only with foreground:true + foregroundReason.+ if want_fg and len(reason) >= _FG_REASON_MIN:+ h2, w2, res = show_hidden_main()+ else:+ h2, w2, res = None, None, None hidden_fix = dict(hidden_state, shown=bool(h2), showCallback=res) if h2: hwnd0, win0 = h2, w2@@ -801,11 +817,17 @@ def handle_open(args: dict) -> dict: if hidden_fix is not None: env.update({k: hidden_fix[k] for k in ("mainWindowHidden", "strayWindows", "rememberedMainHwnd")}) env["shownHiddenMain"] = hidden_fix["shown"]- env["_hint"] = (("Grok Bot's main window was hidden; showed it again BEHIND the user's other "- "windows (show + bottom, no focus steal). ") if hidden_fix["shown"] else- ("Grok Bot is running but its main window is hidden and its hwnd is not "- "remembered on this PC. grok_open {\"restart\":true,\"reason\":\"...\"} "- "relaunches it in the background. ")) + env["_hint"]+ if hidden_fix["shown"]:+ env["_hint"] = "Grok Bot's main window was hidden; shown again because foregroundReason was given. " + env["_hint"]+ elif hidden_fix.get("rememberedMainHwnd"):+ env["_hint"] = ("Grok Bot is running with its main window HIDDEN (not shown: showing it takes "+ "focus). grok_chat_read / grok_chat_status still read it in place. To show it: "+ "grok_open {\"foreground\":true,\"foregroundReason\":\"<why the user needs to see it>\"}. " + env["_hint"])+ env["_next"] = "grok_open {\"foreground\":true,\"foregroundReason\":\"...\"} only if the user needs to see it"+ else:+ env["_hint"] = ("Grok Bot is running but its main window is hidden and its hwnd is not remembered "+ "on this PC. grok_open {\"restart\":true,\"reason\":\"...\"} relaunches it in the "+ "background. " + env["_hint"]) if restarted is not None: env["restartKill"] = restarted env["_hint"] = "Restart asked, but Grok Bot was still running after the kill. " + env["_hint"]