diff --git a/AGENTS.md b/AGENTS.md index b3bb612..2dd4505 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,6 +17,11 @@ A deploy is a release that isn't uploaded: the same notarized disk image, instal 3. Once the service is confirmed healthy, update each client Mac whose app is running, through the client tools and without asking first: upload the disk image (`mac/.build/release//byre-.dmg`) and `mac/install.sh`, quit the app, run `install.sh `, and `open /Applications/Byre.app`. The app reads its server address from its iCloud-synced SwiftData store, so it reconnects to prod with no setup. Report each Mac's app commit (`install.sh` prints it). 4. End the report with release notes for everything on main since the last release tag (`git describe --tags --abbrev=0` names it), written for a byre user in the "Releasing" shape (`## New` and `## Fixed`, each a bullet with a bold short name and what it does or what now works; no `## Install`). Read `git diff ..HEAD`, not just the commit subjects, and leave out changes no user sees. +Besides iso, beast also runs its own byre server. Run `mac/package.sh` once, install beast first, and finish with iso's install: + +- Upload the disk image to beast as `~/byre-deploy/byre.dmg` and `mac/install.sh` as `~/byre-deploy/install.sh` (`client_upload`), then run `~/byre-deploy/run.sh` there detached, through `client_bash`: `perl -MPOSIX -e 'fork and exit; POSIX::setsid(); open STDIN,">$ENV{HOME}/byre-deploy/run.log"; open STDERR,">&STDOUT"; exec "/bin/zsh","$ENV{HOME}/byre-deploy/run.sh"'`. It quits the app, installs, and reopens it; the beast client drops for about a minute and `list_clients` shows it back on the new commit. Do the same for every other running client Mac, and relaunch iso's app only if it is running. +- Check each server with the bearer token in `~/Library/Application Support/byre/loopback-token`: `GET https://byre-.tailcecab.ts.net/api/tailnet` (`state` is `Running`) and `/api/admin/status` (report zombies, protocol errors, rate limits). The loopback address serves `/api/tailnet` but not `/api/admin/status`. + What to expect: - The notarizations take a minute or two each; `notarytool` prints "In Progress" until "Accepted". A rejection stops the script before anything is installed; `xcrun notarytool log --keychain-profile byre-notary` says why. diff --git a/mac/Sources/Byre/Pages.swift b/mac/Sources/Byre/Pages.swift index 3ba920f..c26b5fc 100644 --- a/mac/Sources/Byre/Pages.swift +++ b/mac/Sources/Byre/Pages.swift @@ -40,7 +40,8 @@ func isPage(_ path: String) -> Bool { extension Store { func openPage(_ page: Page) { - sheet = Sheet(owner: .task(page.taskId), view: .page(page)) + shownPages[page.taskId] = page + sheet = Sheet(owner: .task(page.taskId), view: .tab(.page)) } } diff --git a/mac/Sources/Byre/Panes.swift b/mac/Sources/Byre/Panes.swift index e37a8d9..3559e1a 100644 --- a/mac/Sources/Byre/Panes.swift +++ b/mac/Sources/Byre/Panes.swift @@ -7,6 +7,7 @@ let tabLabels: [TaskTab: String] = [ .board: "Board", .changes: "Changes", .files: "Files", + .page: "Page", .terminal: "Terminal", .workflow: "Workflow", .project: "Project", @@ -230,6 +231,10 @@ struct TaskTabBody: View { ChangesView() case .files: FilesView() + case .page: + if let page = store.selectedTaskId.flatMap({ store.shownPages[$0] }) { + PageView(page: page) + } case .terminal: TerminalTab() case .workflow: @@ -385,6 +390,7 @@ private struct TabStrip: View { } switch t { case .board: return team + case .page: return store.shownPages[taskId] != nil case .workflow: return false default: return true } diff --git a/mac/Sources/Byre/Sheet.swift b/mac/Sources/Byre/Sheet.swift index 1102790..652f8ba 100644 --- a/mac/Sources/Byre/Sheet.swift +++ b/mac/Sources/Byre/Sheet.swift @@ -5,7 +5,6 @@ enum SheetView { case tab(TaskTab) case image(NSImage) case diagram(BoxLayout) - case page(Page) } struct Sheet { @@ -82,7 +81,7 @@ private struct SheetPanel: View { .lineLimit(1) .truncationMode(.tail) Spacer(minLength: 0) - if case .page(let page) = sheet.view, let url = page.url(store) { + if sheet.tab == .page, let page = store.selectedTaskId.flatMap({ store.shownPages[$0] }), let url = page.url(store) { Button { NSWorkspace.shared.open(url) } label: { @@ -129,7 +128,6 @@ private struct SheetPanel: View { case .tab(let t): tabLabels[t]! case .image: "Image" case .diagram: "Diagram" - case .page(let page): page.title(store) } if !overLeft { return "Lead ยท \(label)" @@ -159,8 +157,6 @@ private struct SheetPanel: View { DiagramViewer(layout: layout) .id(layout.id) .padding(12) - case .page(let page): - PageView(page: page) } } } diff --git a/mac/Sources/Byre/Store.swift b/mac/Sources/Byre/Store.swift index 142b631..3cabe16 100644 --- a/mac/Sources/Byre/Store.swift +++ b/mac/Sources/Byre/Store.swift @@ -3,10 +3,10 @@ import Observation import SwiftData enum TaskTab: String { - case transcript, board, changes, files, terminal, workflow, project + case transcript, board, changes, files, page, terminal, workflow, project } -let taskTabs: [TaskTab] = [.transcript, .board, .changes, .files, .terminal, .workflow, .project] +let taskTabs: [TaskTab] = [.transcript, .board, .changes, .files, .page, .terminal, .workflow, .project] enum JumpTarget: Equatable { case question(String) @@ -71,6 +71,7 @@ final class Store { var connected = false private(set) var focus = Focus() var sheet: Sheet? + var shownPages: [String: Page] = [:] var leadSessions: [AgentSession] = [] let leadFeed: Feed var jump: Jump?