Sign the macOS app and keep its state in SwiftData with iCloud sync

This commit is contained in:
Ian Gulliver
2026-10-17 10:13:26 -07:00
parent d21215b442
commit 1808ca8be6
11 changed files with 195 additions and 36 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
- `internal/tailscale`: `tailscale serve` for task previews (see "Previews").
- `internal/workflow`: validating workflow definitions and reading and writing their YAML files (see "Workflows").
- `web/`: the SPA, frameworkless TypeScript compiled file-by-file to ES modules (no bundler). `web/src/*.ts` is the source; `web/src/api.gen.ts` holds types generated from `api/openapi.yaml`, and `web/src/api.ts` is the typed client over them. `go generate ./web` runs `npm ci`, regenerates the types and compiles `web/dist/`, which is committed so `go install` needs no Node. The binary embeds `index.html`, `style.css`, `favicon.svg` (a lead dot in the accent colour with spokes to five task-coloured dots; its colours are saturated versions of the `web/style.css` accent and task hues, not copies of the palette, since the palette's pastels blur together at 16px; they switch with the light/dark scheme), `favicon.png` (the same icon in its dark colours on an opaque dark `--surface` square at 180×180, rendered from `web/favicon-tile.svg`, which is not embedded; opaque because Orion puts a transparent icon on a white tile; linked as a second icon and as the `apple-touch-icon`, which Orion prefers over the SVG for its tab icon; Orion's icon store (`~/Library/Application Support/Orion/Defaults/website_icons`, kept apart from its cache) keys icons by hostname without the port, so another server on the same hostname can supply byre's tab icon; `favicon-tile.svg` repeats the shapes and dark colours of `favicon.svg`, so change both together, then regenerate the PNG with `rsvg-convert --width 180 --height 180 --output web/favicon.png web/favicon-tile.svg`), `dist/`, `src/` (for source maps), `fonts/` and `vendor/` (Mermaid, see "Inbox"; xterm.js, see "Terminals"). `byre serve --dev` serves `./web` from disk instead (run from the repo root); pair it with `npm --prefix web exec tsc -- --watch`.
- `mac/` is the macOS client in progress; `docs/macos.md` is its design and says what exists. `mac/bundle.sh` builds `mac/.build/byre.app`, which connects to the byre `https` origin typed into its connection screen (the same `tailscale serve` URL a browser uses). Its API client is generated from `api/openapi.yaml` at build time, and `go generate ./mac` regenerates the committed `mac/Sources/Byre/Palette.swift` from the custom properties in `web/style.css`, so run it after changing the palette. The app keeps its state in its own defaults domain (`defaults read run.fc.byre.mac` prints it): the server origin in `byre.server`, last task visits in `byre.visits`, and composer and answer drafts as JSON in `byre.drafts.<origin>.<login>`, one key per server and login. Pasted images stay in memory with the connection and are dropped on Change Server… and quit. It reports `PUT /api/me/pane-focus` as the web client does, and sends `focused: false` on Change Server…, on closing the window and on quit.
- `mac/` is the macOS client in progress; `docs/macos.md` is its design and says what exists. `mac/bundle.sh` builds `mac/.build/byre.app`, which connects to the byre `https` origin typed into its connection screen (the same `tailscale serve` URL a browser uses). Its API client is generated from `api/openapi.yaml` at build time, and `go generate ./mac` regenerates the committed `mac/Sources/Byre/Palette.swift` from the custom properties in `web/style.css`, so run it after changing the palette. The app keeps its state in SwiftData synced through the iCloud private database of container `iCloud.run.fc.byre.mac` (the CloudKit console shows its records): the server origin, last task visits, and composer and answer drafts as JSON, one record per server and login (`docs/macos.md`, "Persistence"). Pasted images stay in memory with the connection and are dropped on Change Server… and quit. It reports `PUT /api/me/pane-focus` as the web client does, and sends `focused: false` on Change Server…, on closing the window and on quit.
## Data