name: macOS CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
concurrency:
group: macos-ci-${{ github.ref }}
cancel-in-progress: true
env:
SWIFT_TOOLCHAIN_ID: swift-6.2-RELEASE
SWIFT_TOOLCHAIN_NAME: swift
SWIFT_TOOLCHAIN_URL: https://download.swift.org/swift-6.2-release/xcode/swift-6.2-RELEASE/swift-6.2-RELEASE-osx.pkg
jobs:
peekaboo-core:
name: PeekabooCore build & tests
runs-on: macos-latest
env:
PEEKABOO_INCLUDE_AUTOMATION_TESTS: "false"
RUN_AUTOMATION_TESTS: "false"
RUN_LOCAL_TESTS: "false"
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- name: Select Xcode 26.1.1 (if present) or fallback to default
run: |
set -euo pipefail
for candidate in /Applications/Xcode_26.1.1.app /Applications/Xcode_26.1.app /Applications/Xcode.app; do
if [[ -d "$candidate" ]]; then
sudo xcode-select -s "$candidate"
echo "DEVELOPER_DIR=${candidate}/Contents/Developer" >> "$GITHUB_ENV"
break
fi
done
/usr/bin/xcodebuild -version
- name: Prepare Swift Argument Parser fork
run: |
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete/Projects
if [ -d /Users/steipete/Projects/swift-argument-parser ]; then
cd /Users/steipete/Projects/swift-argument-parser
git fetch origin approachable-concurrency
git checkout approachable-concurrency
git pull --ff-only origin approachable-concurrency
else
git clone --branch approachable-concurrency --depth 1 https://github.com/steipete/swift-argument-parser.git /Users/steipete/Projects/swift-argument-parser
fi
- name: Compute SwiftPM cache key (PeekabooCore)
id: cache-key-core
env:
CACHE_PREFIX: ${{ runner.os }}-spm-core-
run: |
set -euo pipefail
if [ -f Core/PeekabooCore/Package.resolved ]; then
HASH=$(shasum Core/PeekabooCore/Package.resolved | awk '{print $1}')
else
echo "Package.resolved missing, falling back to commit SHA"
HASH=${GITHUB_SHA}
fi
echo "key=${CACHE_PREFIX}${HASH}" >> "$GITHUB_OUTPUT"
- name: Cache SwiftPM (PeekabooCore)
uses: actions/cache@v4
with:
path: |
~/.swiftpm
~/.cache/org.swift.swiftpm
Core/PeekabooCore/.build
key: ${{ steps.cache-key-core.outputs.key }}
restore-keys: |
${{ runner.os }}-spm-core-
- name: Install Swift 6.2 toolchain
run: |
if [ ! -d "/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain" ]; then
curl -L "${SWIFT_TOOLCHAIN_URL}" -o /tmp/swift-toolchain.pkg
sudo installer -pkg /tmp/swift-toolchain.pkg -target /
fi
- name: Show Swift toolchain version
run: xcrun --toolchain ${SWIFT_TOOLCHAIN_NAME} swift --version
- name: Export Swift toolchain binary
run: |
echo "SWIFT_BIN=/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/bin/swift" >> "$GITHUB_ENV"
- name: Export Swift runtime library path
run: |
RUNTIME_PATH="/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/lib/swift/macosx"
echo "SWIFT_RUNTIME_LIB=${RUNTIME_PATH}" >> "$GITHUB_ENV"
if [ -n "${DYLD_LIBRARY_PATH:-}" ]; then
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}:${DYLD_LIBRARY_PATH}" >> "$GITHUB_ENV"
else
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}" >> "$GITHUB_ENV"
fi
- name: Show Xcode version
run: xcodebuild -version
- name: Build PeekabooCore
working-directory: Core/PeekabooCore
run: |
"$SWIFT_BIN" build --configuration debug
- name: Run focused Swift tests
working-directory: Core/PeekabooCore
run: |
"$SWIFT_BIN" test --filter ScreenCaptureServiceFlowTests
peekaboo-cli:
name: Peekaboo CLI build & tests
runs-on: macos-latest
needs: peekaboo-core
env:
PEEKABOO_INCLUDE_AUTOMATION_TESTS: "false"
PEEKABOO_SKIP_AUTOMATION: "1"
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- name: Select Xcode 26.1.1 (if present) or fallback to default
run: |
set -euo pipefail
for candidate in /Applications/Xcode_26.1.1.app /Applications/Xcode_26.1.app /Applications/Xcode.app; do
if [[ -d "$candidate" ]]; then
sudo xcode-select -s "$candidate"
echo "DEVELOPER_DIR=${candidate}/Contents/Developer" >> "$GITHUB_ENV"
break
fi
done
/usr/bin/xcodebuild -version
- name: Prepare Swift Argument Parser fork
run: |
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete/Projects
if [ -d /Users/steipete/Projects/swift-argument-parser ]; then
cd /Users/steipete/Projects/swift-argument-parser
git fetch origin approachable-concurrency
git checkout approachable-concurrency
git pull --ff-only origin approachable-concurrency
else
git clone --branch approachable-concurrency --depth 1 https://github.com/steipete/swift-argument-parser.git /Users/steipete/Projects/swift-argument-parser
fi
- name: Compute SwiftPM cache key (CLI)
id: cache-key-cli
env:
CACHE_PREFIX: ${{ runner.os }}-spm-cli-
run: |
set -euo pipefail
if [ -f Apps/CLI/Package.resolved ]; then
HASH=$(shasum Apps/CLI/Package.resolved | awk '{print $1}')
else
echo "Package.resolved missing, falling back to commit SHA"
HASH=${GITHUB_SHA}
fi
echo "key=${CACHE_PREFIX}${HASH}" >> "$GITHUB_OUTPUT"
- name: Cache SwiftPM (CLI)
uses: actions/cache@v4
with:
path: |
~/.swiftpm
~/.cache/org.swift.swiftpm
Apps/CLI/.build
key: ${{ steps.cache-key-cli.outputs.key }}
restore-keys: |
${{ runner.os }}-spm-cli-
- name: Install Swift 6.2 toolchain
run: |
if [ ! -d "/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain" ]; then
curl -L "${SWIFT_TOOLCHAIN_URL}" -o /tmp/swift-toolchain.pkg
sudo installer -pkg /tmp/swift-toolchain.pkg -target /
fi
- name: Show Swift toolchain version
run: xcrun --toolchain ${SWIFT_TOOLCHAIN_NAME} swift --version
- name: Export Swift toolchain binary
run: |
echo "SWIFT_BIN=/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/bin/swift" >> "$GITHUB_ENV"
- name: Export Swift runtime library path
run: |
RUNTIME_PATH="/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/lib/swift/macosx"
echo "SWIFT_RUNTIME_LIB=${RUNTIME_PATH}" >> "$GITHUB_ENV"
if [ -n "${DYLD_LIBRARY_PATH:-}" ]; then
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}:${DYLD_LIBRARY_PATH}" >> "$GITHUB_ENV"
else
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}" >> "$GITHUB_ENV"
fi
- name: Show Xcode version
run: xcodebuild -version
- name: Build CLI target
working-directory: Apps/CLI
run: |
"$SWIFT_BIN" build --configuration debug
- name: Run CLI unit tests (skip automation)
working-directory: Apps/CLI
run: |
"$SWIFT_BIN" test -Xswiftc -DPEEKABOO_SKIP_AUTOMATION
tachikoma:
name: Tachikoma build & tests
runs-on: macos-latest
needs: peekaboo-cli
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- name: Select Xcode 26.1.1 (if present) or fallback to default
run: |
set -euo pipefail
for candidate in /Applications/Xcode_26.1.1.app /Applications/Xcode_26.1.app /Applications/Xcode.app; do
if [[ -d "$candidate" ]]; then
sudo xcode-select -s "$candidate"
echo "DEVELOPER_DIR=${candidate}/Contents/Developer" >> "$GITHUB_ENV"
break
fi
done
/usr/bin/xcodebuild -version
- name: Remove phantom submodule metadata
run: |
rm -f .gitmodules
git config --local --remove-section submodule.Tachikoma || true
- name: Prepare Swift Argument Parser fork
run: |
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete
sudo mkdir -p /Users/steipete/Projects
sudo chown $USER /Users/steipete/Projects
if [ -d /Users/steipete/Projects/swift-argument-parser ]; then
cd /Users/steipete/Projects/swift-argument-parser
git fetch origin approachable-concurrency
git checkout approachable-concurrency
git pull --ff-only origin approachable-concurrency
else
git clone --branch approachable-concurrency --depth 1 https://github.com/steipete/swift-argument-parser.git /Users/steipete/Projects/swift-argument-parser
fi
- name: Compute SwiftPM cache key (Tachikoma)
id: cache-key-tachikoma
env:
CACHE_PREFIX: ${{ runner.os }}-spm-tachikoma-
run: |
set -euo pipefail
if [ -f Tachikoma/Package.resolved ]; then
HASH=$(shasum Tachikoma/Package.resolved | awk '{print $1}')
else
echo "Package.resolved missing, falling back to commit SHA"
HASH=${GITHUB_SHA}
fi
echo "key=${CACHE_PREFIX}${HASH}" >> "$GITHUB_OUTPUT"
- name: Cache SwiftPM (Tachikoma)
uses: actions/cache@v4
with:
path: |
~/.swiftpm
~/.cache/org.swift.swiftpm
Tachikoma/.build
key: ${{ steps.cache-key-tachikoma.outputs.key }}
restore-keys: |
${{ runner.os }}-spm-tachikoma-
- name: Install Swift 6.2 toolchain
run: |
if [ ! -d "/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain" ]; then
curl -L "${SWIFT_TOOLCHAIN_URL}" -o /tmp/swift-toolchain.pkg
sudo installer -pkg /tmp/swift-toolchain.pkg -target /
fi
- name: Show Swift toolchain version
run: xcrun --toolchain ${SWIFT_TOOLCHAIN_NAME} swift --version
- name: Export Swift toolchain binary
run: |
echo "SWIFT_BIN=/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/bin/swift" >> "$GITHUB_ENV"
- name: Export Swift runtime library path
run: |
RUNTIME_PATH="/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain/usr/lib/swift/macosx"
echo "SWIFT_RUNTIME_LIB=${RUNTIME_PATH}" >> "$GITHUB_ENV"
if [ -n "${DYLD_LIBRARY_PATH:-}" ]; then
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}:${DYLD_LIBRARY_PATH}" >> "$GITHUB_ENV"
else
echo "DYLD_LIBRARY_PATH=${RUNTIME_PATH}" >> "$GITHUB_ENV"
fi
- name: Show Xcode version
run: xcodebuild -version
- name: Build Tachikoma
working-directory: Tachikoma
run: |
"$SWIFT_BIN" build --configuration debug
- name: Run Tachikoma unit tests
working-directory: Tachikoma
run: |
"$SWIFT_BIN" test --filter unit
mac-apps:
name: Build macOS apps (Peekaboo + Inspector)
runs-on: macos-latest
needs: [peekaboo-cli, tachikoma]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- name: Select Xcode 26.1.1 (if present) or fallback to default
run: |
set -euo pipefail
for candidate in /Applications/Xcode_26.1.1.app /Applications/Xcode_26.1.app /Applications/Xcode.app; do
if [[ -d "$candidate" ]]; then
sudo xcode-select -s "$candidate"
echo "DEVELOPER_DIR=${candidate}/Contents/Developer" >> "$GITHUB_ENV"
break
fi
done
/usr/bin/xcodebuild -version
- name: Install Swift 6.2 toolchain
run: |
if [ ! -d "/Library/Developer/Toolchains/${SWIFT_TOOLCHAIN_ID}.xctoolchain" ]; then
curl -L "${SWIFT_TOOLCHAIN_URL}" -o /tmp/swift-toolchain.pkg
sudo installer -pkg /tmp/swift-toolchain.pkg -target /
fi
- name: Build Peekaboo app (Xcode)
working-directory: Apps
run: |
/usr/bin/env -u DYLD_LIBRARY_PATH -u DYLD_FRAMEWORK_PATH -u DYLD_FALLBACK_FRAMEWORK_PATH \
xcodebuild -workspace Peekaboo.xcworkspace \
-scheme Peekaboo \
-configuration Debug \
-sdk macosx \
CODE_SIGNING_ALLOWED=NO \
-derivedDataPath /tmp/DerivedData-Peekaboo
- name: Build Inspector app (Xcode)
working-directory: Apps/PeekabooInspector
run: |
/usr/bin/env -u DYLD_LIBRARY_PATH -u DYLD_FRAMEWORK_PATH -u DYLD_FALLBACK_FRAMEWORK_PATH \
xcodebuild -project Inspector.xcodeproj \
-scheme Inspector \
-configuration Debug \
-sdk macosx \
CODE_SIGNING_ALLOWED=NO \
-derivedDataPath /tmp/DerivedData-Inspector
lint:
name: SwiftLint (core + CLI)
runs-on: macos-latest
needs: [peekaboo-cli, tachikoma, mac-apps]
steps:
- uses: actions/checkout@v4
- name: Install SwiftLint
run: brew install swiftlint
- name: Run SwiftLint with CI config
run: swiftlint --config .swiftlint-ci.yml