Watch: snooze finished threads, name the files a file approval would edit, Settle on finished notifications, an instant launch from the saved feed, plain Loading states, and no more cancelled errors
Gateway / check (push) Successful in 9s
Gateway / image (push) Successful in 22s

Gateway: an approval push for a file change says which files it would edit
This commit is contained in:
gib committed 2026-11-02 14:45:34 -05:00
1 parent 4dc4e57dac
commit edc4b88990
35 files changed
+1162 -144

No files matched your search

+25 -1
View File
@@ -59,6 +59,12 @@ protocol GatewayAPI: Sendable {
func recent() async throws -> RecentResponse
/// Settles every completed thread in Recent. Failed threads stay.
func settleRecent() async throws -> SettleRecentResponse
/// Finished threads snoozed for later, the soonest to come back first.
func snoozed() async throws -> RecentResponse
/// Hides a finished thread from Recent until `until`, at most 30 days away.
func snooze(hostId: String, threadId: String, until: Date) async throws
/// Puts a snoozed thread back in Recent now.
func unsnooze(hostId: String, threadId: String) async throws
func projects() async throws -> ProjectsResponse
/// A project's newest 50 threads, settled ones included. Subagents are left out.
func projectThreads(hostId: String, projectId: String) async throws -> ThreadListResponse
@@ -131,6 +137,18 @@ struct GatewayClient: GatewayAPI {
try await call("POST", ["v1", "recent", "settle"])
}
func snoozed() async throws -> RecentResponse {
try await call("GET", ["v1", "snoozed"])
}
func snooze(hostId: String, threadId: String, until: Date) async throws {
try await callIgnoringBody("POST", ["v1", "threads", hostId, threadId, "snooze"], body: SnoozeRequest(until: until))
}
func unsnooze(hostId: String, threadId: String) async throws {
try await callIgnoringBody("POST", ["v1", "threads", hostId, threadId, "unsnooze"], body: nil as SendMessageRequest?)
}
func projects() async throws -> ProjectsResponse {
try await call("GET", ["v1", "projects"])
}
@@ -173,6 +191,12 @@ struct GatewayClient: GatewayAPI {
// MARK: - Plumbing
/// A failed request as the app sees it. A request cancelled because its task was, as when a
/// screen's `.task` ends or a refresh restarts, is a `CancellationError`, which no screen shows.
static func transportError(_ error: URLError) -> any Error {
error.code == .cancelled ? CancellationError() : GatewayError.transport(error.localizedDescription)
}
private func call<Response: Decodable>(
_ method: String, _ path: [String], query: [URLQueryItem] = []
) async throws -> Response {
@@ -216,7 +240,7 @@ struct GatewayClient: GatewayAPI {
do {
(data, response) = try await session.data(for: request)
} catch let error as URLError {
throw GatewayError.transport(error.localizedDescription)
throw Self.transportError(error)
}
guard let http = response as? HTTPURLResponse else {