diff --git a/api/openapi.yaml b/api/openapi.yaml index 7edde38..c41d9dc 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1335,7 +1335,8 @@ paths: description: > A WebSocket over which task agents use this Mac: the server sends ClientRequest text messages and the client answers each with a ClientReply text message carrying the same id, in any order. The Byre-Host header names - the client; a newer connection from the same host replaces the older one. + the client, percent-encoded since device names hold characters such as ’ that headers can't carry; a newer + connection from the same host replaces the older one. responses: "101": description: Switched to the WebSocket protocol. diff --git a/docs/macos.md b/docs/macos.md index 93ddb0a..45645ba 100644 --- a/docs/macos.md +++ b/docs/macos.md @@ -36,6 +36,7 @@ Every build is signed for distribution outside the App Store: the team's Develop - The transcript is a plain `VStack` in a `ScrollView`, not lazy: a `LazyVStack` estimates the height of rows it hasn't shown yet and corrects it when they scroll into view, without moving the scroll offset, so scrolling up through rows not yet shown jumped by each correction; SwiftUI can't move the offset mid-scroll without stopping its momentum. - The terminal cursor is a steady block: SwiftTerm's blinking cursor restarts its Core Animation fade on every keypress, scheduled 0.7 s out, and on a ProMotion display macOS then holds the window's screen update until that fade starts, so each typed letter appears about 0.7 s late. SwiftTerm redraws the whole screen whenever a terminal color is set, even when its value hasn't changed. +- A full-size diagram is drawn at its zoom, in tiles, and a pinch is folded into that zoom when it ends. Scaling a natural-size SwiftUI view down with `NSScrollView` magnification or `UIScrollView` zooming draws only about a window's width of it, so fitting a wide diagram that way shows its first few boxes and blank space. - The Page view loads a worktree page from a plain-HTTP server the app runs on a loopback port (`http://127.0.0.1://`), which fetches each file through the server's `getTaskRaw` endpoint. The page's relative links to its stylesheets, scripts and images resolve to files beside it; absolute and `file://` references don't load. "↗ Browser" opens the same address. iOS reclaims the listening socket while the app is suspended, so the app binds it again on the same port each time it returns to the foreground. Previews load from their loopback forwards at `-.localhost`. App Transport Security blocks plain HTTP to `*.localhost` even with `NSAllowsLocalNetworking`; the `localhost` exception domain with subdomains in `Info.plist` allows it (loopback IP addresses need no exception). `NSAllowsArbitraryLoadsInWebContent` lets the Page view load plain-HTTP websites without lifting ATS for the app's own requests. - Each Page view tab's `WKWebView` belongs to `Pages`, not to the SwiftUI view, so it keeps its page while the sheet is closed and agents can drive it with `drive_page` (navigate, JavaScript, capture) from the client connection. All tabs share WebKit's default persistent data store, so a site the human signs into stays signed in across launches. A link that opens a new window becomes a new tab of the same task. Capture refuses a tab that isn't on screen (sheet closed, or another tab showing), since its snapshot would show nothing the human sees. Passkey sign-in may fail, because WebKit allows WebAuthn in an embedded view only for apps with Apple's web browser entitlement; a password with a 2FA code works. diff --git a/internal/api/api.gen.go b/internal/api/api.gen.go index d055528..9f2145f 100644 --- a/internal/api/api.gen.go +++ b/internal/api/api.gen.go @@ -5160,376 +5160,377 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H // const string: with thousands of chunks the chained `+` fold is several // times slower for the Go compiler than parsing a slice literal. var swaggerSpec = []string{ - "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", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/server/clients.go b/internal/server/clients.go index 47560df..7405797 100644 --- a/internal/server/clients.go +++ b/internal/server/clients.go @@ -22,9 +22,9 @@ import ( func (s *Server) ConnectClient(w http.ResponseWriter, r *http.Request) { id := r.Header.Get("Byre-Client") - host := r.Header.Get("Byre-Host") + host := clientHost(r) if id == "" || host == "" { - writeError(w, http.StatusBadRequest, errors.New("missing Byre-Client or Byre-Host")) + writeError(w, http.StatusBadRequest, errors.New("missing Byre-Client or Byre-Host, or Byre-Host isn't percent-encoded")) return } @@ -40,9 +40,9 @@ func (s *Server) ConnectClient(w http.ResponseWriter, r *http.Request) { func (s *Server) SetClientSync(w http.ResponseWriter, r *http.Request) { id := r.Header.Get("Byre-Client") - host := r.Header.Get("Byre-Host") + host := clientHost(r) if id == "" || host == "" { - writeError(w, http.StatusBadRequest, errors.New("missing Byre-Client or Byre-Host")) + writeError(w, http.StatusBadRequest, errors.New("missing Byre-Client or Byre-Host, or Byre-Host isn't percent-encoded")) return } sync := api.ClientSync{} diff --git a/internal/server/server.go b/internal/server/server.go index 84524a8..c932f96 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -8,6 +8,7 @@ import ( "fmt" "log/slog" "net/http" + "net/url" "os" "path/filepath" "strings" @@ -202,11 +203,19 @@ func (s *Server) identify(next http.Handler) http.Handler { } func (s *Server) acted(login string, r *http.Request) { - if s.clients.Acted(r.Header.Get("Byre-Client"), login, r.Header.Get("Byre-Host"), r.Header.Get("Byre-Commit"), r.Header.Get("Byre-Build")) { + if s.clients.Acted(r.Header.Get("Byre-Client"), login, clientHost(r), r.Header.Get("Byre-Commit"), r.Header.Get("Byre-Build")) { s.clientsChanged() } } +func clientHost(r *http.Request) string { + host, err := url.PathUnescape(r.Header.Get("Byre-Host")) + if err != nil { + return "" + } + return host +} + func (s *Server) connectedClients() []api.ConnectedClient { out := []api.ConnectedClient{} for _, c := range s.clients.List() { diff --git a/mac/Sources/Byre/API.swift b/mac/Sources/Byre/API.swift index 8d89896..6946546 100644 --- a/mac/Sources/Byre/API.swift +++ b/mac/Sources/Byre/API.swift @@ -125,7 +125,7 @@ final class API: Sendable { "Byre-Client": clientID, "Byre-Commit": Bundle.main.object(forInfoDictionaryKey: "ByreCommit") as! String, "Byre-Device": deviceKind, - "Byre-Host": deviceName, + "Byre-Host": deviceName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!, ] config.proxyConfigurations = [tailnetNode.proxy()] session = URLSession(configuration: config, delegate: RequestTiming(), delegateQueue: nil) diff --git a/mac/Sources/Byre/BoxDiagram.swift b/mac/Sources/Byre/BoxDiagram.swift index 3f19456..f7df1f8 100644 --- a/mac/Sources/Byre/BoxDiagram.swift +++ b/mac/Sources/Byre/BoxDiagram.swift @@ -1346,11 +1346,14 @@ func fill(_ b: PlacedBox) -> Color { struct BoxCanvas: View { let layout: BoxLayout var focus: BoxFocus? + var region: CGRect? var body: some View { Canvas { context, size in - let scale = layout.size.width > 0 ? size.width / layout.size.width : 1 + let r = region ?? CGRect(origin: .zero, size: layout.size) + let scale = r.width > 0 ? size.width / r.width : 1 context.scaleBy(x: scale, y: scale) + context.translateBy(x: -r.minX, y: -r.minY) draw(&context) } } @@ -1565,17 +1568,43 @@ struct DiagramViewer: View { } } +private let minZoom: CGFloat = 0.25 +private let maxZoom: CGFloat = 6 + private struct SizedCanvas: View { let layout: BoxLayout let focus: BoxFocus? + let zoom: CGFloat var body: some View { - BoxCanvas(layout: layout, focus: focus) - .frame(width: layout.size.width, height: layout.size.height) - .diagramMenu(layout) + ZStack(alignment: .topLeading) { + ForEach(Array(tiles(layout.size, side: 1024 / zoom).enumerated()), id: \.offset) { _, r in + BoxCanvas(layout: layout, focus: focus, region: r) + .frame(width: r.width * zoom, height: r.height * zoom) + .offset(x: r.minX * zoom, y: r.minY * zoom) + } + } + .frame(width: layout.size.width * zoom, height: layout.size.height * zoom, alignment: .topLeading) + .diagramMenu(layout) } } +// The zoom views draw at their zoom rather than scaling a natural-size view, since SwiftUI then draws only a window's +// width of it; tiles keep each canvas within the largest texture the GPU takes. +private func tiles(_ size: CGSize, side: CGFloat) -> [CGRect] { + var out: [CGRect] = [] + var y: CGFloat = 0 + while y < size.height { + var x: CGFloat = 0 + while x < size.width { + out.append(CGRect(x: x, y: y, width: min(side, size.width - x), height: min(side, size.height - y))) + x += side + } + y += side + } + return out +} + private func click(_ layout: BoxLayout, _ p: CGPoint, tap: (String?) -> Void, open: (String) -> Void) { if let id = layout.opener(at: p) { open(id) @@ -1614,15 +1643,64 @@ private final class CenteringClipView: NSClipView { } private final class FittingScrollView: NSScrollView { - var fitted = false + let host: NSHostingView + var diagram: BoxLayout + var focus: BoxFocus? + private(set) var zoom: CGFloat = 1 + private var fit: CGFloat = 1 + private var fitted: CGSize? + + init(_ diagram: BoxLayout, focus: BoxFocus?) { + self.diagram = diagram + self.focus = focus + host = NSHostingView(rootView: SizedCanvas(layout: diagram, focus: focus, zoom: 1)) + super.init(frame: .zero) + contentView = CenteringClipView() + drawsBackground = false + hasVerticalScroller = true + hasHorizontalScroller = true + autohidesScrollers = true + allowsMagnification = true + documentView = host + NotificationCenter.default.addObserver(self, selector: #selector(endMagnify), name: NSScrollView.didEndLiveMagnifyNotification, object: self) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) is not supported") + } + + func render() { + host.rootView = SizedCanvas(layout: diagram, focus: focus, zoom: zoom) + host.frame = CGRect(x: 0, y: 0, width: diagram.size.width * zoom, height: diagram.size.height * zoom) + minMagnification = min(minZoom, fit) / zoom + maxMagnification = maxZoom / zoom + } override func layout() { super.layout() - guard !fitted, let doc = documentView, bounds.width > 0, bounds.height > 0, doc.frame.width > 0 else { + guard fitted != bounds.size, bounds.width > 0, bounds.height > 0, diagram.size.width > 0, diagram.size.height > 0 else { return } - fitted = true - magnification = min(2, bounds.width / doc.frame.width, bounds.height / doc.frame.height) + fitted = bounds.size + fit = min(2, bounds.width / diagram.size.width, bounds.height / diagram.size.height) + zoom = fit + magnification = 1 + render() + } + + @objc private func endMagnify() { + let m = magnification + guard m != 1 else { + return + } + let visible = contentView.bounds + let center = CGPoint(x: visible.midX * m, y: visible.midY * m) + zoom *= m + magnification = 1 + render() + let size = contentView.bounds.size + contentView.scroll(to: CGPoint(x: center.x - size.width / 2, y: center.y - size.height / 2)) + reflectScrolledClipView(contentView) } } @@ -1635,16 +1713,18 @@ private struct ZoomingCanvas: NSViewRepresentable { @MainActor final class Coordinator: NSObject { var canvas: ZoomingCanvas + weak var scroll: FittingScrollView? init(_ canvas: ZoomingCanvas) { self.canvas = canvas } @objc func clicked(_ g: NSClickGestureRecognizer) { - guard let view = g.view else { + guard let view = g.view, let zoom = scroll?.zoom else { return } - click(canvas.layout, g.location(in: view), tap: canvas.tap, open: canvas.open) + let p = g.location(in: view) + click(canvas.layout, CGPoint(x: p.x / zoom, y: p.y / zoom), tap: canvas.tap, open: canvas.open) } } @@ -1653,68 +1733,74 @@ private struct ZoomingCanvas: NSViewRepresentable { } func makeNSView(context: Context) -> FittingScrollView { - let scroll = FittingScrollView() - scroll.contentView = CenteringClipView() - scroll.drawsBackground = false - scroll.hasVerticalScroller = true - scroll.hasHorizontalScroller = true - scroll.autohidesScrollers = true - scroll.allowsMagnification = true - scroll.minMagnification = 0.25 - scroll.maxMagnification = 6 - let host = NSHostingView(rootView: SizedCanvas(layout: layout, focus: focus)) - host.frame = CGRect(origin: .zero, size: layout.size) - host.addGestureRecognizer(NSClickGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.clicked))) - scroll.documentView = host + let scroll = FittingScrollView(layout, focus: focus) + scroll.host.addGestureRecognizer(NSClickGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.clicked))) + context.coordinator.scroll = scroll return scroll } func updateNSView(_ scroll: FittingScrollView, context: Context) { context.coordinator.canvas = self - (scroll.documentView as? NSHostingView)?.rootView = SizedCanvas(layout: layout, focus: focus) + scroll.diagram = layout + scroll.focus = focus + scroll.render() } } #else private struct TappableCanvas: View { let layout: BoxLayout let focus: BoxFocus? + let zoom: CGFloat let tap: (String?) -> Void let open: (String) -> Void var body: some View { - SizedCanvas(layout: layout, focus: focus) + SizedCanvas(layout: layout, focus: focus, zoom: zoom) .contentShape(Rectangle()) .onTapGesture(coordinateSpace: .local) { p in - click(layout, p, tap: tap, open: open) + click(layout, CGPoint(x: p.x / zoom, y: p.y / zoom), tap: tap, open: open) } } } private final class FittingScrollView: UIScrollView, UIScrollViewDelegate { + var canvas: TappableCanvas let host: UIHostingController - private var fitted = false + private var zoom: CGFloat = 1 + private var fit: CGFloat = 1 + private var fitted: CGSize? - init(_ canvas: TappableCanvas, size: CGSize) { + init(_ canvas: TappableCanvas) { + self.canvas = canvas host = UIHostingController(rootView: canvas) super.init(frame: .zero) host.view.backgroundColor = .clear - host.view.frame = CGRect(origin: .zero, size: size) addSubview(host.view) - contentSize = size delegate = self - minimumZoomScale = 0.25 - maximumZoomScale = 6 } required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") } + func render() { + let size = canvas.layout.size + host.rootView = TappableCanvas(layout: canvas.layout, focus: canvas.focus, zoom: zoom, tap: canvas.tap, open: canvas.open) + host.view.frame = CGRect(x: 0, y: 0, width: size.width * zoom, height: size.height * zoom) + contentSize = host.view.frame.size + minimumZoomScale = min(minZoom, fit) / zoom + maximumZoomScale = maxZoom / zoom + } + override func layoutSubviews() { super.layoutSubviews() - if !fitted, bounds.width > 0, bounds.height > 0, host.view.bounds.width > 0 { - fitted = true - zoomScale = min(2, bounds.width / host.view.bounds.width, bounds.height / host.view.bounds.height) + let size = canvas.layout.size + if fitted != bounds.size, bounds.width > 0, bounds.height > 0, size.width > 0, size.height > 0 { + fitted = bounds.size + fit = min(2, bounds.width / size.width, bounds.height / size.height) + zoom = fit + zoomScale = 1 + render() } center() } @@ -1727,6 +1813,18 @@ private final class FittingScrollView: UIScrollView, UIScrollViewDelegate { center() } + func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) { + guard scale != 1 else { + return + } + let offset = contentOffset + zoom *= scale + zoomScale = 1 + render() + contentOffset = offset + center() + } + private func center() { let x = max(0, (bounds.width - contentSize.width) / 2) let y = max(0, (bounds.height - contentSize.height) / 2) @@ -1741,11 +1839,12 @@ private struct ZoomingCanvas: UIViewRepresentable { let open: (String) -> Void func makeUIView(context: Context) -> FittingScrollView { - FittingScrollView(TappableCanvas(layout: layout, focus: focus, tap: tap, open: open), size: layout.size) + FittingScrollView(TappableCanvas(layout: layout, focus: focus, zoom: 1, tap: tap, open: open)) } func updateUIView(_ scroll: FittingScrollView, context: Context) { - scroll.host.rootView = TappableCanvas(layout: layout, focus: focus, tap: tap, open: open) + scroll.canvas = TappableCanvas(layout: layout, focus: focus, zoom: 1, tap: tap, open: open) + scroll.render() } } #endif diff --git a/mac/Sources/Byre/Chat.swift b/mac/Sources/Byre/Chat.swift index 0621928..b175ffe 100644 --- a/mac/Sources/Byre/Chat.swift +++ b/mac/Sources/Byre/Chat.swift @@ -457,7 +457,7 @@ final class ChatModel { if let q = groups.first(where: { $0.id == "questions" }) { return flagged(q) } - if let busy = store.progress(task) { + if let busy = task.state == .running ? store.taskState(task) : store.progress(task) { return ChatStatus(label: busy.label, help: "\(busy.title)\(end)", tone: .working, group: nil) } return groups.first.map(flagged) @@ -991,7 +991,7 @@ private struct TranscriptScroll: View { } .scrollTargetLayout() .overlay(alignment: .bottomLeading) { - if running && model.key != nil { + if running && !model.paused && model.key != nil { Scanner(color: accent) .frame(width: 84, height: 2) .offset(y: 8) @@ -1303,8 +1303,10 @@ struct WhenText: View { let when: Date var body: some View { - Text(ago(when)) - .help(isoText(when)) + TimelineView(.periodic(from: when, by: 60)) { _ in + Text(ago(when)) + } + .help(isoText(when)) } } diff --git a/mac/Sources/Byre/Composer.swift b/mac/Sources/Byre/Composer.swift index 64fb897..5bc5008 100644 --- a/mac/Sources/Byre/Composer.swift +++ b/mac/Sources/Byre/Composer.swift @@ -659,12 +659,31 @@ struct ComposerView: View { chat.showStatus(s) } } - HStack(spacing: 8) { - controls(m) - .frame(maxWidth: .infinity, alignment: .leading) - status - actions(live?.id, running: sessionState == .running, paused: live?.paused ?? false) - .frame(maxWidth: .infinity, alignment: .trailing) + let buttons = actions(live?.id, running: sessionState == .running, paused: live?.paused ?? false) + ViewThatFits(in: .horizontal) { + HStack(spacing: 8) { + controls(m) + .frame(maxWidth: .infinity, alignment: .leading) + status + buttons + .frame(maxWidth: .infinity, alignment: .trailing) + } + VStack(alignment: .trailing, spacing: 8) { + status + HStack(spacing: 8) { + controls(m) + .frame(maxWidth: .infinity, alignment: .leading) + buttons + } + } + VStack(alignment: .leading, spacing: 8) { + controls(m) + HStack(spacing: 8) { + Spacer(minLength: 0) + status + buttons + } + } } } .padding(.horizontal, 16) diff --git a/mac/Sources/Byre/Dialogs.swift b/mac/Sources/Byre/Dialogs.swift index a5888c3..5accc4b 100644 --- a/mac/Sources/Byre/Dialogs.swift +++ b/mac/Sources/Byre/Dialogs.swift @@ -137,9 +137,6 @@ final class Overlays { if switcher != nil { return } - #if os(macOS) - logFocus("open switcher") - #endif switcher = SwitcherModel(store: store, overlays: self, anchor: pickerFrame) } @@ -293,16 +290,6 @@ final class Overlays { #endif } -#if os(macOS) -@MainActor -func logFocus(_ what: String) { - let key = NSApp.keyWindow - let main = NSApp.mainWindow - let responder = key?.firstResponder.map { String(describing: type(of: $0)) } ?? "nil" - log.notice("focus debug: \(what, privacy: .public) active=\(NSApp.isActive) key=\(key?.title ?? "nil", privacy: .public) main=\(main?.title ?? "nil", privacy: .public) mainIsKey=\(main?.isKeyWindow ?? false) responder=\(responder, privacy: .public)") -} -#endif - struct ModalText: View { let text: String diff --git a/mac/Sources/Byre/NetworkWatch.swift b/mac/Sources/Byre/NetworkWatch.swift index ff2cde8..20ecadf 100644 --- a/mac/Sources/Byre/NetworkWatch.swift +++ b/mac/Sources/Byre/NetworkWatch.swift @@ -11,11 +11,11 @@ final class NetworkWatch { static let shared = NetworkWatch() private let monitor = NWPathMonitor() - private var seen = false + private var last: String? private init() { monitor.pathUpdateHandler = { [weak self] path in - let summary = "\(path.status) \(path.availableInterfaces.map(\.name).joined(separator: " "))" + let summary = "\(path.status) \(path.availableInterfaces.map(\.name).joined(separator: " ")) via \(path.gateways.map { "\($0)" }.joined(separator: " "))" Task { @MainActor in self?.pathChanged(summary) } @@ -40,8 +40,12 @@ final class NetworkWatch { } private func pathChanged(_ summary: String) { - guard seen else { - seen = true + let first = last == nil + guard summary != last else { + return + } + last = summary + if first { return } log.notice("network changed (\(summary, privacy: .public)), reconnecting") diff --git a/mac/Sources/Byre/PaneFocus.swift b/mac/Sources/Byre/PaneFocus.swift index a6198ec..1d69002 100644 --- a/mac/Sources/Byre/PaneFocus.swift +++ b/mac/Sources/Byre/PaneFocus.swift @@ -184,7 +184,6 @@ final class PaneFocus { } private func changed(_ name: Notification.Name) { - logFocus(name.rawValue) update() } diff --git a/mac/Sources/Byre/Sheet.swift b/mac/Sources/Byre/Sheet.swift index 2e4b25a..a272f8f 100644 --- a/mac/Sources/Byre/Sheet.swift +++ b/mac/Sources/Byre/Sheet.swift @@ -66,6 +66,7 @@ private struct SheetPanel: View { let sheet: Sheet let overLeft: Bool @Environment(Store.self) private var store + @Environment(Overlays.self) private var overlays var body: some View { let task = store.selectedTaskId.flatMap { store.findTask($0) } @@ -129,7 +130,7 @@ private struct SheetPanel: View { case .diagram: "Diagram" } if !overLeft { - return "Lead · \(label)" + return "\(overlays.leftTab.rawValue.capitalized) · \(label)" } let project = store.focusedProject()?.name ?? "" guard let task else { diff --git a/mac/Sources/Byre/Store.swift b/mac/Sources/Byre/Store.swift index 8178d7b..4d91097 100644 --- a/mac/Sources/Byre/Store.swift +++ b/mac/Sources/Byre/Store.swift @@ -56,6 +56,8 @@ private let stateTitles: [ByreTask.StatePayload: TaskState] = [ .discarded: TaskState(kind: .idle, label: "Discarded", title: "The task was discarded"), ] +private let pausedState = TaskState(kind: .held, label: "Paused", title: "The agent holds after its current step until you resume it") + @MainActor @Observable final class Store { @@ -267,7 +269,10 @@ final class Store { } func taskState(_ task: ByreTask) -> TaskState { - stateTitles[task.state]! + if task.state == .running, (sessions[task.id] ?? []).contains(where: { $0.paused }) { + return pausedState + } + return stateTitles[task.state]! } func progress(_ task: ByreTask) -> TaskState? { diff --git a/mac/Sources/Byre/Switcher.swift b/mac/Sources/Byre/Switcher.swift index 2e5bd8f..79f7b5d 100644 --- a/mac/Sources/Byre/Switcher.swift +++ b/mac/Sources/Byre/Switcher.swift @@ -457,15 +457,11 @@ private struct SwitcherBox: View { .onAppear { DispatchQueue.main.async { #if os(macOS) - logFocus("switcher before focus") if model.inList { overlays.window?.makeFirstResponder(nil) } else { focused = true } - DispatchQueue.main.async { - logFocus("switcher after focus focused=\(focused)") - } #else focused = !model.inList #endif diff --git a/mac/Sources/Byre/TranscriptBuilder.swift b/mac/Sources/Byre/TranscriptBuilder.swift index 08c242e..47cfcef 100644 --- a/mac/Sources/Byre/TranscriptBuilder.swift +++ b/mac/Sources/Byre/TranscriptBuilder.swift @@ -1114,6 +1114,11 @@ private func resultText(_ content: (any Sendable)?) -> String { if let d = c as? JSONDict, let text = d["text"] { return jsString(text) } + if let d = c as? JSONDict, str(d, "type") == "image" { + let source = d["source"] as? JSONDict + let size = (source?["data"] as? String).map { " " + bytes(Int64($0.utf8.count / 4 * 3)) } ?? "" + return "[image\(source.flatMap { str($0, "media_type") }.map { " " + $0 } ?? "")\(size)]" + } return compactJSON(c) }.joined(separator: "\n") } diff --git a/mac/Sources/Byre/WorkflowEditor.swift b/mac/Sources/Byre/WorkflowEditor.swift index aa434cb..9372168 100644 --- a/mac/Sources/Byre/WorkflowEditor.swift +++ b/mac/Sources/Byre/WorkflowEditor.swift @@ -337,7 +337,10 @@ private struct StepRow: View { var body: some View { VStack(alignment: .leading, spacing: 6) { HStack(alignment: .firstTextBaseline, spacing: 6) { - Text(guide).foregroundStyle(Palette.muted) + Text(guide) + .font(Fonts.font(13, mono: true)) + .foregroundStyle(Palette.muted) + .fixedSize() if node.parent?.kind == .random { WeightField(node: node) } @@ -352,13 +355,14 @@ private struct StepRow: View { .frame(width: 12) } .buttonStyle(.plain) - TextField("Stage name", text: $node.name) - .textFieldStyle(.plain) - .font(Fonts.font(13, weight: 700)) - if let agents = node.agents { - Text("team of \(agents.count)").foregroundStyle(Palette.muted).fixedSize() + if touchOnly { + VStack(alignment: .leading, spacing: 4) { + stageName + stageModel + } } else { - ModelPicker(model: $node.model, effort: $node.effort) + stageName + stageModel } case .order: Text("in order").foregroundStyle(Palette.muted) @@ -406,6 +410,21 @@ private struct StepRow: View { } } + private var stageName: some View { + TextField("Stage name", text: $node.name) + .textFieldStyle(.plain) + .font(Fonts.font(13, weight: 700)) + } + + @ViewBuilder + private var stageModel: some View { + if let agents = node.agents { + Text("team of \(agents.count)").foregroundStyle(Palette.muted).fixedSize() + } else { + ModelPicker(model: $node.model, effort: $node.effort) + } + } + private var actions: some View { Menu { switch node.kind {