Skip to content

Windows: is_stream_deck_app_running()/stop_stream_deck_app() are Darwin-only stubs, silently defeating write_page's safety check #74

Description

@okkon24

Summary

profile_manager.py (confirmed in the published PyPI 0.3.0 release) guards write_page against clobbering by the running Elgato app like this:

def is_stream_deck_app_running() -> bool:
    if sys.platform != "darwin":
        return False
    ...

def stop_stream_deck_app(*, graceful_timeout: float = 3.0) -> dict[str, Any]:
    if sys.platform != "darwin":
        return {"stopped": False, "graceful": [], "forced": [], "reason": "non-darwin platform"}
    ...

Both functions unconditionally treat every non-macOS platform as "app not running," and write_page's guard is:

if is_stream_deck_app_running():
    if not auto_quit_app:
        raise StreamDeckAppRunningError(...)
    ...

On Windows this branch is never entered, regardless of whether the Stream Deck app is actually running and regardless of auto_quit_app. The README documents Windows as a supported target for the default profile-writer mode ("the Elgato Stream Deck desktop app, which is available on macOS and Windows") and explicitly warns that "The Elgato desktop app keeps profiles in memory and can overwrite on-disk manifest edits when it quits" — but on Windows the safeguard against exactly that scenario silently does nothing.

Impact

Calling streamdeck_write_page on Windows while the Stream Deck app is running does not raise StreamDeckAppRunningError and appears to succeed. The on-disk edit can later be silently reverted the next time the user quits/restarts the Stream Deck app normally, with no error at write time and no indication anything was lost.

Repro

  1. On Windows, with the Elgato Stream Deck app running (StreamDeck.exe in Task Manager).
  2. Call ProfileManager().write_page(...) (or the streamdeck_write_page MCP tool) without stopping the app first.
  3. No StreamDeckAppRunningError is raised; the manifest is written to disk immediately.
  4. Quit/restart the Stream Deck app normally — it may overwrite the on-disk manifest with its in-memory state, discarding the edit from step 2/3 with no warning.

Suggested fix

Implement is_stream_deck_app_running() / stop_stream_deck_app() for Windows too, e.g. via psutil or tasklist/taskkill (the real process name is StreamDeck.exe, not Stream Deck/Elgato Stream Deck as used in the current STREAM_DECK_APP_PROCESS_NAMES for the macOS pgrep/osascript/killall calls). Happy to send a PR if useful — worked around it locally in the meantime with:

Stop-Process -Name StreamDeck -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
# ... call write_page ...
Start-Process "C:\Program Files\Elgato\StreamDeck\StreamDeck.exe"

Related, smaller Windows gaps noticed while debugging this

  • create_action raises ProfileValidationError unconditionally on sys.platform == "win32" (POSIX-only .sh + chmod implementation). A path-based button (com.elgato.streamdeck.system.open) works as a substitute for simple cases, but there's no Windows equivalent for "create a new script-backed action" the way .sh works on POSIX.
  • restart_app also raises on any non-macOS platform, so after a write the app must be relaunched manually on Windows (matches the README's note, just flagging it's a hard error rather than a no-op).

Environment

  • streamdeck-mcp 0.3.0 (via uvx streamdeck-mcp)
  • Windows 11
  • Elgato Stream Deck app (Windows), ProfilesV3

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions