macOS agent Round 2: ScreenCaptureKit remote desktop + install/uninstall + CI #13
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
hex/zeno-rmm!13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/macos-agent-round2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
macOS agent Round 2: real remote desktop (ScreenCaptureKit capture + CGEvent
input), LaunchDaemon install/uninstall,
.pkgpackaging, and aForgejo-self-hosted CI job. Complements
0cc2c2d(server-side macOSdownload/deploy plumbing, already on
main) — that commit's author calledthis branch out by name as the agent-side counterpart.
MacCapture— ScreenCaptureKit main-display stream (BGRA→RGBA,~30fps), bridged to the existing pull-based
Capture::next_framecontractvia a bounded
tokio::mpscchannel. Emptydisplays()+ actionableunavailable_reason()on missing Screen Recording permission or macOS<12.3, matching
LinuxCapture's contract.MacInput— CGEvent posted viakCGHIDEventTap, gated onAXIsProcessTrusted()(Accessibility). Deviated from the brief's suggested"probe with a no-op CGEventCreate" gate: that probe can't actually detect a
missing grant (
CGEventCreate*always succeeds regardless ofauthorization;
CGEventPostreturns void). Fixed US-layoutCGKeyCodetable for non-printable keys;
Printableroutes throughCGEventKeyboardSetUnicodeStringfor correct Unicode text on any layout.floor), client-side, before the redeem call.
zeno-agent install/uninstallCLI subcommands(LaunchDaemon, root-required). Also fixed the pre-existing
server-triggered self-uninstall path, which only knew about systemd and
silently no-op'd on macOS instead of unloading the LaunchDaemon.
packaging/macos/build-pkg.sh→dist/zeno-agent-<version>-aarch64.pkg.macos-agentjob in.github/workflows/ci.yml, adapted forthis repo's actual Forgejo self-hosted setup (not the GitHub-hosted
macos-latest+ marketplace actions the original brief assumed — this repohas neither). Deliberately excluded from
publish'sneeds:so it can'tblock the Windows/Linux/server pipeline while no runner carries the
macoslabel yet.docs/macos-agent.md(shipped/skipped scope, TCCpermissions, verification checklist);
docs/roadmap.mdupdated.⚠️ Verification status — read before merging
This code has not been compiled. Authored on a Linux host with no Apple
toolchain — confirmed the hard way: even
cargo check --target aarch64-apple-darwinfails before reaching this crate's code, becausering's (transitive, unrelated) assembly build script needs a real Applecc. There is no way to get compiler feedback onobjc2/ScreenCaptureKit/CGEvent bindings from this box.
Verified:
objc2dependency graph resolves foraarch64-apple-darwin(
cargo metadata --filter-platform).cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspace --all-targetsall pass on this host (all new macOS code is#[cfg(target_os = "macos")]-gated).0cc2c2dwith no conflicts.Not verified (exact
objc2-screen-capture-kit/objc2-core-graphics0.3.2binding signatures,
.pkgbuild on realpkgbuild,launchctlidempotency-string matching, whether ScreenCaptureKit's completion handlers
fire correctly without a Cocoa run loop) — see
docs/macos-agent.md'sVerification status section for the full list. Registering a Forgejo
runner with the
macoslabel and pushing is the fastest way to get realcompiler feedback — expect a fixup round.
Test plan
macoslabelmacos-agentCI job for compile errors, fixsudo installer -pkg dist/zeno-agent-*.pkg -target /on a real M-series Macsudo zeno-agent install, grant Screen Recording + Accessibility + Input Monitoring,sudo launchctl kickstart -k system/com.zeno.agentsudo zeno-agent uninstall, confirm LaunchDaemon/plist/binary gone🤖 Generated with Claude Code
Pull request closed