//! Shared Workspace HTTP resource contracts. //! //! This crate owns transport DTOs exposed by the Workspace Server and consumed //! by Rust clients. Runtime-internal projections remain in their owning crates; //! callers must explicitly construct these Workspace-authoritative resources. use serde::{Deserialize, Serialize}; use workdir::workspace::WorkingDirectorySummary; pub const TICKET_RELATIONS_QUERY_PATH: &str = "/tickets/relations/search"; pub const TICKET_ORCHESTRATION_PLANS_QUERY_PATH: &str = "/tickets/orchestration-plans/search"; #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum DiagnosticSeverity { Info, Warning, Error, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Diagnostic { pub code: String, pub severity: DiagnosticSeverity, pub message: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ListResponse { pub workspace_id: String, pub limit: usize, pub items: Vec, pub source: String, #[serde(default)] pub diagnostics: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] #[cfg_attr(feature = "typescript", derive(ts_rs::TS))] pub struct QueryPage { pub limit: usize, pub returned: usize, pub has_more: bool, pub next_cursor: Option, pub sort: String, pub source_limit: Option, pub source_truncated: bool, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveEventDetail { pub event_ref: String, pub kind: String, pub body: Option, pub created_at: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveLinkedTicketSummary { pub id: String, pub resource_key: String, pub title: String, pub state: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveResourceSummary { pub path: String, pub media_type: Option, pub bytes: usize, pub updated_at: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveSummary { pub id: String, pub resource_key: String, pub title: String, pub state: String, pub created_at: Option, pub updated_at: Option, pub summary: String, pub linked_tickets: Vec, pub record_source: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveDetail { pub id: String, pub resource_key: String, pub title: String, pub state: String, pub revision: String, pub created_at: Option, pub updated_at: Option, pub linked_tickets: Vec, pub linked_ticket_summaries: Vec, pub resources: Vec, pub body: String, pub body_truncated: bool, pub events: Vec, pub event_page: QueryPage, pub record_source: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveCreateRequest { pub title: String, #[serde(default)] pub body_md: String, #[serde(default = "default_objective_state")] pub state: String, #[serde(default)] pub linked_tickets: Vec, } fn default_objective_state() -> String { "active".to_string() } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct ObjectiveEditRequest { pub title: Option, pub old_string: Option, pub new_string: Option, #[serde(default)] pub replace_all: bool, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveStateRequest { pub state: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ObjectiveLinkTicketRequest { pub ticket_id: String, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RuntimeSourceKind { EmbeddedWorkerRuntime, RemoteHttp, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RuntimeSourceStatus { Active, Reserved, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RuntimeIdentityAuthority { RuntimeRegistryProjection, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RuntimeSourceSummary { pub kind: RuntimeSourceKind, pub status: RuntimeSourceStatus, pub identity_authority: RuntimeIdentityAuthority, pub note: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RuntimeCapabilitySummary { pub can_list_hosts: bool, pub can_list_workers: bool, pub can_get_worker: bool, pub can_spawn_worker: bool, pub can_stop_worker: bool, pub has_workspace_fs: bool, pub has_shell: bool, pub has_git: bool, pub supports_worktrees: bool, pub supports_backend_internal_tools: bool, pub workspace_scope: String, pub max_workers: usize, pub os: String, pub arch: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct RuntimeSummary { pub runtime_id: String, pub label: String, pub kind: String, pub status: String, pub source: RuntimeSourceSummary, #[serde(default)] pub host_ids: Vec, pub capabilities: RuntimeCapabilitySummary, #[serde(default)] pub diagnostics: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerWorkspaceSummary { pub visibility: String, pub identity: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub workspace_id: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerImplementationSummary { pub kind: String, pub display_hint: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerCapabilitySummary { pub can_stop: bool, pub can_spawn_followup: bool, } /// Workspace-authoritative Worker projection. /// /// `resource_key` is required here even though Runtime-internal Worker summaries /// do not carry one. The Workspace Server must resolve it from Workspace /// authority before constructing this response. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerSummary { pub runtime_id: String, pub worker_id: String, pub resource_key: String, pub host_id: String, #[serde(default)] pub display_name: String, pub label: String, pub profile: Option, pub singleton_key: Option, #[serde(default)] pub tags: Vec, pub workspace: WorkerWorkspaceSummary, pub state: String, pub last_seen_at: Option, #[serde(default)] pub pinned: bool, #[serde(default)] pub retention_state: String, pub implementation: WorkerImplementationSummary, pub capabilities: WorkerCapabilitySummary, #[serde(default, skip_serializing_if = "Option::is_none")] pub working_directory: Option, #[serde(default)] pub diagnostics: Vec, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum WorkerOperationState { Accepted, Unsupported, Rejected, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerRestoreResult { pub state: WorkerOperationState, pub worker: Option, #[serde(default)] pub diagnostics: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct WorkerRestoreResponse { pub workspace_id: String, pub runtime_id: String, pub worker_id: String, pub result: WorkerRestoreResult, } /// Workspace-owned Memory settings returned by the shared Server API. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct WorkspaceMemorySettings { pub workspace_id: String, pub settings_revision: u64, pub language: String, } /// Compare-and-swap update for Workspace-owned Memory settings. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct UpdateWorkspaceMemorySettingsRequest { pub expected_revision: u64, pub language: String, } #[cfg(test)] mod tests { use super::*; #[test] fn worker_resource_key_is_required() { let payload = serde_json::json!({ "runtime_id": "arcadia", "worker_id": "worker-1", "host_id": "host", "display_name": "Coder", "label": "Coder", "workspace": { "visibility": "workspace", "identity": "workspace-test" }, "state": "idle", "implementation": {"kind": "worker", "display_hint": "Coder"}, "capabilities": {"can_stop": true, "can_spawn_followup": false} }); assert!(serde_json::from_value::(payload).is_err()); } }