import Foundation import Tagged public enum WorkspaceIDTag: Sendable {} public typealias WorkspaceID = Tagged public enum WorkspaceBranchTag: Sendable {} public typealias WorkspaceBranch = Tagged public enum WorkspaceRevisionTag: Sendable {} public typealias WorkspaceRevision = Tagged public enum WorkspaceProposalIDTag: Sendable {} public typealias WorkspaceProposalID = Tagged public enum WorkspaceConflictPathTag: Sendable {} public typealias WorkspaceConflictPath = Tagged public struct WorkspaceBranchReference: Codable, Equatable, Sendable { public var branch: WorkspaceBranch public var revision: WorkspaceRevision public init(branch: WorkspaceBranch, revision: WorkspaceRevision) { self.branch = branch self.revision = revision } } public struct WorkspaceReconciliationConflict: Equatable, Sendable { public var baseline: WorkspaceBranchReference public var upstream: WorkspaceBranchReference public var conflictingPaths: [WorkspaceConflictPath] public init( baseline: WorkspaceBranchReference, upstream: WorkspaceBranchReference, conflictingPaths: [WorkspaceConflictPath] ) { self.baseline = baseline self.upstream = upstream self.conflictingPaths = conflictingPaths } } public enum WorkspaceReconciliation: Equatable, Sendable { case current case reconciling case conflicted(WorkspaceReconciliationConflict) } public enum WorkspaceReconciliationResult: Sendable { /// The returned session has been verified against the current remote branch. case current(WorkspaceSession) case conflicted(WorkspaceReconciliationConflict) } extension WorkspaceReconciliationResult: Equatable where Source: Equatable {} public struct WorkspaceProposalTitle: Codable, Equatable, Sendable { public let rawValue: String public init?(_ rawValue: String) { let value = rawValue.trimmingCharacters(in: .whitespacesAndNewlines) guard !value.isEmpty else { return nil } self.rawValue = value } public init(from decoder: any Decoder) throws { let container = try decoder.singleValueContainer() let value = try container.decode(String.self) guard let title = Self(value) else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "A workspace proposal title cannot be empty." ) } self = title } public func encode(to encoder: any Encoder) throws { var container = encoder.singleValueContainer() try container.encode(rawValue) } } public struct WorkspaceProposalDetails: Codable, Equatable, Sendable { public var description: String? public var title: WorkspaceProposalTitle public init(title: WorkspaceProposalTitle, description: String? = nil) { let description = description?.trimmingCharacters(in: .whitespacesAndNewlines) self.description = description?.isEmpty == false ? description : nil self.title = title } } /// User-authored commit metadata shared by proposal and direct publication flows. public struct WorkspacePublicationDetails: Codable, Equatable, Sendable { public var description: String? public var title: WorkspaceProposalTitle public init(title: WorkspaceProposalTitle, description: String? = nil) { let description = description?.trimmingCharacters(in: .whitespacesAndNewlines) self.description = description?.isEmpty == false ? description : nil self.title = title } public var proposalDetails: WorkspaceProposalDetails { WorkspaceProposalDetails(title: title, description: description) } } public struct WorkspaceProposal: Codable, Equatable, Sendable { /// The exact remote proposal record URI. public var id: WorkspaceProposalID /// The opaque revision represented by the proposal's patch. public var revision: WorkspaceRevision /// The exact Published branch revision against which the proposal was opened. public var target: WorkspaceBranchReference public init( id: WorkspaceProposalID, revision: WorkspaceRevision, target: WorkspaceBranchReference ) { self.id = id self.revision = revision self.target = target } private enum CodingKeys: String, CodingKey { case id case revision case source case target } public init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(WorkspaceProposalID.self, forKey: .id) self.target = try container.decode(WorkspaceBranchReference.self, forKey: .target) if let revision = try container.decodeIfPresent( WorkspaceRevision.self, forKey: .revision ) { self.revision = revision } else { self.revision = try container.decode( WorkspaceBranchReference.self, forKey: .source ).revision } } public func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(revision, forKey: .revision) try container.encode(target, forKey: .target) } } /// The complete state Workspace owns for one local editable workspace. public struct WorkspaceState: Sendable { public let id: WorkspaceID public var availability: WorkspaceAvailability public var reconciliation: WorkspaceReconciliation public init( id: WorkspaceID, availability: WorkspaceAvailability = .inactive, reconciliation: WorkspaceReconciliation = .current ) { self.id = id self.availability = availability self.reconciliation = reconciliation } } public extension WorkspaceState { var session: WorkspaceSession? { guard case let .ready(session) = availability else { return nil } return session } var baseline: WorkspaceBranchReference? { session?.baseline } var preparationFailure: WorkspaceFailure? { guard case let .preparationFailed(failure) = availability else { return nil } return failure } } extension WorkspaceState: Equatable where Source: Equatable {} public enum WorkspaceAvailability: Sendable { case inactive case preparing case preparationFailed(WorkspaceFailure) case ready(WorkspaceSession) } extension WorkspaceAvailability: Equatable where Source: Equatable {} /// A coherent editable source and the exact branch revision against which edits are compared. public struct WorkspaceSession: Sendable { public var source: Source public var baseline: WorkspaceBranchReference public init(source: Source, baseline: WorkspaceBranchReference) { self.source = source self.baseline = baseline } } extension WorkspaceSession: Equatable where Source: Equatable {} /// One in-memory publication attempt. It is deliberately not durable workspace state. public struct WorkspaceProposalAttempt: Equatable, Sendable { public let changes: ChangeSet public let details: WorkspaceProposalDetails public let target: WorkspaceBranchReference public init( changes: ChangeSet, details: WorkspaceProposalDetails, target: WorkspaceBranchReference ) { self.changes = changes self.details = details self.target = target } } /// One request to publish the captured changes directly to an exact Published branch head. public struct WorkspacePublicationAttempt: Equatable, Sendable { public let changes: ChangeSet public let details: WorkspacePublicationDetails public let target: WorkspaceBranchReference public init( changes: ChangeSet, details: WorkspacePublicationDetails, target: WorkspaceBranchReference ) { self.changes = changes self.details = details self.target = target } } public enum WorkspaceChangeCapture: Equatable, Sendable { case changes(ChangeSet) case noChanges } /// The result after a proposal record exists remotely. /// /// Proposal publication does not change the editable workspace or its baseline. public struct WorkspaceProposalPublication: Equatable, Sendable { public var proposal: WorkspaceProposal public init(proposal: WorkspaceProposal) { self.proposal = proposal } } /// The result after changes have been merged directly into the Published branch. /// /// `session` contains the installed Published revision, or the prior coherent Published baseline /// when the integration has recorded durable local repair work. public struct WorkspacePublishedChanges: Sendable { public var published: WorkspaceBranchReference public var session: WorkspaceSession public init( published: WorkspaceBranchReference, session: WorkspaceSession ) { self.published = published self.session = session } } extension WorkspacePublishedChanges: Equatable where Source: Equatable {} public struct WorkspaceFailure: Equatable, Error, Sendable { public var message: String public init(message: String) { self.message = message } public init(_ error: any Error) { self.message = String(reflecting: error) } } public struct WorkspaceHeadMismatch: Equatable, Error, Sendable { public var observedRevision: WorkspaceRevision public init(observedRevision: WorkspaceRevision) { self.observedRevision = observedRevision } } public struct WorkspacePublicationConflict: Equatable, Error, Sendable { public var conflictingPaths: [WorkspaceConflictPath] public init(conflictingPaths: [WorkspaceConflictPath]) { self.conflictingPaths = conflictingPaths } } public enum WorkspaceAuthorizationError: Equatable, Error, Sendable { case invalidated } public enum WorkspaceTransitionError: Equatable, Error, Sendable { case publicationReturnedWrongProposal case publicationDidNotInstallPublishedBranch case reconciledBaselineChangedBranch case selectedBaselineDoesNotMatchRequest }