Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,22 @@ let package = Package(
products: [
.executable(name: "AgentBar", targets: ["AgentBar"]),
],
dependencies: [
.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.9.4"),
],
targets: [
.executableTarget(
name: "AgentBar",
path: "Sources/AgentBar"
dependencies: [
.product(name: "Sparkle", package: "Sparkle"),
],
path: "Sources/AgentBar",
linkerSettings: [
.unsafeFlags([
"-Xlinker", "-rpath",
"-Xlinker", "@executable_path/../Frameworks",
]),
]
),
]
)
33 changes: 33 additions & 0 deletions Sources/AgentBar/App/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import AppKit
import Combine
import Sparkle
import SwiftUI

@MainActor
Expand All @@ -14,10 +15,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
private var globalEventMonitor: Any?
private var cancellables = Set<AnyCancellable>()
private var lastShownCLIUpgradeAlertMessage: String?
private var updaterController: SPUStandardUpdaterController?

func applicationDidFinishLaunching(_ notification: Notification) {
NSApp.setActivationPolicy(.accessory)
NSApp.applicationIconImage = AppIcon.image()
configureUpdater()
configureStatusItem()
configurePopover()
bindStore()
Expand Down Expand Up @@ -51,6 +54,20 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
menuBarView = view
}

private func configureUpdater() {
guard Self.hasSparkleConfiguration else {
return
}

let updaterController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)
self.updaterController = updaterController
updaterController.updater.checkForUpdatesInBackground()
}

private func configurePopover() {
let popover = NSPopover()
popover.behavior = .transient
Expand Down Expand Up @@ -214,6 +231,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
let pointInView = view.convert(pointInWindow, from: nil)
return view.bounds.contains(pointInView)
}

private static var hasSparkleConfiguration: Bool {
guard
let infoDictionary = Bundle.main.infoDictionary,
let feedURL = trimmedInfoValue("SUFeedURL", in: infoDictionary),
let publicKey = trimmedInfoValue("SUPublicEDKey", in: infoDictionary)
else {
return false
}

return !feedURL.isEmpty && !publicKey.isEmpty
}

private static func trimmedInfoValue(_ key: String, in infoDictionary: [String: Any]) -> String? {
(infoDictionary[key] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
}
}

private final class VisualEffectHostingController<Content: View>: NSViewController {
Expand Down
11 changes: 11 additions & 0 deletions appcast.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>AgentBar Updates</title>
<link>https://github.com/lonewolfyx/codex-agent-bar</link>
<description>Appcast feed for AgentBar automatic updates.</description>
<language>en</language>
</channel>
</rss>
50 changes: 48 additions & 2 deletions scripts/build-dmg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ CONFIGURATION="${CONFIGURATION:-release}"
DMG_VOLUME_NAME="${DMG_VOLUME_NAME:-$APP_NAME}"
SIGN_APP="${SIGN_APP:-1}"
CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY:--}"
SPARKLE_FEED_URL="${SPARKLE_FEED_URL:-https://raw.githubusercontent.com/lonewolfyx/codex-agent-bar/main/appcast.xml}"
SPARKLE_PUBLIC_ED_KEY="${SPARKLE_PUBLIC_ED_KEY:-KUrqIsbJSH1fYUKJnDxuzKdAWmXt/Tu7JGPSCwkLGtU=}"
SPARKLE_FRAMEWORK_PATH="${SPARKLE_FRAMEWORK_PATH:-}"

ENV_VERSION_WAS_SET=0
ENV_BUILD_NUMBER_WAS_SET=0
Expand Down Expand Up @@ -64,7 +67,8 @@ Options:

Environment overrides:
APP_NAME, BUNDLE_ID, VERSION, BUILD_NUMBER, CONFIGURATION, DIST_DIR,
DMG_VOLUME_NAME, VERSION_ENV_FILE, SIGN_APP, CODE_SIGN_IDENTITY
DMG_VOLUME_NAME, VERSION_ENV_FILE, SIGN_APP, CODE_SIGN_IDENTITY,
SPARKLE_FEED_URL, SPARKLE_PUBLIC_ED_KEY, SPARKLE_FRAMEWORK_PATH

Version file:
$VERSION_ENV_FILE
Expand Down Expand Up @@ -129,6 +133,7 @@ WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/AgentBar-dmg.XXXXXX")"
APP_BUNDLE="$WORK_DIR/$APP_NAME.app"
STAGING_DIR="$WORK_DIR/dmg-staging"
TEMP_DMG="$WORK_DIR/$APP_NAME-temp.dmg"
FRAMEWORKS_DIR="$APP_BUNDLE/Contents/Frameworks"
ICONSET_DIR="$WORK_DIR/AppIcon.iconset"
APP_ICON="$WORK_DIR/AppIcon.icns"
ARROW_ICON_WORK="$WORK_DIR/DmgArrowIcon.png"
Expand Down Expand Up @@ -214,10 +219,37 @@ sign_app_bundle() {
echo "Signing app bundle with identity: $CODE_SIGN_IDENTITY"
fi

codesign --force --sign "$CODE_SIGN_IDENTITY" "$APP_BUNDLE"
codesign --force --deep --sign "$CODE_SIGN_IDENTITY" "$APP_BUNDLE"
codesign --verify --deep --strict --verbose=2 "$APP_BUNDLE"
}

copy_sparkle_framework() {
if [ -n "$SPARKLE_FRAMEWORK_PATH" ]; then
if [ ! -d "$SPARKLE_FRAMEWORK_PATH" ]; then
echo "Sparkle framework not found: $SPARKLE_FRAMEWORK_PATH" >&2
exit 1
fi
else
SPARKLE_FRAMEWORK_PATH="$(
find "$REPO_ROOT/.build" -path "*/Sparkle.framework" -type d 2>/dev/null \
| grep '/macos' \
| head -n 1
)"
fi

if [ -z "$SPARKLE_FRAMEWORK_PATH" ]; then
echo "Expected Sparkle.framework under $REPO_ROOT/.build after swift build." >&2
echo "Set SPARKLE_FRAMEWORK_PATH to the macOS Sparkle.framework path if SwiftPM stores it elsewhere." >&2
exit 1
fi

echo "Embedding Sparkle.framework..."
mkdir -p "$FRAMEWORKS_DIR"
rm -rf "$FRAMEWORKS_DIR/Sparkle.framework"
cp -R "$SPARKLE_FRAMEWORK_PATH" "$FRAMEWORKS_DIR/"
chmod -R u+w "$FRAMEWORKS_DIR/Sparkle.framework"
}

write_dmg_layout() {
base64 -D > "$STAGING_DIR/.DS_Store" <<'EOF'
AAAAAUJ1ZDEAABAAAAAIAAAAEAAAAAQKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAgAAAABAAAQAAAgACBJbG9jYmxvYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAACAAAAABAAAAQAAAAAEAAACAAAAAAQAAAQAAAAABAAACAAAAAAEAAAQAAAAAAAAAAAEAABAAAAAAAQAAIAAAAAABAABAAAAAAAEAAIAAAAAAAQABAAAAAAABAAIAAAAAAAEABAAAAAAAAQAIAAAAAAABABAAAAAAAAEAIAAAAAAAAQBAAAAAAAABAIAAAAAAAAEBAAAAAAAAAQIAAAAAAAABBAAAAAAAAAEIAAAAAAAAARAAAAAAAAABIAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAEAsAAABFAAAECgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBERTREIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAIAAAAGAAAAAAAAAAAQAAAIAAAAABAAABAAAAAAEAAAIAAAAAAAAAAAIAAAgAAAAYAAAAAAAAAAABAAAgAAAAAAEAAEAAAAAAAQAAgAAAAAABAAEAAAAAAAEAAgAAAAAAAQAEAAAAAAABAAgAAAAAAAEAEAAAAAAAAQAgAAAAAAABAEAAAAAAAAEAgAAAAAAAAQEAAAAAAAABAgAAAAAAAAEEAAAAAAAAAQgAAAAAAAABEAAAAAAAAAEgAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
Expand Down Expand Up @@ -254,9 +286,11 @@ rm -rf "$DMG_PATH"
mkdir -p \
"$APP_BUNDLE/Contents/MacOS" \
"$APP_BUNDLE/Contents/Resources" \
"$FRAMEWORKS_DIR" \
"$STAGING_DIR" \
"$(dirname -- "$DMG_PATH")"
cp "$EXECUTABLE" "$APP_BUNDLE/Contents/MacOS/$APP_NAME"
copy_sparkle_framework

echo "Preparing app icon..."
mkdir -p "$ICONSET_DIR"
Expand Down Expand Up @@ -307,10 +341,22 @@ cat > "$APP_BUNDLE/Contents/Info.plist" <<EOF
<true/>
<key>NSHighResolutionCapable</key>
<true/>
<key>SUAutomaticallyUpdate</key>
<true/>
<key>SUEnableAutomaticChecks</key>
<true/>
<key>SUFeedURL</key>
<string>$SPARKLE_FEED_URL</string>
<key>SUPublicEDKey</key>
<string>$SPARKLE_PUBLIC_ED_KEY</string>
</dict>
</plist>
EOF

if [ -z "$SPARKLE_PUBLIC_ED_KEY" ]; then
echo "Warning: SPARKLE_PUBLIC_ED_KEY is empty; automatic updates will be disabled in this build." >&2
fi

sign_app_bundle

echo "Preparing DMG staging directory..."
Expand Down
128 changes: 128 additions & 0 deletions scripts/update-appcast.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env sh

set -eu

REPO_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
VERSION_ENV_FILE="${VERSION_ENV_FILE:-$REPO_ROOT/version.env}"

APP_NAME="${APP_NAME:-AgentBar}"
DIST_DIR="${DIST_DIR:-$REPO_ROOT/dist}"
APPCAST_PATH="${APPCAST_PATH:-$REPO_ROOT/appcast.xml}"
SPARKLE_GENERATE_APPCAST="${SPARKLE_GENERATE_APPCAST:-generate_appcast}"

VERSION="1.0.0"
BUILD_NUMBER="1"
if [ -f "$VERSION_ENV_FILE" ]; then
. "$VERSION_ENV_FILE"
fi

RELEASE_TAG="${RELEASE_TAG:-v$VERSION}"
DMG_PATH="${DMG_PATH:-$DIST_DIR/$APP_NAME-$VERSION.dmg}"
DOWNLOAD_URL_PREFIX="${DOWNLOAD_URL_PREFIX:-https://github.com/lonewolfyx/codex-agent-bar/releases/download/$RELEASE_TAG/}"

usage() {
cat <<EOF
Usage: $(basename "$0") [options]

Generates appcast.xml for the current DMG using Sparkle's generate_appcast tool.

Options:
-d, --dmg PATH DMG to publish. Default: $DMG_PATH
-o, --output PATH Appcast output path. Default: $APPCAST_PATH
-t, --tag TAG GitHub release tag. Default: $RELEASE_TAG
-u, --download-url URL Download URL prefix. Default: $DOWNLOAD_URL_PREFIX
-h, --help Show this help.

Environment overrides:
APP_NAME, DIST_DIR, VERSION_ENV_FILE, DMG_PATH, APPCAST_PATH,
RELEASE_TAG, DOWNLOAD_URL_PREFIX, SPARKLE_GENERATE_APPCAST
EOF
}

while [ "$#" -gt 0 ]; do
case "$1" in
-d|--dmg)
if [ "$#" -lt 2 ]; then
echo "Missing value for $1" >&2
exit 1
fi
DMG_PATH="$2"
shift 2
;;
-o|--output)
if [ "$#" -lt 2 ]; then
echo "Missing value for $1" >&2
exit 1
fi
APPCAST_PATH="$2"
shift 2
;;
-t|--tag)
if [ "$#" -lt 2 ]; then
echo "Missing value for $1" >&2
exit 1
fi
RELEASE_TAG="$2"
DOWNLOAD_URL_PREFIX="https://github.com/lonewolfyx/codex-agent-bar/releases/download/$RELEASE_TAG/"
shift 2
;;
-u|--download-url)
if [ "$#" -lt 2 ]; then
echo "Missing value for $1" >&2
exit 1
fi
DOWNLOAD_URL_PREFIX="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
esac
done

if [ ! -f "$DMG_PATH" ]; then
echo "Expected DMG not found: $DMG_PATH" >&2
exit 1
fi

if ! command -v "$SPARKLE_GENERATE_APPCAST" >/dev/null 2>&1; then
CANDIDATE="$(
find "$REPO_ROOT/.build" -name generate_appcast -type f 2>/dev/null \
| head -n 1
)"
if [ -n "$CANDIDATE" ]; then
SPARKLE_GENERATE_APPCAST="$CANDIDATE"
else
echo "Missing Sparkle generate_appcast tool." >&2
echo "Install Sparkle tools or set SPARKLE_GENERATE_APPCAST=/path/to/generate_appcast." >&2
exit 1
fi
fi

WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/AgentBar-appcast.XXXXXX")"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT HUP INT TERM

cp "$DMG_PATH" "$WORK_DIR/"

"$SPARKLE_GENERATE_APPCAST" \
--download-url-prefix "$DOWNLOAD_URL_PREFIX" \
"$WORK_DIR"

if [ ! -f "$WORK_DIR/appcast.xml" ]; then
echo "generate_appcast did not create appcast.xml" >&2
exit 1
fi

mkdir -p "$(dirname -- "$APPCAST_PATH")"
cp "$WORK_DIR/appcast.xml" "$APPCAST_PATH"

echo "Updated: $APPCAST_PATH"
Loading