use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProgressUpdate {
pub timestamp: String,
pub phase: String,
pub previous_phase: Option<String>,
pub iteration: Option<u32>,
pub total_iterations: Option<u32>,
pub review_pass: Option<u32>,
pub total_review_passes: Option<u32>,
pub message: String,
pub event_type: ProgressEventType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ProgressEventType {
PipelineStarted,
PhaseTransition {
from: Option<String>,
to: String,
},
IterationStarted {
iteration: u32,
},
IterationProgress {
current: u32,
total: u32,
},
IterationCompleted {
iteration: u32,
status: String,
},
ReviewPassStarted {
pass: u32,
},
ReviewProgress {
pass: u32,
total: u32,
},
ReviewPassCompleted {
pass: u32,
issues_found: bool,
},
AgentInvoked {
role: String,
agent: String,
},
AgentCompleted {
role: String,
duration_ms: u64,
},
CheckpointSaved,
CommitCreated {
sha: String,
},
PushCompleted {
remote: String,
branch: String,
},
PushFailed {
remote: String,
branch: String,
error: String,
},
PullRequestCreated {
url: String,
number: u32,
},
PullRequestFailed {
error: String,
},
PipelineCompleted {
success: bool,
},
PipelineInterrupted {
reason: String,
},
Heartbeat,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PipelineResult {
pub success: bool,
pub commit_sha: Option<String>,
pub pr_url: Option<String>,
#[serde(default)]
pub push_count: u32,
#[serde(default)]
pub last_pushed_commit: Option<String>,
#[serde(default)]
pub unpushed_commits: Vec<String>,
#[serde(default)]
pub last_push_error: Option<String>,
pub iterations_used: u32,
pub review_passes_used: u32,
pub issues_found: bool,
pub duration_secs: u64,
pub error_message: Option<String>,
}
#[derive(Debug, thiserror::Error)]
pub enum CloudError {
#[error("Configuration error: {0}")]
Configuration(String),
#[error("HTTP error {0}: {1}")]
HttpError(u16, String),
#[error("Network error: {0}")]
NetworkError(String),
#[error("Serialization error: {0}")]
Serialization(String),
}
impl From<std::io::Error> for CloudError {
fn from(e: std::io::Error) -> Self {
CloudError::NetworkError(e.to_string())
}
}
impl CloudError {
pub fn is_success(&self) -> bool {
matches!(self, CloudError::Configuration(_))
}
}
pub fn interpret_http_response(status: u16, body: String) -> Result<(), CloudError> {
if (200..300).contains(&status) {
Ok(())
} else {
Err(CloudError::HttpError(status, body))
}
}
pub const fn heartbeat_drop_join_timeout() -> std::time::Duration {
std::time::Duration::from_millis(50)
}
pub fn heartbeat_should_join_thread(done_received: bool) -> bool {
done_received
}