feat(computer-use): make the preflight cross-platform (win/linux)
The card was macOS-only. cua-driver also runs on Windows and Linux, so fold `cua-driver doctor` (cross-platform binary/health probes) into a single OS-aware `ready` signal: - macOS: ready == both TCC grants; keeps the permission rows + grant flow. - Windows/Linux: no TCC toggles, so ready == driver health, with a per-OS note (SmartScreen/UIAccess on Windows; X11/XWayland on Linux). `computer_use_status()` replaces the macOS-only `permissions_status()` and surfaces `platform`, `ready`, `can_grant`, and the doctor `checks` (non-ok ones render as warnings). CLI `permissions status`, the REST endpoint, and the desktop card all key off the one payload. Grant stays macOS-only (400 elsewhere — nothing to grant).
This commit is contained in:
parent
0223ea5f59
commit
2dfcead683
6 changed files with 229 additions and 125 deletions
|
|
@ -12598,27 +12598,32 @@ def main():
|
|||
sys.exit(request_permissions_grant())
|
||||
if perms_action == "status":
|
||||
import json as _json
|
||||
from tools.computer_use.permissions import permissions_status
|
||||
st = permissions_status()
|
||||
from tools.computer_use.permissions import computer_use_status
|
||||
st = computer_use_status()
|
||||
if bool(getattr(args, "json", False)):
|
||||
print(_json.dumps(st, indent=2, sort_keys=True))
|
||||
else:
|
||||
if not st["installed"]:
|
||||
print("cua-driver: not installed")
|
||||
print(" Run: hermes computer-use install")
|
||||
elif not st["platform_supported"]:
|
||||
print("Computer Use permissions are managed on macOS only.")
|
||||
else:
|
||||
def _glyph(v):
|
||||
return "✅" if v is True else ("❌" if v is False else "•")
|
||||
print(f"cua-driver: {st.get('version') or 'installed'}")
|
||||
print(f" {_glyph(st['accessibility'])} Accessibility")
|
||||
print(f" {_glyph(st['screen_recording'])} Screen Recording")
|
||||
if st.get("error"):
|
||||
print(f" ⚠ {st['error']}")
|
||||
if st["accessibility"] is not True or st["screen_recording"] is not True:
|
||||
print(" Grant: hermes computer-use permissions grant")
|
||||
sys.exit(0 if st.get("accessibility") and st.get("screen_recording") else 1)
|
||||
sys.exit(0 if st["ready"] else 1)
|
||||
if not st["platform_supported"]:
|
||||
print(f"Computer Use is not supported on {st['platform']}.")
|
||||
sys.exit(1)
|
||||
if not st["installed"]:
|
||||
print("cua-driver: not installed. Run: hermes computer-use install")
|
||||
sys.exit(1)
|
||||
glyph = lambda v: "✅" if v is True else ("❌" if v is False else "•") # noqa: E731
|
||||
print(f"cua-driver: {st['version'] or 'installed'} ({st['platform']})")
|
||||
if st["can_grant"]: # macOS TCC permissions
|
||||
print(f" {glyph(st['accessibility'])} Accessibility")
|
||||
print(f" {glyph(st['screen_recording'])} Screen Recording")
|
||||
if not st["ready"]:
|
||||
print(" Grant: hermes computer-use permissions grant")
|
||||
else: # no TCC model — readiness is driver health
|
||||
print(f" {glyph(st['ready'])} driver health (no permission toggles on {st['platform']})")
|
||||
for c in st["checks"]:
|
||||
if c["status"] != "ok":
|
||||
print(f" ⚠ {c['label']}: {c['message']}")
|
||||
if st["error"]:
|
||||
print(f" ⚠ {st['error']}")
|
||||
sys.exit(0 if st["ready"] else 1)
|
||||
computer_use_perms.print_help()
|
||||
return
|
||||
# No subcommand → show help
|
||||
|
|
|
|||
|
|
@ -10673,43 +10673,45 @@ async def run_toolset_post_setup(
|
|||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Computer Use (cua-driver) — install + macOS permission state
|
||||
# Computer Use (cua-driver) — cross-platform readiness + macOS permission grant
|
||||
#
|
||||
# Computer Use drives the Mac through cua-driver, whose Accessibility +
|
||||
# Screen Recording grants attach to cua-driver's OWN TCC identity
|
||||
# (com.trycua.driver / the installed CuaDriver.app) — not the Hermes desktop
|
||||
# app or this server. The desktop's Computer Use card reflects that state and
|
||||
# triggers a grant via the same `cua-driver permissions grant` flow the CLI
|
||||
# uses, so no Hermes-side entitlement is involved.
|
||||
# cua-driver runs on macOS, Windows, and Linux. The desktop card reflects
|
||||
# per-OS readiness: on macOS the Accessibility + Screen Recording TCC grants
|
||||
# (which attach to cua-driver's OWN identity, com.trycua.driver — not Hermes,
|
||||
# so no app entitlement is involved); elsewhere, driver health from
|
||||
# `cua-driver doctor`. The grant flow is macOS-only (no TCC toggles to request
|
||||
# on Windows/Linux).
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@app.get("/api/tools/computer-use/status")
|
||||
async def get_computer_use_status(profile: Optional[str] = None):
|
||||
"""Report cua-driver install + macOS permission state for the desktop card.
|
||||
"""Cross-platform Computer Use readiness for the desktop card.
|
||||
|
||||
See ``tools.computer_use.permissions.permissions_status`` for the payload
|
||||
shape. Read-only and fast (shells ``cua-driver permissions status``).
|
||||
See ``tools.computer_use.permissions.computer_use_status`` for the payload
|
||||
shape. Read-only and fast (shells ``cua-driver doctor`` + macOS
|
||||
``permissions status``).
|
||||
"""
|
||||
from tools.computer_use.permissions import permissions_status
|
||||
from tools.computer_use.permissions import computer_use_status
|
||||
|
||||
with _profile_scope(profile):
|
||||
return permissions_status()
|
||||
return computer_use_status()
|
||||
|
||||
|
||||
@app.post("/api/tools/computer-use/permissions/grant")
|
||||
async def grant_computer_use_permissions(profile: Optional[str] = None):
|
||||
"""Spawn ``hermes computer-use permissions grant`` as a background action.
|
||||
|
||||
``cua-driver permissions grant`` launches CuaDriver via LaunchServices so
|
||||
the macOS TCC dialog is attributed to com.trycua.driver, then waits for
|
||||
the user to approve. The frontend polls ``GET /api/actions/computer-use-
|
||||
grant/status`` for progress and re-reads ``/status`` once it exits.
|
||||
macOS-only: ``cua-driver permissions grant`` launches CuaDriver via
|
||||
LaunchServices so the TCC dialog is attributed to com.trycua.driver, then
|
||||
waits for approval. The frontend polls ``GET /api/actions/computer-use-
|
||||
grant/status`` and re-reads ``/status`` once it exits. Windows/Linux have
|
||||
no TCC toggles to grant, so this returns 400 there.
|
||||
"""
|
||||
if sys.platform != "darwin":
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Computer Use permissions are managed on macOS only.",
|
||||
detail="Computer Use permission grants are a macOS concept.",
|
||||
)
|
||||
try:
|
||||
proc = _spawn_hermes_action(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue