macOS client store and API

This commit is contained in:
Ian Gulliver
2026-10-16 22:46:54 -07:00
parent b28968a0bc
commit a9bec7a7ea
22 changed files with 1508 additions and 251 deletions
+15 -21
View File
@@ -6,7 +6,7 @@ let exitedCode = 4000
let internalErrorCode = 1011
struct TerminalSpike: View {
@Environment(Server.self) private var server
@Environment(Store.self) private var store
@ViewState private var status = ""
var body: some View {
@@ -16,24 +16,26 @@ struct TerminalSpike: View {
Text(status)
.foregroundStyle(.secondary)
}
if server.taskId.isEmpty {
Text("No task selected.")
} else if server.tasks.first(where: { $0.id == server.taskId })?.status != "active" {
Text("The task is closed; its worktree is gone.")
if let taskId = store.selectedTaskId {
if store.findTask(taskId)?.status != .active {
Text("The task is closed; its worktree is gone.")
} else {
TerminalHost(api: store.api, taskId: taskId, status: $status)
}
} else {
TerminalHost(server: server, taskId: server.taskId, status: $status)
Text("No task selected.")
}
}
}
}
struct TerminalHost: NSViewRepresentable {
let server: Server
let api: API
let taskId: String
@Binding var status: String
func makeCoordinator() -> TerminalSession {
TerminalSession(server: server, taskId: taskId) { s in
TerminalSession(api: api, taskId: taskId) { s in
status = s
}
}
@@ -59,14 +61,14 @@ struct TerminalHost: NSViewRepresentable {
@MainActor
final class TerminalSession: NSObject, TerminalViewDelegate {
let server: Server
let api: API
let taskId: String
let show: (String) -> Void
weak var view: TerminalView?
private var ws: URLSessionWebSocketTask?
init(server: Server, taskId: String, show: @escaping (String) -> Void) {
self.server = server
init(api: API, taskId: String, show: @escaping (String) -> Void) {
self.api = api
self.taskId = taskId
self.show = show
}
@@ -76,16 +78,8 @@ final class TerminalSession: NSObject, TerminalViewDelegate {
return
}
let t = view.terminalDimensions
guard let http = try? server.url("/api/tasks/\(taskId)/terminal", [URLQueryItem(name: "cols", value: String(t.cols)), URLQueryItem(name: "rows", value: String(t.rows))]), var c = URLComponents(url: http, resolvingAgainstBaseURL: false) else {
show("not connected")
return
}
c.scheme = "wss"
guard let wss = c.url else {
show("bad terminal URL")
return
}
let task = URLSession.shared.webSocketTask(with: wss)
let wss = api.url("/api/tasks/\(taskId)/terminal", [URLQueryItem(name: "cols", value: String(t.cols)), URLQueryItem(name: "rows", value: String(t.rows))], scheme: "wss")
let task = api.session.webSocketTask(with: wss)
ws = task
show("connecting…")
task.resume()