2025-12-05 23:54:15 +01:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
# Build and bundle Clawdis into a minimal .app we can open.
|
|
|
|
|
# Outputs to dist/Clawdis.app
|
|
|
|
|
|
|
|
|
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
|
|
|
APP_ROOT="$ROOT_DIR/dist/Clawdis.app"
|
2025-12-06 01:23:54 +01:00
|
|
|
BUILD_PATH="$ROOT_DIR/apps/macos/.build"
|
2025-12-05 23:54:15 +01:00
|
|
|
PRODUCT="Clawdis"
|
2025-12-07 00:30:40 +01:00
|
|
|
BUNDLE_ID="${BUNDLE_ID:-com.steipete.clawdis.debug}"
|
2025-12-07 01:00:47 +00:00
|
|
|
PKG_VERSION="$(cd "$ROOT_DIR" && node -p "require('./package.json').version" 2>/dev/null || echo "0.0.0")"
|
2025-12-07 00:30:40 +01:00
|
|
|
BUILD_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
|
|
|
GIT_COMMIT=$(cd "$ROOT_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
2025-12-12 17:27:11 +00:00
|
|
|
GIT_BUILD_NUMBER=$(cd "$ROOT_DIR" && git rev-list --count HEAD 2>/dev/null || echo "0")
|
2025-12-07 01:00:47 +00:00
|
|
|
APP_VERSION="${APP_VERSION:-$PKG_VERSION}"
|
2025-12-12 17:27:11 +00:00
|
|
|
APP_BUILD="${APP_BUILD:-$GIT_BUILD_NUMBER}"
|
2025-12-08 00:18:16 +01:00
|
|
|
BUILD_CONFIG="${BUILD_CONFIG:-debug}"
|
|
|
|
|
SPARKLE_PUBLIC_ED_KEY="${SPARKLE_PUBLIC_ED_KEY:-AGCY8w5vHirVfGGDGc8Szc5iuOqupZSh9pMj/Qs67XI=}"
|
|
|
|
|
SPARKLE_FEED_URL="${SPARKLE_FEED_URL:-https://raw.githubusercontent.com/steipete/clawdis/main/appcast.xml}"
|
|
|
|
|
AUTO_CHECKS=true
|
|
|
|
|
if [[ "$BUNDLE_ID" == *.debug ]]; then
|
|
|
|
|
SPARKLE_FEED_URL=""
|
|
|
|
|
AUTO_CHECKS=false
|
|
|
|
|
fi
|
2025-12-05 23:54:15 +01:00
|
|
|
|
2025-12-07 18:25:07 +01:00
|
|
|
echo "📦 Ensuring deps (pnpm install)"
|
|
|
|
|
(cd "$ROOT_DIR" && pnpm install --no-frozen-lockfile --config.node-linker=hoisted)
|
2025-12-09 17:36:24 +00:00
|
|
|
if [[ "${SKIP_TSC:-0}" != "1" ]]; then
|
|
|
|
|
echo "📦 Building JS (pnpm exec tsc)"
|
|
|
|
|
(cd "$ROOT_DIR" && pnpm exec tsc -p tsconfig.json)
|
|
|
|
|
else
|
|
|
|
|
echo "📦 Skipping TS build (SKIP_TSC=1)"
|
|
|
|
|
fi
|
2025-12-07 18:20:40 +01:00
|
|
|
|
2025-12-05 23:54:15 +01:00
|
|
|
cd "$ROOT_DIR/apps/macos"
|
|
|
|
|
|
2025-12-08 00:18:16 +01:00
|
|
|
echo "🔨 Building $PRODUCT ($BUILD_CONFIG)"
|
2025-12-20 02:08:04 +00:00
|
|
|
swift build -c "$BUILD_CONFIG" --product "$PRODUCT" --build-path "$BUILD_PATH"
|
2025-12-05 23:54:15 +01:00
|
|
|
|
2025-12-08 00:18:16 +01:00
|
|
|
BIN="$BUILD_PATH/$BUILD_CONFIG/$PRODUCT"
|
2025-12-09 01:45:56 +00:00
|
|
|
echo "pkg: binary $BIN" >&2
|
2025-12-05 23:54:15 +01:00
|
|
|
echo "🧹 Cleaning old app bundle"
|
|
|
|
|
rm -rf "$APP_ROOT"
|
|
|
|
|
mkdir -p "$APP_ROOT/Contents/MacOS"
|
|
|
|
|
mkdir -p "$APP_ROOT/Contents/Resources"
|
2025-12-07 18:20:40 +01:00
|
|
|
mkdir -p "$APP_ROOT/Contents/Resources/Relay"
|
2025-12-08 00:18:16 +01:00
|
|
|
mkdir -p "$APP_ROOT/Contents/Frameworks"
|
2025-12-05 23:54:15 +01:00
|
|
|
|
|
|
|
|
echo "📄 Writing Info.plist"
|
2025-12-06 23:46:19 +01:00
|
|
|
cat > "$APP_ROOT/Contents/Info.plist" <<PLIST
|
2025-12-05 23:54:15 +01:00
|
|
|
<?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>CFBundleIdentifier</key>
|
2025-12-06 23:46:19 +01:00
|
|
|
<string>${BUNDLE_ID}</string>
|
2025-12-07 00:59:37 +00:00
|
|
|
<key>CFBundleShortVersionString</key>
|
|
|
|
|
<string>${APP_VERSION}</string>
|
|
|
|
|
<key>CFBundleVersion</key>
|
|
|
|
|
<string>${APP_BUILD}</string>
|
2025-12-05 23:54:15 +01:00
|
|
|
<key>CFBundleName</key>
|
|
|
|
|
<string>Clawdis</string>
|
|
|
|
|
<key>CFBundleExecutable</key>
|
|
|
|
|
<string>Clawdis</string>
|
2025-12-06 02:40:49 +01:00
|
|
|
<key>CFBundleIconFile</key>
|
|
|
|
|
<string>Clawdis</string>
|
2025-12-05 23:54:15 +01:00
|
|
|
<key>CFBundlePackageType</key>
|
|
|
|
|
<string>APPL</string>
|
|
|
|
|
<key>LSMinimumSystemVersion</key>
|
|
|
|
|
<string>15.0</string>
|
|
|
|
|
<key>LSUIElement</key>
|
|
|
|
|
<true/>
|
2025-12-12 23:22:40 +00:00
|
|
|
<key>CFBundleURLTypes</key>
|
|
|
|
|
<array>
|
|
|
|
|
<dict>
|
|
|
|
|
<key>CFBundleURLName</key>
|
|
|
|
|
<string>com.steipete.clawdis.deeplink</string>
|
|
|
|
|
<key>CFBundleURLSchemes</key>
|
|
|
|
|
<array>
|
|
|
|
|
<string>clawdis</string>
|
|
|
|
|
</array>
|
|
|
|
|
</dict>
|
|
|
|
|
</array>
|
2025-12-07 00:30:40 +01:00
|
|
|
<key>ClawdisBuildTimestamp</key>
|
|
|
|
|
<string>${BUILD_TS}</string>
|
|
|
|
|
<key>ClawdisGitCommit</key>
|
|
|
|
|
<string>${GIT_COMMIT}</string>
|
2025-12-08 00:18:16 +01:00
|
|
|
<key>SUFeedURL</key>
|
|
|
|
|
<string>${SPARKLE_FEED_URL}</string>
|
|
|
|
|
<key>SUPublicEDKey</key>
|
|
|
|
|
<string>${SPARKLE_PUBLIC_ED_KEY}</string>
|
|
|
|
|
<key>SUEnableAutomaticChecks</key>
|
|
|
|
|
<${AUTO_CHECKS}/>
|
2025-12-06 00:37:46 +01:00
|
|
|
<key>NSUserNotificationUsageDescription</key>
|
|
|
|
|
<string>Clawdis needs notification permission to show alerts for agent actions.</string>
|
|
|
|
|
<key>NSScreenCaptureDescription</key>
|
|
|
|
|
<string>Clawdis captures the screen when the agent needs screenshots for context.</string>
|
2025-12-14 00:48:58 +00:00
|
|
|
<key>NSCameraUsageDescription</key>
|
|
|
|
|
<string>Clawdis can capture photos or short video clips when requested by the agent.</string>
|
2025-12-06 00:37:46 +01:00
|
|
|
<key>NSMicrophoneUsageDescription</key>
|
2025-12-06 02:10:20 +01:00
|
|
|
<string>Clawdis needs the mic for Voice Wake tests and agent audio capture.</string>
|
|
|
|
|
<key>NSSpeechRecognitionUsageDescription</key>
|
|
|
|
|
<string>Clawdis uses speech recognition to detect your Voice Wake trigger phrase.</string>
|
2025-12-07 02:34:21 +01:00
|
|
|
<key>NSAppleEventsUsageDescription</key>
|
|
|
|
|
<string>Clawdis needs Automation (AppleScript) permission to drive Terminal and other apps for agent actions.</string>
|
2025-12-21 02:17:55 +00:00
|
|
|
<key>NSAppTransportSecurity</key>
|
|
|
|
|
<dict>
|
2025-12-27 00:20:58 +01:00
|
|
|
<key>NSAllowsArbitraryLoadsInWebContent</key>
|
|
|
|
|
<true/>
|
2025-12-21 02:17:55 +00:00
|
|
|
<key>NSExceptionDomains</key>
|
|
|
|
|
<dict>
|
|
|
|
|
<key>100.100.100.100</key>
|
|
|
|
|
<dict>
|
|
|
|
|
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
|
|
|
|
<true/>
|
|
|
|
|
<key>NSIncludesSubdomains</key>
|
|
|
|
|
<true/>
|
|
|
|
|
</dict>
|
|
|
|
|
</dict>
|
|
|
|
|
</dict>
|
2025-12-05 23:54:15 +01:00
|
|
|
</dict>
|
|
|
|
|
</plist>
|
|
|
|
|
PLIST
|
|
|
|
|
|
|
|
|
|
echo "🚚 Copying binary"
|
|
|
|
|
cp "$BIN" "$APP_ROOT/Contents/MacOS/Clawdis"
|
|
|
|
|
chmod +x "$APP_ROOT/Contents/MacOS/Clawdis"
|
2025-12-21 02:06:12 +01:00
|
|
|
# SwiftPM outputs ad-hoc signed binaries; strip the signature before install_name_tool to avoid warnings.
|
|
|
|
|
/usr/bin/codesign --remove-signature "$APP_ROOT/Contents/MacOS/Clawdis" 2>/dev/null || true
|
2025-12-05 23:54:15 +01:00
|
|
|
|
2025-12-08 00:18:16 +01:00
|
|
|
SPARKLE_FRAMEWORK="$BUILD_PATH/$BUILD_CONFIG/Sparkle.framework"
|
|
|
|
|
if [ -d "$SPARKLE_FRAMEWORK" ]; then
|
|
|
|
|
echo "✨ Embedding Sparkle.framework"
|
|
|
|
|
cp -R "$SPARKLE_FRAMEWORK" "$APP_ROOT/Contents/Frameworks/"
|
|
|
|
|
chmod -R a+rX "$APP_ROOT/Contents/Frameworks/Sparkle.framework"
|
|
|
|
|
install_name_tool -add_rpath "@executable_path/../Frameworks" "$APP_ROOT/Contents/MacOS/Clawdis"
|
|
|
|
|
fi
|
|
|
|
|
|
2025-12-06 02:40:49 +01:00
|
|
|
echo "🖼 Copying app icon"
|
|
|
|
|
cp "$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/Clawdis.icns" "$APP_ROOT/Contents/Resources/Clawdis.icns"
|
|
|
|
|
|
2025-12-07 18:20:40 +01:00
|
|
|
RELAY_DIR="$APP_ROOT/Contents/Resources/Relay"
|
|
|
|
|
|
2025-12-09 18:00:01 +00:00
|
|
|
if [[ "${SKIP_GATEWAY_PACKAGE:-0}" != "1" ]]; then
|
2025-12-19 19:20:46 +01:00
|
|
|
if ! command -v bun >/dev/null 2>&1; then
|
|
|
|
|
echo "ERROR: bun missing. Install bun to package the embedded gateway." >&2
|
|
|
|
|
exit 1
|
2025-12-09 17:36:24 +00:00
|
|
|
fi
|
|
|
|
|
|
2025-12-20 19:35:29 +00:00
|
|
|
echo "🧰 Building bundled relay (bun --compile)"
|
2025-12-19 19:20:46 +01:00
|
|
|
mkdir -p "$RELAY_DIR"
|
2025-12-20 19:35:29 +00:00
|
|
|
RELAY_OUT="$RELAY_DIR/clawdis"
|
|
|
|
|
bun build "$ROOT_DIR/dist/macos/relay.js" \
|
2025-12-19 22:11:41 +01:00
|
|
|
--compile \
|
|
|
|
|
--bytecode \
|
2025-12-20 19:35:29 +00:00
|
|
|
--outfile "$RELAY_OUT" \
|
2025-12-19 22:11:41 +01:00
|
|
|
-e electron \
|
|
|
|
|
--define "__CLAWDIS_VERSION__=\\\"$PKG_VERSION\\\""
|
2025-12-20 19:35:29 +00:00
|
|
|
chmod +x "$RELAY_OUT"
|
2025-12-20 02:08:04 +00:00
|
|
|
|
2025-12-20 12:17:27 +00:00
|
|
|
echo "🎨 Copying gateway A2UI host assets"
|
|
|
|
|
rm -rf "$RELAY_DIR/a2ui"
|
|
|
|
|
cp -R "$ROOT_DIR/src/canvas-host/a2ui" "$RELAY_DIR/a2ui"
|
|
|
|
|
|
2025-12-20 12:23:53 +00:00
|
|
|
echo "🧠 Copying bundled skills"
|
|
|
|
|
rm -rf "$RELAY_DIR/skills"
|
|
|
|
|
cp -R "$ROOT_DIR/skills" "$RELAY_DIR/skills"
|
|
|
|
|
|
2025-12-19 19:20:46 +01:00
|
|
|
echo "📄 Writing embedded runtime package.json (Pi compatibility)"
|
|
|
|
|
cat > "$RELAY_DIR/package.json" <<JSON
|
|
|
|
|
{
|
|
|
|
|
"name": "clawdis-embedded",
|
|
|
|
|
"version": "$PKG_VERSION",
|
|
|
|
|
"piConfig": {
|
|
|
|
|
"name": "pi",
|
|
|
|
|
"configDir": ".pi"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
JSON
|
|
|
|
|
|
|
|
|
|
echo "🎨 Copying Pi theme payload (optional)"
|
|
|
|
|
PI_ENTRY_URL="$(cd "$ROOT_DIR" && node --input-type=module -e "console.log(import.meta.resolve('@mariozechner/pi-coding-agent'))")"
|
|
|
|
|
PI_ENTRY="$(cd "$ROOT_DIR" && node --input-type=module -e "console.log(new URL(process.argv[1]).pathname)" "$PI_ENTRY_URL")"
|
|
|
|
|
PI_DIR="$(cd "$(dirname "$PI_ENTRY")/.." && pwd)"
|
|
|
|
|
THEME_SRC="$PI_DIR/dist/modes/interactive/theme"
|
|
|
|
|
if [ -d "$THEME_SRC" ]; then
|
|
|
|
|
rm -rf "$RELAY_DIR/theme"
|
|
|
|
|
cp -R "$THEME_SRC" "$RELAY_DIR/theme"
|
|
|
|
|
else
|
|
|
|
|
echo "WARN: Pi theme dir missing at $THEME_SRC (continuing)" >&2
|
2025-12-09 17:36:24 +00:00
|
|
|
fi
|
|
|
|
|
else
|
2025-12-09 18:00:01 +00:00
|
|
|
echo "🧰 Skipping gateway payload packaging (SKIP_GATEWAY_PACKAGE=1)"
|
2025-12-07 22:46:02 +01:00
|
|
|
fi
|
|
|
|
|
|
2025-12-06 00:14:12 +01:00
|
|
|
echo "⏹ Stopping any running Clawdis"
|
|
|
|
|
killall -q Clawdis 2>/dev/null || true
|
|
|
|
|
|
2025-12-07 04:38:37 +01:00
|
|
|
echo "🔏 Signing bundle (auto-selects signing identity if SIGN_IDENTITY is unset)"
|
|
|
|
|
"$ROOT_DIR/scripts/codesign-mac-app.sh" "$APP_ROOT"
|
2025-12-06 23:46:19 +01:00
|
|
|
|
2025-12-05 23:54:15 +01:00
|
|
|
echo "✅ Bundle ready at $APP_ROOT"
|