Add team tasks: several agents in one worktree sharing a board

This commit is contained in:
Ian Gulliver
2026-10-18 08:48:57 -07:00
parent 7f62df19d2
commit 6bcde13b2f
31 changed files with 1392 additions and 439 deletions
+70
View File
@@ -0,0 +1,70 @@
import ByreAPI
import SwiftUI
struct BoardView: View {
@Environment(Store.self) private var store
var body: some View {
let taskId = store.selectedTaskId
let posts = store.transcript.filter { $0.kind == "board.posted" }
VStack(spacing: 0) {
HStack(spacing: 10) {
Text("Board").font(Fonts.font(13, weight: 700))
Text(taskId.map { store.team($0).map(\.member).joined(separator: ", ") } ?? "")
.foregroundStyle(Palette.muted)
.lineLimit(1)
.truncationMode(.tail)
}
.modifier(HeaderBar())
if posts.isEmpty {
EmptyText(text: taskId == nil ? "No task selected." : "No posts yet. Post from the Transcript tab's composer.")
} else {
ScrollViewReader { proxy in
ScrollView {
LazyVStack(alignment: .leading, spacing: 12) {
ForEach(posts, id: \.seq) { ev in
PostView(ev: ev, taskId: taskId)
.id(ev.seq)
}
}
.padding(.horizontal, 16)
.padding(.vertical, 12)
}
.onAppear {
proxy.scrollTo(posts.last?.seq, anchor: .bottom)
}
.onChange(of: posts.count) {
proxy.scrollTo(posts.last?.seq, anchor: .bottom)
}
}
}
}
.frame(maxHeight: .infinity, alignment: .top)
}
}
private struct PostView: View {
let ev: ByreEvent
let taskId: String?
var body: some View {
let p = ev.payload.value
let member = str(p, "member") ?? ""
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 6) {
Text(member.isEmpty ? ev.actor : member).font(Fonts.font(12, weight: 700))
if !member.isEmpty {
Text(str(p, "model") ?? "").foregroundStyle(Palette.muted)
}
WhenText(when: ev.createdAt).foregroundStyle(Palette.muted)
}
.font(Fonts.font(11))
MarkdownView(blocks: parseMarkdown(str(p, "text") ?? ""), ctx: MDContext(taskId: taskId))
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
.frame(maxWidth: .infinity, alignment: .leading)
.background(member.isEmpty ? Palette.accentTint : Palette.raised, in: RoundedRectangle(cornerRadius: 10))
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Palette.border))
}
}