#!/bin/bash # Build ../dist/DoTouchAI.app + a drag-install DMG from the local electron # dist + app sources. (Manual bundle construction: deterministic, no network, # no @electron/get.) set -euo pipefail cd "$(dirname "$0")/.." SRC="node_modules/electron/dist/Electron.app" OUT="../dist" APP="$OUT/DoTouchAI.app" PLIST="$APP/Contents/Info.plist" VERSION="$(node -p "require('./package.json').version")" DMG="$OUT/DoTouchAI-${VERSION}-arm64.dmg" rm -rf "$APP" mkdir -p "$OUT" "$APP/Contents/Resources/app/assets" cp -R "$SRC/." "$APP/" rm -rf "$APP/Contents/Resources/default_app.asar" # App sources — this shell has zero runtime npm deps, so node_modules stays out. cp main.js env.js service.js updater.js plugins.js package.json "$APP/Contents/Resources/app/" cp assets/trayTemplate.png assets/trayTemplate@2x.png assets/icon.icns \ "$APP/Contents/Resources/app/assets/" # Build metadata (shown in the About dialog so installs are distinguishable). node -e "require('fs').writeFileSync('$APP/Contents/Resources/app/build.json', JSON.stringify({version:'$VERSION', builtAt:new Date().toLocaleString('zh-CN',{hour12:false})}, null, 2) + '\n')" # Bundled dsh plugins (voice suite) — copied from DSWorkSpace, deps hoisted # flat next to the plugins (same layout the profile already uses), and # auto-installed into the web profile on first launch (see app/plugins.js). # Dep sources come from the live profile root (the real files — the # DSWorkSpace copies are pnpm symlinks). VOICE_SRC="/Users/eastudio/Documents/DSWorkSpace" DEP_SRC="$HOME/.dsh/profiles/web/node_modules" BUNDLED="$APP/Contents/Resources/app/plugins" mkdir -p "$BUNDLED" rm -rf "$BUNDLED"/* cp -R "$VOICE_SRC/dsh-voice-client" "$BUNDLED/dsh-voice-client" rm -rf "$BUNDLED/dsh-voice-client/node_modules" cp -R "$VOICE_SRC/dsh-voice-server" "$BUNDLED/dsh-voice-server" rm -rf "$BUNDLED/dsh-voice-server/node_modules" for dep in sherpa-onnx-node sherpa-onnx-darwin-arm64 ws; do cp -R "$DEP_SRC/$dep" "$BUNDLED/$dep" done node -e "require('fs').writeFileSync('$BUNDLED/manifest.json', JSON.stringify({ 'dsh-voice-client': { id: 'dsh-voice-client', name: 'dsh-voice-client' }, 'dsh-voice-server': { id: 'dsh-voice-server', name: 'dsh-voice-server/lib/index-v6.js' }, 'sherpa-onnx-node': { dep: true }, 'sherpa-onnx-darwin-arm64': { dep: true }, 'ws': { dep: true } }, null, 2) + '\n')" echo "bundled plugins: $(du -sh "$BUNDLED" | cut -f1) — $(ls "$BUNDLED" | tr '\n' ' ')" # Identity + icon. cp assets/icon.icns "$APP/Contents/Resources/electron.icns" plutil -replace CFBundleName -string "DoTouchAI" "$PLIST" plutil -replace CFBundleDisplayName -string "DoTouchAI" "$PLIST" plutil -replace CFBundleIdentifier -string "local.eastudio.dsh-desktop" "$PLIST" plutil -replace CFBundleShortVersionString -string "$VERSION" "$PLIST" # Ad-hoc signature: no Apple ID needed, silences Gatekeeper's unsigned-binary nag. codesign --force --sign - "$APP" >/dev/null 2>&1 || true echo "built: $APP ($(du -sh "$APP" | cut -f1))" # Drag-install DMG: the app beside a symlink to /Applications. STAGING="../.dmg-staging" rm -rf "$STAGING" mkdir -p "$STAGING" cp -R "$APP" "$STAGING/" ln -sfn /Applications "$STAGING/Applications" rm -f "$DMG" hdiutil create -volname "DoTouchAI $VERSION" -srcfolder "$STAGING" -ov -format UDZO "$DMG" >/dev/null rm -rf "$STAGING" hdiutil verify "$DMG" >/dev/null && echo "built: $DMG ($(du -sh "$DMG" | cut -f1))"