Replaces the original shannoncoat.sh entirely with in-process Swift. The script stopped earning its keep once the rest went native, and being a persistent process rather than a one-shot CLI is what later makes live window tracking possible at all. - ProfileStore: JSON config at ~/.shannoncoat/<name>.json (was hand-rolled YAML), with ~ expansion, paths relative to the config dir, and name/dir-collision validation in one place. - ProcessInspector: sysctl(KERN_PROC_ALL/KERN_PROCARGS2) enumeration instead of shelling out to pgrep. - ClaudeControl: launch via Process, focus via direct Accessibility calls (unhide, un-minimize, poll-for-window, AXRaise) instead of AppleScript, and a quit that respects Claude's own termination handling rather than unconditionally SIGKILLing after a flat 5s timeout. - LiveState: NSWorkspace notification-driven state with no polling timer, so the menu bar reflects reality within about a second — including changes made outside the app entirely. - ManageWindow: one non-modal window replacing what would otherwise be a string of separate popup alerts, with inline add/remove and directory pickers. - LaunchAtLogin / UpdateChecker: SMAppService login-item toggle, and a minimal VERSION-file update check that alerts on a manual check and posts a quiet notification on the automatic one. Also drops the standalone CLI in favour of GUI-only, and adds a placeholder app icon drawn from vector shapes rather than composited on top of Claude's own icon assets. Claude Desktop is located at runtime rather than assumed: a path the user picked previously, then /Applications, then a per-user ~/Applications install, each accepted only if it actually contains the executable. If none match, launching a profile asks the user to locate it once and remembers the answer — a launch that silently does nothing gives them no way to work out what's wrong.
61 lines
2.6 KiB
Bash
Executable File
61 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Builds "shannoncoat.app" — a menu bar app (no Dock icon, no window) with a
|
|
# custom icon (icon/AppIcon.icns — see icon/generate-icon.swift) for
|
|
# Finder/Spotlight. It stays running in the menu bar: click the status item
|
|
# to switch profiles, or open Manage Profiles… (Cmd+,) to add/remove one.
|
|
# Launch at Login is a toggle inside the app itself.
|
|
#
|
|
# Builds into ./.build (gitignored) rather than installing straight into an
|
|
# Applications dir — copy/drag the .app from there yourself. It's a fully
|
|
# native, self-contained bundle — no bundled script, so copying it anywhere
|
|
# after the build is safe.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SOURCES_DIR="$SCRIPT_DIR/Sources"
|
|
VERSION_FILE="$SCRIPT_DIR/VERSION"
|
|
ICON_SRC="$SCRIPT_DIR/icon/AppIcon.icns"
|
|
OUT_DIR="${1:-$SCRIPT_DIR/.build}"
|
|
APP="$OUT_DIR/shannoncoat.app"
|
|
|
|
# Read from the repo's VERSION file so the .app and the script it bundles
|
|
# never report different numbers.
|
|
VERSION="$(cat "$VERSION_FILE" 2>/dev/null)"
|
|
[[ -n "$VERSION" ]] || { echo "error: couldn't read $VERSION_FILE" >&2; exit 1; }
|
|
|
|
mkdir -p "$OUT_DIR" "$APP/Contents/MacOS" "$APP/Contents/Resources"
|
|
|
|
[[ -f "$ICON_SRC" ]] || { echo "error: $ICON_SRC missing (see icon/generate-icon.swift)" >&2; exit 1; }
|
|
cp "$ICON_SRC" "$APP/Contents/Resources/AppIcon.icns"
|
|
|
|
cat >"$APP/Contents/Info.plist" <<PLIST
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CFBundleName</key><string>shannoncoat</string>
|
|
<key>CFBundleDisplayName</key><string>shannoncoat</string>
|
|
<key>CFBundleIdentifier</key><string>com.local.shannoncoat</string>
|
|
<key>CFBundleVersion</key><string>$VERSION</string>
|
|
<key>CFBundleShortVersionString</key><string>$VERSION</string>
|
|
<key>CFBundlePackageType</key><string>APPL</string>
|
|
<key>CFBundleExecutable</key><string>launcher</string>
|
|
<key>CFBundleIconFile</key><string>AppIcon</string>
|
|
<key>LSUIElement</key><true/>
|
|
<key>NSHighResolutionCapable</key><true/>
|
|
</dict>
|
|
</plist>
|
|
PLIST
|
|
|
|
command -v swiftc >/dev/null || { echo "error: swiftc not found (install Xcode Command Line Tools: xcode-select --install)" >&2; exit 1; }
|
|
|
|
# VERSION travels in Resources (not baked into the binary) so the About
|
|
# panel and the update checker read the same file this script stamped into
|
|
# Info.plist above.
|
|
cp "$VERSION_FILE" "$APP/Contents/Resources/VERSION"
|
|
swiftc -O "$SOURCES_DIR"/*.swift -o "$APP/Contents/MacOS/launcher"
|
|
|
|
touch "$APP"
|
|
echo "Built: $APP"
|
|
echo "Copy it to /Applications (or ~/Applications) to install."
|