Add Windows support: CUA daemon wiring, platform-gated macOS features, NSIS packaging, .cmd CLI shims - #5
Add Windows support: CUA daemon wiring, platform-gated macOS features, NSIS packaging, .cmd CLI shims#5Agwstin wants to merge 4 commits into
Conversation
…, NSIS packaging, .cmd CLI shims - electron/cua.mjs: resolve cua-driver per platform (trycua Cua app under %LOCALAPPDATA%, PATH via where) and probe daemon liveness with 'cua-driver status' on Windows (named pipes can't be socket-probed); embedded host works on win32 via the SDK's native DLL - electron/main.mjs: gate TCC permission flows (macOS-only) and native dictation; Windows deep-links to ms-settings privacy panes; default window frame outside macOS - electron/speech.mjs + Composer: dictation stays macOS-only, mic button hidden elsewhere - electron-builder.yml: NSIS x64 target + icon.ico; mac-only Swift helpers moved to mac.extraResources so Windows builds don't require swiftc - package.json: pnpm.onlyBuiltDependencies (pnpm 10 blocks electron postinstall) + package:win script - server/drivers/cli.ts: resolve .cmd shims (npm-global CLIs on Windows can't be spawned by child_process); codex/claude drivers now detect codex.cmd correctly - README: Windows install + platform notes
…shell-less CLI spawn - server/index.ts: readCuaConnection now uses the real userData path (Electron main passes it via OMB_USER_DATA) with per-platform fallbacks — previously hardcoded ~/Library/Application Support, so local computer use silently never connected on Windows - server/drivers/claude.ts: permission broker socket is a \\.\pipe\ name on Windows (drive-letter paths are invalid pipe names, EACCES) — every permission ask used to auto-deny - server/drivers/cli.ts: resolve .cmd shims to their real JS entry and spawn process.execPath directly (no cmd.exe, no shell quoting hazards); all probes async (spawnSync was blocking the harness event loop up to 60s in generateText); `where` results cached; killProcessTree uses taskkill /T /F on Windows (process.kill(-pid) throws ESRCH and orphaned the CLI) - electron/cua.mjs: windowsHide on all child processes; daemon liveness probe is async (spawn) instead of a blocking spawnSync at startup - UI copy: 'this Mac' -> 'this computer' in Onboarding + ComputerPanel
The harness spawns the agent CLIs (claude, codex) from the Electron GUI host; without windowsHide each turn flashed a console window on Windows. Both driver spawns now pass windowsHide: true (dev probes already did).
windowsHide only hides the direct child; console-app descendants (cmd.exe for device-id probes, MCP servers like cua-driver.exe) still flash their own windows. Spawn the CLI through PowerShell 7 (pwsh) with a hidden console instead, so the entire subtree inherits it and nothing flashes. Args travel through a temp JSON file (no cmd/PowerShell quoting hazards; PS 5.1 mangles embedded quotes in --mcp-config, pwsh passes argv correctly). Falls back to a plain windowsHide spawn when pwsh is missing. detached is stripped on Windows: it maps to DETACHED_PROCESS there, which makes pwsh exit 0 immediately without running the script (surfaces as "cli exited 0 before result"). POSIX keeps it (killProcessTree uses the process group); Windows reaps the tree with taskkill /T /F. Verified end-to-end on Windows: agent turn with local computer use (get_screen_size -> 1920x1080) through the packaged app, no console windows.
|
Thanks for this — the core design here (resolve A deep review turned up a few things that block merging as-is:
Rather than round-tripping all of that, I've pushed #10 — your branch with all commits preserved, merged with current main, plus the fixes above and a portable test file for the spawn layer ( |
|
Current main already contains the Windows desktop shell, NSIS packaging, platform-gated macOS features, named-pipe permission broker, process-tree cleanup, and the portable capability contract. This branch predates those implementations and still routes npm shims through cmd.exe, which conflicts with the current no-shell security rule. It should not be merged; please close it, and move any still-missing narrowly scoped behavior into a fresh PR against current main. |
|
Thank you for this — you were first to map out what Windows support actually required, and that shaped everything that followed. Closing as superseded: Windows support landed in #17 (f3bac3a), which covers the same ground — Not a reflection on the work — three parallel Windows ports arrived and only one could land. If you spot something yours handled that main still gets wrong, please open a focused PR against current main and I'll take it seriously. |
Summary
This PR ports OpenMausBot to Windows (x64, NSIS installer) so the chat-app agents work on Windows with local computer use, and lays the groundwork for Linux. The harness was already portable Node; the macOS-specific surface was the Electron shell (TCC permission flows, Swift dictation, CuaDriver.app paths) plus packaging. Everything macOS-only is now platform-gated, and the CUA daemon wiring works in embedded mode on win32.
Changes
whereon Windows; CuaDriver.app on macOS); probe daemon liveness withcua-driver statuson Windows (named pipes can't be socket-probed). The SDK's EmbeddedCuaDriverHost works on win32 via its native DLL.userDatapath to the harness (OMB_USER_DATA).whereresults are cached, and process trees are killed with taskkill /T /F on Windows. Exact no-op on macOS/Linux.package:winscript.Testing
Verified on Windows 10/11 x64 (Node 25, pnpm 10): typecheck + build pass, the NSIS installer builds and runs, the packaged app's harness serves the UI, CUA embedded spawns its own daemon on a private named pipe, agent turns with local computer use work end-to-end (get_screen_size round-trip through the permission broker), and Claude + Codex CLIs are detected correctly (including npm-installed codex.cmd). macOS behavior is unchanged (all new code paths are gated or no-ops on POSIX).