Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
072963b
Fix model router failure cases: Apple fallback state leak and Claude …
devin-ai-integration[bot] Jun 7, 2026
62e32ef
Add inline STT engine badge (DG / APL) to voice transcription UI
devin-ai-integration[bot] Jun 7, 2026
029d991
feat: add music mini-player banner to chat view
devin-ai-integration[bot] Jun 7, 2026
e8d95b1
Add media ducking and resumption for voice sessions
devin-ai-integration[bot] Jun 7, 2026
5926a5a
Merge pull request #68 from getathelas/devin/1780810685-fix-model-rou…
theashbhat Jun 7, 2026
38afaed
Merge pull request #69 from getathelas/devin/1780811927-stt-engine-badge
theashbhat Jun 7, 2026
87f5d99
Merge pull request #70 from getathelas/devin/1780814474-music-mini-pl…
theashbhat Jun 7, 2026
0557d46
Merge pull request #71 from getathelas/devin/1780814696-media-ducking
theashbhat Jun 7, 2026
17b4e36
made changes to improve how the vm handles crons (#75)
theashbhat Jun 7, 2026
9c53621
feat(push): register APNs token with backend via decoupled PushBridge
ashbhat Jun 6, 2026
e54a29c
fixed the typed annotation for stt
ashbhat Jun 7, 2026
74e05cb
stt rendered under cell
ashbhat Jun 7, 2026
e0bd6d9
Merge pull request #76 from getathelas/feat/stt_improvements
theashbhat Jun 7, 2026
ed6b07d
Fix playlist/album playback: support library IDs and append queue mode
devin-ai-integration[bot] Jun 7, 2026
96ba251
Fix audio ducking/resume: deactivate session with .notifyOthersOnDeac…
devin-ai-integration[bot] Jun 7, 2026
bf6264c
feat: Add Google Workspace integration (Drive, Gmail, Calendar)
devin-ai-integration[bot] Jun 8, 2026
87ac9ee
feat: Stories / HTML Infographic prototype
devin-ai-integration[bot] Jun 8, 2026
af9d0be
Merge branch 'devin/1780878387-google-workspace-integration' of githu…
ashbhat Jun 8, 2026
790c887
Merge branch 'devin/1780875316-fix-audio-ducking-resume' of github.co…
ashbhat Jun 8, 2026
600ebcc
Merge branch 'devin/1780873772-fix-playlist-album-playback' of github…
ashbhat Jun 8, 2026
a88a788
feat(mac): voice parity, shared skills, and Stories on Mac
ashbhat Jun 8, 2026
0ccad26
Merge pull request #80 from getathelas/devin/1780880580-stories-html-…
theashbhat Jun 9, 2026
8e7bc4e
feat: Add iOS 27 App Intents (AskLoop, CaptureToLoop, LoopRemember, S…
devin-ai-integration[bot] Jun 10, 2026
23d1d5d
feat: Add anti-loop / duplicate tool-call guard
devin-ai-integration[bot] Jun 10, 2026
fa68913
fix: reliable queue append and playlist creation on iOS 27
devin-ai-integration[bot] Jun 11, 2026
3fde6bb
added improved support for browser-tool (#85)
theashbhat Jun 11, 2026
19d3dfd
fix: self-heal blank screen after tab switch / iCloud sync
devin-ai-integration[bot] Jun 11, 2026
fea1f69
added improved support for dragging cells to see times
ashbhat Jun 13, 2026
5394573
Managed loop Support (#91)
theashbhat Jun 15, 2026
efe35b7
Merge branch 'develop' of github.com:getathelas/LoopHarness into develop
ashbhat Jun 15, 2026
0ff07f0
fixed code in convo
ashbhat Jun 16, 2026
1ba8283
feat: Add share toolbar to markdown preview surfaces
devin-ai-integration[bot] Jun 17, 2026
345ee78
Merge branch 'devin/1781671199-markdown-share-toolbar' of github.com:…
ashbhat Jun 17, 2026
8b23634
latest code
ashbhat Jun 17, 2026
fa20743
feat: Add GLM 5.2 as a selectable Fireworks model
devin-ai-integration[bot] Jun 20, 2026
3a025f9
improving card support
ashbhat Jun 20, 2026
df27125
Merge branch 'devin/1781934191-add-glm-5p2-model' of github.com:getat…
ashbhat Jun 20, 2026
805f6eb
fixed the toolbar crash
ashbhat Jun 20, 2026
d3d9b9c
Merge branch 'devin/1781193527-fix-music-append-and-playlist' of gith…
ashbhat Jun 20, 2026
11e9e3f
Merge branch 'devin/1781115653-anti-loop-guard' of github.com:getathe…
ashbhat Jun 20, 2026
2935710
fixed issues around markdown and pulled in more branches
ashbhat Jun 20, 2026
8cce976
added improved support for mac
ashbhat Jun 20, 2026
a54f6e3
Merge branch 'devin/1781072115-ios27-app-intents' of github.com:getat…
ashbhat Jun 20, 2026
d5d11aa
fixed iOS 27 build bugs
ashbhat Jun 20, 2026
aa0d8fb
Merge branch 'devin/1781200840-fix-tab-switch-sync-bug' of github.com…
ashbhat Jun 20, 2026
32f8b77
added improved image search and improved card support
ashbhat Jun 20, 2026
9aa6780
Merge pull request #95 from getathelas/dev/jun16
gandalf-the-engineer Jun 20, 2026
843230a
site: route Mac download CTA to latest release
ashbhat Jun 20, 2026
94606e6
Merge pull request #97 from getathelas/website/mac-release-cta-develop
gandalf-the-engineer Jun 20, 2026
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
327 changes: 193 additions & 134 deletions .github/workflows/release-mac.yml
Original file line number Diff line number Diff line change
@@ -1,134 +1,193 @@
# Disabled until Apple signing/notarization secrets are added.
# xcrun notarytool --wait will hang the runner with no diagnostics if secrets are missing.
# Re-enable by uncommenting once the following repo secrets exist:
# APPLE_ID, APPLE_APP_PASSWORD, APPLE_TEAM_ID,
# MACOS_CERTIFICATE_P12_BASE64, MACOS_CERTIFICATE_PASSWORD, MACOS_KEYCHAIN_PASSWORD
#
# name: release-mac
#
# on:
# push:
# branches: [main]
# workflow_dispatch:
#
# permissions:
# contents: write
#
# concurrency:
# group: release-mac
# cancel-in-progress: false
#
# jobs:
# build-and-release:
# name: Build, sign, notarize, release LoopMac
# runs-on: macos-14
# env:
# APPLE_ID: ${{ secrets.APPLE_ID }}
# APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
# APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# SCHEME: LoopMac
# APP_NAME: Loop
# BUILD_DIR: build
# ARCHIVE_PATH: build/LoopMac.xcarchive
# EXPORT_PATH: build/export
# steps:
# - name: Checkout
# uses: actions/checkout@v4
#
# - name: Select Xcode
# run: sudo xcode-select -s /Applications/Xcode_15.4.app
#
# - name: Write Secrets.xcconfig from APPLE_TEAM_ID
# run: |
# printf 'DEVELOPMENT_TEAM = %s\n' "$APPLE_TEAM_ID" > Secrets.xcconfig
#
# - name: Import Developer ID signing certificate
# uses: apple-actions/import-codesign-certs@v3
# with:
# p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }}
# p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
# keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
#
# - name: Stamp build number from run number
# run: |
# cd Loop.xcodeproj/..
# xcrun agvtool new-version -all "${{ github.run_number }}"
#
# - name: Generate ExportOptions.plist
# run: |
# cat > ExportOptions.plist <<EOF
# <?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>method</key><string>developer-id</string>
# <key>teamID</key><string>${APPLE_TEAM_ID}</string>
# <key>signingStyle</key><string>manual</string>
# <key>signingCertificate</key><string>Developer ID Application</string>
# </dict>
# </plist>
# EOF
#
# - name: Archive
# run: |
# xcodebuild \
# -project Loop.xcodeproj \
# -scheme "$SCHEME" \
# -configuration Release \
# -archivePath "$ARCHIVE_PATH" \
# -destination 'generic/platform=macOS' \
# archive
#
# - name: Export signed .app
# run: |
# xcodebuild -exportArchive \
# -archivePath "$ARCHIVE_PATH" \
# -exportOptionsPlist ExportOptions.plist \
# -exportPath "$EXPORT_PATH"
#
# - name: Notarize .app
# run: |
# APP_PATH="$EXPORT_PATH/$APP_NAME.app"
# ZIP_PATH="$BUILD_DIR/$APP_NAME.zip"
# ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
# xcrun notarytool submit "$ZIP_PATH" \
# --apple-id "$APPLE_ID" \
# --password "$APPLE_APP_PASSWORD" \
# --team-id "$APPLE_TEAM_ID" \
# --wait
# xcrun stapler staple "$APP_PATH"
#
# - name: Install create-dmg
# run: brew install create-dmg
#
# - name: Build DMG
# run: |
# DMG_PATH="$BUILD_DIR/$APP_NAME-${{ github.run_number }}.dmg"
# create-dmg \
# --volname "$APP_NAME" \
# --window-size 600 400 \
# --icon "$APP_NAME.app" 175 190 \
# --app-drop-link 425 190 \
# --codesign "Developer ID Application" \
# "$DMG_PATH" \
# "$EXPORT_PATH/$APP_NAME.app"
# echo "DMG_PATH=$DMG_PATH" >> "$GITHUB_ENV"
#
# - name: Notarize DMG
# run: |
# xcrun notarytool submit "$DMG_PATH" \
# --apple-id "$APPLE_ID" \
# --password "$APPLE_APP_PASSWORD" \
# --team-id "$APPLE_TEAM_ID" \
# --wait
# xcrun stapler staple "$DMG_PATH"
#
# - name: Create GitHub Release
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run: |
# TAG="v1.0-build${{ github.run_number }}"
# gh release create "$TAG" \
# "$DMG_PATH" \
# --title "Loop 1.0 (build ${{ github.run_number }})" \
# --notes "Auto-built from ${{ github.sha }}"
# Builds, signs, notarizes, and publishes the LoopMac app + a Sparkle auto-update feed.
#
# Required repo secrets:
# APPLE_ID, APPLE_APP_PASSWORD, APPLE_TEAM_ID — notarization (notarytool)
# MACOS_CERTIFICATE_P12_BASE64 — Developer ID Application cert (base64 .p12)
# MACOS_CERTIFICATE_PASSWORD — password for the .p12
# MACOS_KEYCHAIN_PASSWORD — ephemeral CI keychain password
# SPARKLE_ED_PRIVATE_KEY — Sparkle EdDSA private key (export with
# `generate_keys -x private-key.pem`, paste file contents)
#
# Outputs:
# - Per-build GitHub Release `v1.0-build<run>` with `Loop-<run>.dmg` (human download)
# and `Loop-<run>.zip` (the Sparkle update payload).
# - A fixed `appcast` release whose `appcast.xml` asset the app polls via SUFeedURL.
# The app's Info.plist SUFeedURL must point at:
# https://github.com/getathelas/LoopHarness/releases/download/appcast/appcast.xml

name: release-mac

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: write

concurrency:
group: release-mac
cancel-in-progress: false

jobs:
build-and-release:
name: Build, sign, notarize, release LoopMac
runs-on: macos-14
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
SCHEME: Loop_MacOS
APP_NAME: Loop
# Actual product wrapper name (PRODUCT_NAME = LoopMac); distinct from the
# user-facing APP_NAME used for DMG/zip filenames and the DMG volume.
APP_BUNDLE: LoopMac
SPARKLE_VERSION: "2.9.2"
BUILD_DIR: build
ARCHIVE_PATH: build/LoopMac.xcarchive
EXPORT_PATH: build/export
DOWNLOAD_REPO: getathelas/LoopHarness
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_15.4.app

- name: Write Secrets.xcconfig from APPLE_TEAM_ID
run: |
printf 'DEVELOPMENT_TEAM = %s\n' "$APPLE_TEAM_ID" > Secrets.xcconfig

- name: Import Developer ID signing certificate
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}

- name: Stamp build number from run number
run: |
xcrun agvtool new-version -all "${{ github.run_number }}"

- name: Generate ExportOptions.plist
run: |
cat > ExportOptions.plist <<EOF
<?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>method</key><string>developer-id</string>
<key>teamID</key><string>${APPLE_TEAM_ID}</string>
<key>signingStyle</key><string>manual</string>
<key>signingCertificate</key><string>Developer ID Application</string>
</dict>
</plist>
EOF

- name: Archive
run: |
xcodebuild \
-project Loop.xcodeproj \
-scheme "$SCHEME" \
-configuration Release \
-archivePath "$ARCHIVE_PATH" \
-destination 'generic/platform=macOS' \
archive

- name: Export signed .app
run: |
xcodebuild -exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportOptionsPlist ExportOptions.plist \
-exportPath "$EXPORT_PATH"

- name: Notarize and staple .app
run: |
APP_PATH="$EXPORT_PATH/$APP_BUNDLE.app"
NOTARIZE_ZIP="$BUILD_DIR/notarize.zip"
ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_ZIP"
xcrun notarytool submit "$NOTARIZE_ZIP" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$APP_PATH"

- name: Install create-dmg
run: brew install create-dmg

- name: Build and notarize DMG
run: |
DMG_PATH="$BUILD_DIR/$APP_NAME-${{ github.run_number }}.dmg"
create-dmg \
--volname "$APP_NAME" \
--window-size 600 400 \
--icon "$APP_BUNDLE.app" 175 190 \
--app-drop-link 425 190 \
--codesign "Developer ID Application" \
"$DMG_PATH" \
"$EXPORT_PATH/$APP_BUNDLE.app"
xcrun notarytool submit "$DMG_PATH" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$DMG_PATH"
echo "DMG_PATH=$DMG_PATH" >> "$GITHUB_ENV"

- name: Package Sparkle update zip (stapled .app)
run: |
# Re-zip AFTER stapling so the Sparkle payload carries the notarization
# ticket (the notarize.zip above held the un-stapled app).
ZIP_PATH="$BUILD_DIR/$APP_NAME-${{ github.run_number }}.zip"
ditto -c -k --keepParent "$EXPORT_PATH/$APP_BUNDLE.app" "$ZIP_PATH"
echo "ZIP_PATH=$ZIP_PATH" >> "$GITHUB_ENV"

- name: Download Sparkle CLI tools
run: |
curl -fsSL -o sparkle.tar.xz \
"https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz"
mkdir -p sparkle-tools
tar -xf sparkle.tar.xz -C sparkle-tools
echo "SPARKLE_BIN=$PWD/sparkle-tools/bin" >> "$GITHUB_ENV"

- name: Generate signed appcast.xml
run: |
TAG="v1.0-build${{ github.run_number }}"
# generate_appcast scans a directory of archives, reads each app's
# CFBundleShortVersionString/CFBundleVersion, computes the EdDSA
# signature + length, and writes appcast.xml. --download-url-prefix
# makes the enclosure URLs point at the per-build release assets.
mkdir -p sparkle-feed
cp "$ZIP_PATH" sparkle-feed/
printf '%s' "$SPARKLE_ED_PRIVATE_KEY" > ed_private_key
"$SPARKLE_BIN/generate_appcast" \
--ed-key-file ed_private_key \
--download-url-prefix "https://github.com/${DOWNLOAD_REPO}/releases/download/${TAG}/" \
sparkle-feed/
rm -f ed_private_key
echo "APPCAST_PATH=$PWD/sparkle-feed/appcast.xml" >> "$GITHUB_ENV"

- name: Publish per-build release (DMG + Sparkle zip)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="v1.0-build${{ github.run_number }}"
gh release create "$TAG" \
"$DMG_PATH" "$ZIP_PATH" \
--title "Loop 1.0 (build ${{ github.run_number }})" \
--notes "Auto-built from ${{ github.sha }}"

- name: Publish appcast feed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# The `appcast` release is a fixed, stable home for the feed so
# SUFeedURL never changes. Create it once; thereafter clobber the asset.
gh release view appcast >/dev/null 2>&1 || \
gh release create appcast \
--title "Sparkle update feed" \
--notes "Auto-update appcast for LoopMac. Do not delete — SUFeedURL points here." \
--latest=false
gh release upload appcast "$APPCAST_PATH" --clobber
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.env.*
!.env.example
Secrets.xcconfig
Secrets_managed.xcconfig
*.secrets.xcconfig
*.p12
*.mobileprovision
Expand All @@ -25,6 +26,9 @@ xcuserdata/
*.dSYM.zip
*.dSYM
*.swiftpm
# Built app bundles / disk images bake in build-time secrets — never commit
*.app/
*.dmg

# ─── macOS ────────────────────────────────────────────────────────────
.DS_Store
Expand Down
Loading
Loading