mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 19:01:47 +03:00
refactor(cli): unify on clawdis CLI + node permissions
This commit is contained in:
+38
-88
@@ -1,95 +1,57 @@
|
||||
---
|
||||
summary: "Spec for the Clawdis macOS companion menu bar app and local broker (control socket + PeekabooBridge)"
|
||||
summary: "Spec for the Clawdis macOS companion menu bar app (gateway + node broker)"
|
||||
read_when:
|
||||
- Implementing macOS app features
|
||||
- Touching broker/CLI bridging
|
||||
- Changing gateway lifecycle or node bridging on macOS
|
||||
---
|
||||
# Clawdis macOS Companion (menu bar + local broker)
|
||||
# Clawdis macOS Companion (menu bar + gateway broker)
|
||||
|
||||
Author: steipete · Status: draft spec · Date: 2025-12-05
|
||||
Author: steipete · Status: draft spec · Date: 2025-12-20
|
||||
|
||||
## Purpose
|
||||
- Single macOS menu-bar app named **Clawdis** that:
|
||||
- Shows native notifications for Clawdis/clawdis events.
|
||||
- Owns TCC prompts (Notifications, Accessibility, Screen Recording, Automation/AppleScript, Microphone, Speech Recognition).
|
||||
- Brokers privileged actions via local IPC:
|
||||
- Clawdis control socket (app-specific actions like notify/run)
|
||||
- PeekabooBridge socket (`bridge.sock`) for UI automation brokering (consumed by `peekaboo`; see `docs/mac/peekaboo.md`)
|
||||
- Provides a tiny CLI (`clawdis-mac`) that talks to the app; Node/TS shells out to it.
|
||||
- Replace the separate notifier helper pattern (Oracle) with a built-in notifier.
|
||||
- Offer a first-run experience similar to VibeTunnel’s onboarding (permissions + CLI install).
|
||||
- Runs (or connects to) the **Gateway** and exposes itself as a **node** so agents can reach macOS‑only features.
|
||||
- Hosts **PeekabooBridge** for UI automation (consumed by `peekaboo`; see `docs/mac/peekaboo.md`).
|
||||
- Installs a single CLI (`clawdis`) by symlinking the bundled binary.
|
||||
|
||||
## High-level design
|
||||
- SwiftPM package in `apps/macos/` (macOS 15+, Swift 6).
|
||||
- Targets:
|
||||
- `ClawdisIPC` (shared Codable types + helpers for app-specific commands).
|
||||
- `Clawdis` (LSUIElement MenuBarExtra app; hosts control socket + optional PeekabooBridgeHost).
|
||||
- `ClawdisCLI` (`clawdis-mac`; prints text by default, `--json` for scripts).
|
||||
- `ClawdisIPC` (shared Codable types + helpers for app‑internal actions).
|
||||
- `Clawdis` (LSUIElement MenuBarExtra app; hosts Gateway + node bridge + PeekabooBridgeHost).
|
||||
- Bundle ID: `com.steipete.clawdis`.
|
||||
- The CLI lives in the app bundle `Contents/Helpers/clawdis-mac`; dev symlink `bin/clawdis-mac` points there.
|
||||
- Node/TS layer calls the CLI; no direct privileged API calls from Node.
|
||||
- Bundled runtime binaries live under `Contents/Resources/Relay/`:
|
||||
- `clawdis-gateway` (bun‑compiled Gateway)
|
||||
- `clawdis` (bun‑compiled CLI)
|
||||
- The app symlinks `clawdis` into `/usr/local/bin` and `/opt/homebrew/bin`.
|
||||
|
||||
Note: `docs/mac/xpc.md` describes an aspirational long-term Mach/XPC architecture. The current direction for UI automation is PeekabooBridge (socket-based).
|
||||
## Gateway + node bridge
|
||||
- The mac app runs the Gateway in **local** mode (unless configured remote).
|
||||
- The mac app connects to the bridge as a **node** and advertises capabilities/commands.
|
||||
- Agent‑facing actions are exposed via `node.invoke` (no local control socket).
|
||||
|
||||
## IPC contract (ClawdisIPC)
|
||||
- Codable enums; small payloads (<1 MB enforced in listener):
|
||||
### Node commands (mac)
|
||||
- Canvas: `canvas.present|navigate|eval|snapshot|a2ui.*`
|
||||
- Camera: `camera.snap|camera.clip`
|
||||
- Screen: `screen.record`
|
||||
- System: `system.run` (shell) and `system.notify`
|
||||
|
||||
```
|
||||
enum Capability { notifications, accessibility, screenRecording, appleScript, microphone, speechRecognition }
|
||||
enum Request {
|
||||
notify(title, body, sound?)
|
||||
ensurePermissions([Capability], interactive: Bool)
|
||||
runShell(command:[String], cwd?, env?, timeoutSec?, needsScreenRecording: Bool)
|
||||
status
|
||||
}
|
||||
struct Response { ok: Bool; message?: String; payload?: Data }
|
||||
```
|
||||
- The control-socket server rejects oversize/unknown cases and validates the caller by code signature TeamID (with a `DEBUG`-only same-UID escape hatch controlled by `CLAWDIS_ALLOW_UNSIGNED_SOCKET_CLIENTS=1`).
|
||||
### Permission advertising
|
||||
- Nodes include a `permissions` map in hello/pairing.
|
||||
- The Gateway surfaces it via `node.list` / `node.describe` so agents can decide what to run.
|
||||
|
||||
UI automation is not part of `ClawdisIPC.Request`:
|
||||
- UI automation is handled via the separate PeekabooBridge socket and is surfaced by the `peekaboo` CLI (see `docs/mac/peekaboo.md`).
|
||||
## CLI (`clawdis`)
|
||||
- The **only** CLI is `clawdis` (TS/bun). There is no `clawdis-mac` helper.
|
||||
- For mac‑specific actions, the CLI uses `node.invoke`:
|
||||
- `clawdis canvas present|navigate|eval|snapshot|a2ui push|a2ui reset`
|
||||
- `clawdis nodes run --node <id> -- <command...>`
|
||||
- `clawdis nodes notify --node <id> --title ...`
|
||||
|
||||
## App UX (Clawdis)
|
||||
- MenuBarExtra icon only (LSUIElement; no Dock).
|
||||
- Menu items: Status, Permissions…, **Pause Clawdis** toggle (temporarily deny privileged actions/notifications without quitting), Quit.
|
||||
- Settings window (Trimmy-style tabs):
|
||||
- General: launch at login toggle and debug/visibility toggles (no per-user default sound; pass sounds per notification via CLI).
|
||||
- Permissions: live status + “Request” buttons for Notifications/Accessibility/Screen Recording; links to System Settings.
|
||||
- Debug (when enabled): PID/log links, restart/reveal app shortcuts, manual test notification.
|
||||
- About: version, links, license.
|
||||
- Pause behavior: matches Trimmy’s “Auto Trim” toggle. When paused, the broker returns `ok=false, message="clawdis paused"` for actions that would touch TCC. State is persisted (UserDefaults) and surfaced in menu and status view.
|
||||
- Onboarding (VibeTunnel-inspired): Welcome → What it does → Install CLI (shows `ln -s .../clawdis-mac /usr/local/bin`) → Permissions checklist with live status → Test notification → Done. Re-show when `welcomeVersion` bumps or CLI/app version mismatch.
|
||||
|
||||
## Built-in services
|
||||
- NotificationManager: UNUserNotificationCenter primary; AppleScript `display notification` fallback; respects the `--sound` value on each request.
|
||||
- PermissionManager: checks/requests Notifications, Accessibility (AX), Screen Recording (capture probe); publishes changes for UI.
|
||||
- UI automation + capture: provided by **PeekabooBridgeHost** when enabled (see `docs/mac/peekaboo.md`).
|
||||
- ShellExecutor: executes `Process` with timeout; rejects when `needsScreenRecording` and permission missing; returns stdout/stderr in payload.
|
||||
- ControlSocketServer actor: routes Request → managers; logs via OSLog.
|
||||
|
||||
## CLI (`clawdis-mac`)
|
||||
- Subcommands (text by default; `--json` for machine output; non-zero exit on failure):
|
||||
- `notify --title --body [--sound] [--priority passive|active|timeSensitive] [--delivery system|overlay|auto]`
|
||||
- `ensure-permissions --cap accessibility --cap screenRecording [--interactive]`
|
||||
- UI automation + capture: use `peekaboo …` (Clawdis hosts PeekabooBridge; see `docs/mac/peekaboo.md`)
|
||||
- `run -- cmd args... [--cwd] [--env KEY=VAL] [--timeout 30] [--needs-screen-recording]`
|
||||
- `status`
|
||||
- Nodes (bridge-connected companions):
|
||||
- `node list` — lists paired + currently connected nodes, including advertised capabilities (e.g. `canvas`, `camera`) and hardware identifiers (`deviceFamily`, `modelIdentifier`).
|
||||
- `node invoke --node <id> --command <name> [--params-json <json>]`
|
||||
- Sounds: supply any macOS alert name with `--sound` per notification; omit the flag to use the system default. There is no longer a persisted “default sound” in the app UI.
|
||||
- Priority: `timeSensitive` is best-effort and falls back to `active` unless the app is signed with the Time Sensitive Notifications entitlement.
|
||||
- Delivery: `overlay` and `auto` show an in-app toast panel (bypasses Notification Center/Focus).
|
||||
- Internals:
|
||||
- For app-specific commands (`notify`, `ensure-permissions`, `run`, `status`): build `ClawdisIPC.Request`, send over the control socket.
|
||||
- UI automation is intentionally not exposed via `clawdis-mac`; it lives behind PeekabooBridge and is surfaced by the `peekaboo` CLI.
|
||||
|
||||
## Integration with clawdis/Clawdis (Node/TS)
|
||||
- Add helper module that shells to `clawdis-mac`:
|
||||
- Prefer `ensure-permissions` before actions that need TCC.
|
||||
- Use `notify` for desktop toasts; fall back to JS notifier only if CLI missing or platform ≠ macOS.
|
||||
- Use `run` for tasks requiring privileged UI context (screen-recorded terminal runs, etc.).
|
||||
- For UI automation, shell out to `peekaboo …` (text by default; add `--json` for structured output) and rely on PeekabooBridge host selection (Peekaboo.app → Clawdis.app → local).
|
||||
## Onboarding
|
||||
- Install CLI (symlink) → Permissions checklist → Test notification → Done.
|
||||
- Remote mode skips local gateway/CLI steps.
|
||||
|
||||
## Deep links (URL scheme)
|
||||
|
||||
@@ -127,24 +89,12 @@ Notes:
|
||||
- In local mode, Clawdis will start the local Gateway if needed before issuing the request.
|
||||
- In remote mode, Clawdis will use the configured remote tunnel/endpoint.
|
||||
|
||||
## Permissions strategy
|
||||
- All TCC prompts originate from the app bundle; CLI and Node stay headless.
|
||||
- Permission checks are idempotent; onboarding surfaces missing grants and provides one-click request buttons.
|
||||
|
||||
## Build & dev workflow (native)
|
||||
- `cd native && swift build` (debug) / `swift build -c release`.
|
||||
- Run app for dev: `swift run Clawdis` (or Xcode scheme).
|
||||
- Package app + helper: `swift build -c release && swift package --allow-writing-to-directory ../dist` (tbd exact script).
|
||||
- Tests: add Swift Testing suites under `apps/macos/Tests` (especially IPC round-trips and permission probing fakes).
|
||||
|
||||
## Icon pipeline
|
||||
- Source asset lives at `apps/macos/Icon.icon` (glass .icon bundle).
|
||||
- Regenerate the bundled icns via `scripts/build_icon.sh` (uses ictool/icontool + sips), which outputs to
|
||||
`apps/macos/Sources/Clawdis/Resources/Clawdis.icns` by default. Override `DEST_ICNS` to change the target.
|
||||
The script also writes intermediate renders to `apps/macos/build/icon/`.
|
||||
- Package app + CLI: `scripts/package-mac-app.sh` (builds bun CLI + gateway).
|
||||
- Tests: add Swift Testing suites under `apps/macos/Tests`.
|
||||
|
||||
## Open questions / decisions
|
||||
- Where to place the dev symlink `bin/clawdis-mac` (repo root vs. `apps/macos/bin`)?
|
||||
- Should `runShell` support streaming stdout/stderr (IPC with AsyncSequence) or just buffered? (Start buffered; streaming later.)
|
||||
- Icon: reuse Clawdis lobster or new mac-specific glyph?
|
||||
- Sparkle updates: bundled via Sparkle; release builds point at `https://raw.githubusercontent.com/steipete/clawdis/main/appcast.xml` and enable auto-checks, while debug builds leave the feed blank and disable checks.
|
||||
- Should `system.run` support streaming stdout/stderr or keep buffered responses only?
|
||||
- Should we allow node‑side permission prompts, or always require explicit app UI action?
|
||||
|
||||
Reference in New Issue
Block a user