{"record":{"id":"694177e2e62b68ee","repo":"Hmbown/CodeWhale","slug":"list-windows-needs-wmctrl-x11-swaymsg-sway-or-hyprctl","errorCode":null,"errorMessage":"list_windows needs wmctrl (X11), swaymsg (sway) or hyprctl (hyprland)","messagePattern":"list_windows needs wmctrl \\(X11\\), swaymsg \\(sway\\) or hyprctl \\(hyprland\\)","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":460,"sourceCode":"        return { windows };\n      }\n      if (session === \"wayland\" && tools.swaymsg) {\n        const r = await run(\"swaymsg\", [\"-t\", \"get_tree\", \"-r\"], { timeoutMs: 15_000 });\n        const windows = [];\n        const walk = (n) => {\n          if (n.type === \"con\" && n.name) windows.push({ id: String(n.id), title: n.name, wm_class: n.app_id ?? null, position: { x: n.rect?.x, y: n.rect?.y }, size: { w: n.rect?.width, h: n.rect?.height }, focused: !!n.focused });\n          (n.nodes ?? []).forEach(walk);\n          (n.floating_nodes ?? []).forEach(walk);\n        };\n        walk(tryJson(r.stdout, {}));\n        return { windows };\n      }\n      if (session === \"wayland\" && tools.hyprctl) {\n        const r = await run(\"hyprctl\", [\"-j\", \"clients\"], { timeoutMs: 15_000 });\n        const clients = tryJson(r.stdout, []);\n        return { windows: clients.map((c) => ({ id: String(c.address), title: c.title, wm_class: c.class, position: { x: c.at?.[0], y: c.at?.[1] }, size: { w: c.size?.[0], h: c.size?.[1] }, focused: !!c.focused })) };\n      }\n      throw new ExecError(\"list_windows needs wmctrl (X11), swaymsg (sway) or hyprctl (hyprland)\");\n    },\n    open_application: async ({ name, bundle_id: bid, url: urlArg, activate } = {}) => {\n      const target = name ?? bid;\n      if (!target || !/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/.test(target)) throw new ExecError(\"open_application needs a plain executable/desktop name\");\n      // activate defaults to background: on X11 a new window grabs focus, so\n      // remember the active window and hand focus back after the launch.\n      let prevWindow = null;\n      if (activate !== true) {\n        try {\n          await probeSession();\n          if (session === \"x11\" && tools.xdotool) {\n            const active = await run(\"xdotool\", [\"getactivewindow\"], { timeoutMs: 3_000 });\n            if (active.code === 0 && /^\\d+$/.test(active.stdout.trim())) prevWindow = active.stdout.trim();\n          }\n        } catch { /* no session/tools — the launch itself is still fine */ }\n      }\n      spawnDetached(target, urlArg ? [urlArg] : [], \"\", true);\n      await new Promise((r) => setTimeout(r, 500));","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L442-L478","documentation":"Thrown by list_windows when, after probing the session, none of the three supported enumeration routes is available: wmctrl for X11, swaymsg for sway, or hyprctl for hyprland. It is the terminal fallback at the end of the list_windows implementation, signaling the required window-manager tooling is absent for the detected session.","triggerScenarios":"Calling list_windows when the X11 branch lacks tools.wmctrl, and the Wayland branches lack tools.swaymsg / tools.hyprctl; or the session is a Wayland compositor unsupported by all three branches.","commonSituations":"Minimal X11 installs without wmctrl; GNOME/KDE Wayland sessions where none of the three tools exist; sway/hyprland installed headlessly without their CLI tools on PATH; running the plugin under a different user/PATH than the desktop session.","solutions":["Install wmctrl for X11 (`sudo apt install wmctrl`) or ensure swaymsg/hyprctl are on PATH for sway/hyprland.","Verify tool availability with `command -v wmctrl swaymsg hyprctl` in the plugin's runtime environment.","On unsupported Wayland compositors, run an X11/XWayland session or extend the backend — this code path has no other enumeration route.","Check probeSession's detected session; if it misidentifies X11 as wayland (or vice versa), the wrong branch's tool check fails.","For CI, pair Xvfb with wmctrl so list_windows has a usable source."],"exampleFix":"// before (sway, CLI missing from PATH)\n# swaymsg: command not found\n// after\nexport PATH=\"$PATH:/usr/bin\"  # or reinstall sway providing swaymsg\nswaymsg -t get_tree","handlingStrategy":"fallback","validationCode":"import { execFileSync } from 'child_process';\nconst has = (cmd) => { try { execFileSync('sh', ['-c', `command -v ${cmd}`], { stdio: 'ignore' }); return true; } catch { return false; } };\nfunction windowsAvailable(session) {\n  return session === 'x11' ? has('wmctrl') : (has('swaymsg') || has('hyprctl'));\n}","typeGuard":null,"tryCatchPattern":"try {\n  const { windows } = await listWindows();\n} catch (e) {\n  if (e instanceof ExecError && e.message.startsWith('list_windows needs')) {\n    return { windows: [], note: 'no supported window enumeration tool for this session' };\n  }\n  throw e;\n}","preventionTips":["Install wmctrl for X11; ensure swaymsg/hyprctl ship with sway/hyprland on PATH.","Preflight `command -v wmctrl swaymsg hyprctl` and surface install guidance at startup.","Keep the plugin process inside the desktop session user/PATH context.","For CI, combine Xvfb with wmctrl so enumeration works.","Note the unsupported-Wayland-compositor limitation in your integration docs."],"tags":["dependency","linux","windows","wmctrl","wayland"],"backgroundTag":"missing-dependency","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}