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
4 changes: 2 additions & 2 deletions .github/actions/setup-submodule/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >

inputs:
deploy-key:
description: "SSH deploy key with read access to lobu-ai/owletto-web"
description: "SSH deploy key with read access to lobu-ai/owletto"
required: false
default: ""

Expand All @@ -29,7 +29,7 @@ runs:
shell: bash
run: |
set -euo pipefail
git config --global url."git@github.com:lobu-ai/owletto-web.git".insteadOf "https://github.com/lobu-ai/owletto-web.git"
git config --global url."git@github.com:lobu-ai/owletto.git".insteadOf "https://github.com/lobu-ai/owletto.git"
git submodule update --init --recursive packages/web

- name: Write stub package.json when submodule is unavailable
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
files: coverage/lcov.info
fail_ci_if_error: false

# Frontend tests run under jsdom via vitest. owletto-web is a submodule;
# Frontend tests run under jsdom via vitest. owletto is a submodule;
# forks without the deploy key get a stub package and skip these.
frontend:
runs-on: ubuntu-latest
Expand All @@ -121,16 +121,16 @@ jobs:
if: steps.submodule.outputs.stubbed != 'true'
run: bun install

- name: Build core + connector-sdk (owletto-web imports their compiled dist)
- name: Build core + connector-sdk (owletto imports their compiled dist)
# connector-sdk imports @lobu/core; resolving the type-only barrel
# import needs core/dist on disk first.
if: steps.submodule.outputs.stubbed != 'true'
run: |
cd packages/core && bun run build && cd ../..
cd packages/connector-sdk && bun run build && cd ../..

- name: owletto-web tests (vitest)
# owletto-web doesn't define a `test` script in its package.json yet
- name: owletto tests (vitest)
# owletto doesn't define a `test` script in its package.json yet
# (that change ships as a separate submodule PR). Invoke vitest
# directly via the workspace-installed binary so this works on
# whatever submodule SHA the parent repo points at.
Expand Down
75 changes: 68 additions & 7 deletions .github/workflows/mac-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ name: mac-release
# resolves) and signs an entry into the Sparkle appcast so installed apps can
# auto-update.
#
# The Mac source lives in the private `lobu-ai/owletto` repo, mounted here as
# the `packages/web` submodule. Releases ship from this (public) repo so the
# DMG download URL and Sparkle appcast URL stay reachable to anonymous users —
# private-repo Releases would 404 without auth.
#
# Two modes, picked automatically from whether the Developer ID cert secret is
# set — adding the secrets is the *only* thing needed to flip from stopgap to
# production; nothing in this file changes:
Expand All @@ -26,7 +31,7 @@ name: mac-release
#
# No provisioning profile is required — the app ships only standard
# entitlements (the HealthKit entitlement is disabled; see
# apps/mac/Lobu/Lobu.entitlements).
# packages/web/apps/mac/Lobu/Lobu.entitlements in the owletto submodule).
#
# Sparkle auto-updates: `SPARKLE_ED_PRIVATE_KEY` (64-byte base64 of seed||pub)
# is required. The job signs Lobu.dmg with `sign_update` and pushes a new
Expand All @@ -50,6 +55,50 @@ jobs:
steps:
- uses: actions/checkout@v4

# Mac source lives in the owletto submodule; need the deploy key to clone.
- id: submodule
uses: ./.github/actions/setup-submodule
with:
deploy-key: ${{ secrets.OWLETTO_WEB_DEPLOY_KEY }}

# Release contract — fail fast rather than build a wrong/missing artifact:
# 1. The deploy key must work. The setup-submodule action writes a stub
# package.json when the key is absent; that's fine for CI on forks but
# catastrophic for a release (we'd ship an empty DMG or fail late on
# a missing project). Make it fatal here.
# 2. The submodule must point at lobu-ai/owletto. If the URL drifted we
# could be releasing the wrong codebase entirely.
# 3. The Mac Xcode project + bundle paths the rest of this workflow
# assumes must actually exist at the pinned SHA. Otherwise the
# `lobster-mark.svg` → `owletto-mark.svg` style of silent rename on
# the owletto side would only surface inside `xcodebuild`.
- name: Verify release contract (submodule + Mac source layout)
shell: bash
run: |
set -euo pipefail
if [ "${{ steps.submodule.outputs.stubbed }}" = "true" ]; then
echo "::error::Submodule was stubbed — OWLETTO_WEB_DEPLOY_KEY is missing or invalid. Aborting release."
exit 1
fi
remote_url=$(git -C packages/web config --get remote.origin.url)
case "$remote_url" in
*lobu-ai/owletto.git|*lobu-ai/owletto) ;;
*)
echo "::error::packages/web origin is '$remote_url' — expected lobu-ai/owletto. Aborting release."
exit 1
;;
esac
for required in \
packages/web/apps/mac/Lobu.xcodeproj \
packages/web/apps/mac/Lobu/Info.plist \
scripts/sparkle/update-appcast.py
do
if [ ! -e "$required" ]; then
echo "::error::Required release path missing: $required"
exit 1
fi
done

- name: Resolve version
id: v
run: echo "version=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -89,7 +138,7 @@ jobs:
if: steps.mode.outputs.signed == 'true'
run: |
xcodebuild \
-project apps/mac/Lobu.xcodeproj -scheme Lobu -configuration Release \
-project packages/web/apps/mac/Lobu.xcodeproj -scheme Lobu -configuration Release \
Comment thread
coderabbitai[bot] marked this conversation as resolved.
-archivePath "$RUNNER_TEMP/Lobu.xcarchive" archive \
CODE_SIGN_STYLE=Manual \
CODE_SIGN_IDENTITY="Developer ID Application" \
Expand All @@ -101,7 +150,7 @@ jobs:
if: steps.mode.outputs.signed != 'true'
run: |
xcodebuild \
-project apps/mac/Lobu.xcodeproj -scheme Lobu -configuration Release \
-project packages/web/apps/mac/Lobu.xcodeproj -scheme Lobu -configuration Release \
-archivePath "$RUNNER_TEMP/Lobu.xcarchive" archive \
CODE_SIGNING_ALLOWED=NO \
MARKETING_VERSION="${{ steps.v.outputs.version }}"
Expand Down Expand Up @@ -145,6 +194,11 @@ jobs:
env:
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
run: |
# `set +x` around secret handling — GitHub Actions masks known
# secret strings in logs, but we don't want correctness to rely on
# that masking. Trace only the non-secret commands (curl, tar, git
# clone-with-token-URL is also non-traced for the same reason).
set -e
if [ -z "$SPARKLE_ED_PRIVATE_KEY" ]; then
echo "::error::SPARKLE_ED_PRIVATE_KEY not set — add the 64-byte base64 Sparkle Ed25519 private key as a repo secret."
exit 1
Expand All @@ -155,29 +209,37 @@ jobs:
# Fetch Sparkle's binary tools (sign_update). The SPM artifact bundle
# ships them under `bin/`, but the Sparkle GitHub release tarball is
# the easier source from CI.
set -x
SPARKLE_VERSION="2.9.1"
curl -fsSL -o "$RUNNER_TEMP/sparkle.tar.xz" \
"https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz"
mkdir -p "$RUNNER_TEMP/sparkle" && tar -xJf "$RUNNER_TEMP/sparkle.tar.xz" -C "$RUNNER_TEMP/sparkle"
SIGN_UPDATE="$RUNNER_TEMP/sparkle/bin/sign_update"
test -x "$SIGN_UPDATE" || { echo "::error::sign_update missing from Sparkle archive"; exit 1; }
set +x

# sign_update prints: sparkle:edSignature="..." length="..."
# Secret handling: drop xtrace so the key file path + sign_update
# invocation aren't echoed to the log next to the (masked) secret.
KEY_FILE="$RUNNER_TEMP/sparkle_ed_private.b64"
printf '%s' "$SPARKLE_ED_PRIVATE_KEY" > "$KEY_FILE"
chmod 600 "$KEY_FILE"
SIGN_OUTPUT=$("$SIGN_UPDATE" -f "$KEY_FILE" "$DMG")
rm -f "$KEY_FILE"
echo "sign_update output: $SIGN_OUTPUT"

set -x
ED_SIG=$(echo "$SIGN_OUTPUT" | sed -E 's/.*sparkle:edSignature="([^"]+)".*/\1/')
LENGTH=$(echo "$SIGN_OUTPUT" | sed -E 's/.*length="([^"]+)".*/\1/')
test -n "$ED_SIG" && test -n "$LENGTH" || { echo "::error::failed to parse sign_update output"; exit 1; }
set +x

# Clone gh-pages, append the new <item>, push back.
# Clone gh-pages — token-bearing URL must not be traced.
git clone --depth 1 --branch gh-pages \
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
"$RUNNER_TEMP/ghpages"
python3 apps/mac/sparkle/update-appcast.py "$RUNNER_TEMP/ghpages/appcast.xml" \

set -x
python3 scripts/sparkle/update-appcast.py "$RUNNER_TEMP/ghpages/appcast.xml" \
--version "$VERSION" \
--build "$VERSION" \
--dmg-url "https://github.com/${{ github.repository }}/releases/download/lobu-v${VERSION}/Lobu.dmg" \
Expand All @@ -192,4 +254,3 @@ jobs:
git add appcast.xml
git diff --cached --quiet || git commit -m "appcast: lobu ${VERSION}"
git push origin gh-pages

20 changes: 10 additions & 10 deletions .github/workflows/submodule-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
echo "::error::OWLETTO_WEB_DEPLOY_KEY is missing for a same-repo run; drift check cannot run."
exit 1

- name: Check for unmerged non-bot commits on owletto-web/main
- name: Check for unmerged non-bot commits on owletto/main
if: steps.submodule.outputs.stubbed != 'true'
shell: bash
run: |
Expand All @@ -77,18 +77,18 @@ jobs:
REMOTE=$(git -C packages/web rev-parse origin/main)

echo "Pinned (parent): $PINNED"
echo "owletto-web/main: $REMOTE"
echo "owletto/main: $REMOTE"

# Hard rule: parent must never pin a SHA that isn't on owletto-web/main.
# FluxCD reads charts from owletto-web/main; an off-main pin breaks deploy.
# Hard rule: parent must never pin a SHA that isn't on owletto/main.
# FluxCD reads charts from owletto/main; an off-main pin breaks deploy.
if ! git -C packages/web merge-base --is-ancestor "$PINNED" origin/main; then
echo "::error::Pinned SHA $PINNED is not reachable from owletto-web/main."
echo "::error::Pinned SHA $PINNED is not reachable from owletto/main."
echo "This violates the rule against pinning unmerged submodule SHAs (see AGENTS.md)."
exit 1
fi

if [ "$PINNED" = "$REMOTE" ]; then
echo "Submodule pin matches owletto-web/main — no drift."
echo "Submodule pin matches owletto/main — no drift."
exit 0
fi

Expand Down Expand Up @@ -119,14 +119,14 @@ jobs:
done <<< "$LOG"

if [ -z "$DRIFT" ]; then
echo "owletto-web/main is ahead, but only by FluxCD image-tag commits — no parent bump needed."
echo "owletto/main is ahead, but only by FluxCD image-tag commits — no parent bump needed."
exit 0
fi

echo "::error::owletto-web/main has merged commits past the pinned SHA. The parent bump PR is missing."
echo "::error::owletto/main has merged commits past the pinned SHA. The parent bump PR is missing."
echo ""
echo "Pinned: $PINNED"
echo "owletto-web/main: $REMOTE"
echo "owletto/main: $REMOTE"
echo ""
echo "Commits needing a parent bump:"
printf '%s' "$DRIFT"
Expand All @@ -135,5 +135,5 @@ jobs:
echo " git -C packages/web fetch origin"
echo " git -C packages/web checkout origin/main"
echo " git add packages/web"
echo " git commit -m 'chore(submodule): bump owletto-web to current main'"
echo " git commit -m 'chore(submodule): bump owletto to current main'"
exit 1
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "packages/web"]
path = packages/web
url = https://github.com/lobu-ai/owletto-web.git
url = https://github.com/lobu-ai/owletto.git
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
- When fixing unused-parameter errors, delete the parameter rather than prefixing with `_`.

### Submodules
`packages/web` is a submodule of `lobu-ai/owletto-web`. Push the submodule change to a reachable branch first (usually `main`), then bump the pointer in the parent — the parent must never point at an unreachable SHA, or production cloning will fail.
`packages/web` is a submodule of `lobu-ai/owletto`. Push the submodule change to a reachable branch first (usually `main`), then bump the pointer in the parent — the parent must never point at an unreachable SHA, or production cloning will fail.

### Frontend (web)
When editing UI under `packages/web`, follow the design rules in @packages/web/DESIGN_GUIDELINES.md — confirmations, surfaces, empty states, selection, forms, page copy, radius, Sheet vs Dialog. Match the existing components and exemplar files referenced there; do not introduce new primitives without updating the guideline in the same PR.
Expand Down
88 changes: 0 additions & 88 deletions apps/chrome/README.md

This file was deleted.

Loading
Loading