Three independently ugly bugs that all fed the same log flood:
* Electron's `WebFrameMain.send` writes every "Render frame was disposed"
to stderr via `console.error`. When the worker fans a second
agent-event past a reloading renderer, we produced thousands of
identical lines and stalled the main loop on stderr I/O. Added a
`mainFrame.detached` guard so the send is short-circuited before
Electron's own catch block fires, and installed a targeted filter in
`suppress-warnings.ts` (now actually imported from the entry point)
so the specific `console.error("Error sending from webFrameMain:"…)`
noise never reaches the terminal. Any other payload still surfaces.
* `dispatchAgentMessage` accepted the human-reader sentinel as a wake
target when an agent replied to `__board__` — `wakeAgentIfPossible`
then called `db.getAgent("__board__")`, threw, and the dispatcher
kept repeating on every send. Strip `HUMAN_SENDER_ID` at
`resolveMessageWakeTargets`, and keep a defense-in-depth guard in the
heartbeat so a stray caller (future automation fan-out) cannot
reintroduce the crash.
* Pi's skills loader rejects any SKILL.md whose frontmatter `name`
diverges from its parent directory. The four bundled `my-writing-style`
copies declared `name: writing-style-skill`, so every install emitted
a warning and dropped the skill. They also lived as orphan gitlinks
(mode 160000 without .gitmodules), and the global `*.md` gitignore
hid every other SKILL.md from version control. Fixed the frontmatter
to match the dir, converted the dangling submodules to plain trees,
and allowlisted `builtin-skills/**/*.md` so a fresh clone carries the
catalogue instead of silently losing it.
113 lines
2.5 KiB
Markdown
113 lines
2.5 KiB
Markdown
# SwiftUI Views
|
|
|
|
## SwiftUI Views
|
|
|
|
```swift
|
|
struct ContentView: View {
|
|
@StateObject var userViewModel = UserViewModel()
|
|
|
|
var body: some View {
|
|
TabView {
|
|
HomeView()
|
|
.tabItem { Label("Home", systemImage: "house") }
|
|
|
|
ProfileView(viewModel: userViewModel)
|
|
.tabItem { Label("Profile", systemImage: "person") }
|
|
}
|
|
}
|
|
}
|
|
|
|
struct HomeView: View {
|
|
@State var items: [Item] = []
|
|
@State var loading = true
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
ZStack {
|
|
if loading {
|
|
ProgressView()
|
|
} else {
|
|
List(items) { item in
|
|
NavigationLink(destination: ItemDetailView(item: item)) {
|
|
VStack(alignment: .leading) {
|
|
Text(item.title).font(.headline)
|
|
Text(item.description).font(.subheadline).foregroundColor(.gray)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.navigationTitle("Items")
|
|
.task {
|
|
await loadItems()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func loadItems() async {
|
|
do {
|
|
items = try await NetworkService.shared.fetch([Item].self, from: "/items")
|
|
} catch {
|
|
print("Error: \(error)")
|
|
}
|
|
loading = false
|
|
}
|
|
}
|
|
|
|
struct ItemDetailView: View {
|
|
let item: Item
|
|
@Environment(\.dismiss) var dismiss
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 16) {
|
|
Text(item.title).font(.title2).fontWeight(.bold)
|
|
Text(item.description).font(.body)
|
|
Text("Price: $\(String(format: "%.2f", item.price))")
|
|
.font(.headline).foregroundColor(.blue)
|
|
Spacer()
|
|
}
|
|
.padding()
|
|
}
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
}
|
|
|
|
struct ProfileView: View {
|
|
@ObservedObject var viewModel: UserViewModel
|
|
@State var isLoading = true
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
ZStack {
|
|
if viewModel.isLoading {
|
|
ProgressView()
|
|
} else if let user = viewModel.user {
|
|
VStack(spacing: 20) {
|
|
Text(user.name).font(.title).fontWeight(.bold)
|
|
Text(user.email).font(.subheadline)
|
|
Button("Logout") { viewModel.logout() }
|
|
.foregroundColor(.red)
|
|
Spacer()
|
|
}
|
|
.padding()
|
|
} else {
|
|
Text("No profile data")
|
|
}
|
|
}
|
|
.navigationTitle("Profile")
|
|
.task {
|
|
await viewModel.fetchUser(id: UUID())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Item: Codable, Identifiable {
|
|
let id: String
|
|
let title: String
|
|
let description: String
|
|
let price: Double
|
|
}
|
|
```
|