diff --git a/apps/macos/Sources/Clawdis/Resources/Clawdis.icns b/apps/macos/Sources/Clawdis/Resources/Clawdis.icns index 3870e54f9..a86ccb43f 100644 Binary files a/apps/macos/Sources/Clawdis/Resources/Clawdis.icns and b/apps/macos/Sources/Clawdis/Resources/Clawdis.icns differ diff --git a/docs/clawdis-mac.md b/docs/clawdis-mac.md index a866cb3d8..73b5031c5 100644 --- a/docs/clawdis-mac.md +++ b/docs/clawdis-mac.md @@ -40,10 +40,11 @@ struct Response { ok: Bool; message?: String; payload?: Data } ## App UX (Clawdis) - MenuBarExtra icon only (LSUIElement; no Dock). -- Menu items: Status, Test Notification, Permissions…, **Pause Clawdis** toggle (temporarily deny privileged actions/notifications without quitting), Quit. +- 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, default sound, logging verbosity. - 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, XPC listener returns `ok=false, message="clawdis paused"` for actions that would touch TCC (notify/run/screenshot). 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. @@ -80,6 +81,12 @@ struct Response { ok: Bool; message?: String; payload?: Data } - 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/`. + ## Open questions / decisions - Where to place the dev symlink `bin/clawdis-mac` (repo root vs. `apps/macos/bin`)? - Should `runShell` support streaming stdout/stderr (XPC with AsyncSequence) or just buffered? (Start buffered; streaming later.) diff --git a/scripts/build_icon.sh b/scripts/build_icon.sh new file mode 100755 index 000000000..bd14bd2ea --- /dev/null +++ b/scripts/build_icon.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Render the macOS .icon bundle to a padded .icns like Trimmy's pipeline. +# Defaults target the Clawdis assets so you can just run the script from repo root. + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" + +ICON_FILE=${1:-"$ROOT_DIR/apps/macos/Icon.icon"} +BASENAME=${2:-Clawdis} +OUT_ROOT=${3:-"$ROOT_DIR/apps/macos/build/icon"} +XCODE_APP=${XCODE_APP:-/Applications/Xcode.app} +# Where the final .icns should live; override DEST_ICNS to change. +DEST_ICNS=${DEST_ICNS:-"$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/Clawdis.icns"} + +ICTOOL="$XCODE_APP/Contents/Applications/Icon Composer.app/Contents/Executables/ictool" +if [[ ! -x "$ICTOOL" ]]; then + ICTOOL="$XCODE_APP/Contents/Applications/Icon Composer.app/Contents/Executables/icontool" +fi +if [[ ! -x "$ICTOOL" ]]; then + echo "ictool/icontool not found. Set XCODE_APP if Xcode is elsewhere." >&2 + exit 1 +fi + +ICONSET_DIR="$OUT_ROOT/${BASENAME}.iconset" +TMP_DIR="$OUT_ROOT/tmp" +mkdir -p "$ICONSET_DIR" "$TMP_DIR" + +MASTER_ART="$TMP_DIR/icon_art_824.png" +MASTER_1024="$TMP_DIR/icon_1024.png" + +# Render inner art (no margin) with macOS Default appearance +"$ICTOOL" "$ICON_FILE" \ + --export-preview macOS Default 824 824 1 -45 "$MASTER_ART" + +# Pad to 1024x1024 with transparent border +sips --padToHeightWidth 1024 1024 "$MASTER_ART" --out "$MASTER_1024" >/dev/null + +# Generate required sizes +sizes=(16 32 64 128 256 512 1024) +for sz in "${sizes[@]}"; do + out="$ICONSET_DIR/icon_${sz}x${sz}.png" + sips -z "$sz" "$sz" "$MASTER_1024" --out "$out" >/dev/null + if [[ "$sz" -ne 1024 ]]; then + dbl=$((sz*2)) + out2="$ICONSET_DIR/icon_${sz}x${sz}@2x.png" + sips -z "$dbl" "$dbl" "$MASTER_1024" --out "$out2" >/dev/null + fi +done + +# 512x512@2x already covered by 1024; ensure it exists +cp "$MASTER_1024" "$ICONSET_DIR/icon_512x512@2x.png" + +iconutil -c icns "$ICONSET_DIR" -o "$OUT_ROOT/${BASENAME}.icns" + +mkdir -p "$(dirname "$DEST_ICNS")" +cp "$OUT_ROOT/${BASENAME}.icns" "$DEST_ICNS" + +echo "Icon.icns generated at $DEST_ICNS"