diff --git a/src/api/bundle.rs b/src/api/bundle.rs deleted file mode 100644 index 317da353b3..0000000000 --- a/src/api/bundle.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::api::client::ApiClient; -use crate::api::types::{ApiErrorResponse, CreateBundleRequest, CreateBundleResponse}; -use crate::error::GitAiError; - -/// Bundle API endpoints -impl ApiClient { - /// Create a new bundle by posting to /api/bundle - /// - /// # Arguments - /// * `request` - The bundle creation request - /// - /// # Returns - /// * `Ok(CreateBundleResponse)` - Success response with bundle ID and URL - /// * `Err(GitAiError)` - Error response - /// - /// # Errors - /// * Returns `GitAiError::Generic` for HTTP errors - /// * Returns `GitAiError::JsonError` for JSON parsing errors - /// * Returns `GitAiError::Generic` with error details for API errors (400, 500, etc.) - pub fn create_bundle( - &self, - request: CreateBundleRequest, - ) -> Result { - let response = self.context().post_json("/api/bundles", &request)?; - let status_code = response.status_code; - - let body = response - .as_str() - .map_err(|e| GitAiError::Generic(format!("Failed to read response body: {}", e)))?; - - match status_code { - 200 => { - let bundle_response: CreateBundleResponse = - serde_json::from_str(body).map_err(GitAiError::JsonError)?; - Ok(bundle_response) - } - 400 => { - // Try to parse error response - let error_response: ApiErrorResponse = - serde_json::from_str(body).unwrap_or_else(|_| ApiErrorResponse { - error: "Invalid request body".to_string(), - details: Some(serde_json::Value::String(body.to_string())), - }); - Err(GitAiError::Generic(format!( - "Bad Request: {}", - error_response.error - ))) - } - 500 => { - let error_response: ApiErrorResponse = - serde_json::from_str(body).unwrap_or_else(|_| ApiErrorResponse { - error: "Internal server error".to_string(), - details: None, - }); - Err(GitAiError::Generic(format!( - "Internal Server Error: {}", - error_response.error - ))) - } - _ => Err(GitAiError::Generic(format!( - "Unexpected status code {}: {}", - status_code, body - ))), - } - } -} diff --git a/src/api/cas.rs b/src/api/cas.rs index 7497fd07c5..39279bae5f 100644 --- a/src/api/cas.rs +++ b/src/api/cas.rs @@ -1,7 +1,5 @@ use crate::api::client::ApiClient; -use crate::api::types::{ - ApiErrorResponse, CAPromptStoreReadResponse, CasUploadRequest, CasUploadResponse, -}; +use crate::api::types::{ApiErrorResponse, CasUploadRequest, CasUploadResponse}; use crate::error::GitAiError; /// CAS API endpoints @@ -56,57 +54,4 @@ impl ApiClient { ))), } } - - /// Read CAS objects by hash from the server - /// - /// # Arguments - /// * `hashes` - Slice of CAS hashes to fetch (max 100 per call) - /// - /// # Returns - /// * `Ok(CAPromptStoreReadResponse)` - Response with results for each hash - /// * `Err(GitAiError)` - On network or server errors - pub fn read_ca_prompt_store( - &self, - hashes: &[&str], - ) -> Result { - // Validate all hashes are hex-only before building the URL to prevent - // injection via crafted hash values in the query string. - for hash in hashes { - if !hash.chars().all(|c| c.is_ascii_hexdigit()) { - return Err(GitAiError::Generic(format!( - "CAS hash contains non-hex characters: {}", - hash - ))); - } - } - - let query = hashes.join(","); - let endpoint = format!("/worker/cas/?hashes={}", query); - let response = self.context().get(&endpoint)?; - let status_code = response.status_code; - - let body = response - .as_str() - .map_err(|e| GitAiError::Generic(format!("Failed to read response body: {}", e)))?; - - match status_code { - 200 => { - let cas_response: CAPromptStoreReadResponse = - serde_json::from_str(body).map_err(GitAiError::JsonError)?; - Ok(cas_response) - } - 404 => { - // All hashes not found — return empty response gracefully - Ok(CAPromptStoreReadResponse { - results: Vec::new(), - success_count: 0, - failure_count: hashes.len(), - }) - } - _ => Err(GitAiError::Generic(format!( - "CAS read failed with status {}: {}", - status_code, body - ))), - } - } } diff --git a/src/api/mod.rs b/src/api/mod.rs index e8de28efe3..fbf7447350 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,4 +1,3 @@ -pub mod bundle; pub mod cas; pub mod client; pub mod metrics; diff --git a/src/api/types.rs b/src/api/types.rs index 0f0b92b10d..58be99b509 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -1,4 +1,4 @@ -use crate::authorship::authorship_log::{LineRange, PromptRecord}; +use crate::authorship::authorship_log::LineRange; use crate::commands::diff::FileDiffJson; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -44,34 +44,6 @@ impl From<&FileDiffJson> for ApiFileRecord { } } -/// Bundle data containing prompts and optional files -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct BundleData { - /// REQUIRED: At least one prompt - pub prompts: HashMap, - /// OPTIONAL: File diffs and annotations - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub files: HashMap, -} - -/// Request body for creating a bundle -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CreateBundleRequest { - /// Bundle title (min 1 character) - pub title: String, - /// Bundle data containing prompts and optional files - pub data: BundleData, - // TODO PR Metadata if linked to PR -} - -/// Success response from bundle creation -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct CreateBundleResponse { - pub success: bool, - pub id: String, - pub url: String, -} - /// Error response from API #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ApiErrorResponse { @@ -112,12 +84,6 @@ pub struct CasUploadResponse { pub failure_count: usize, } -/// Wrapper for messages stored in CAS -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CasMessagesObject { - pub messages: Vec, -} - /// A single authorship note entry (commit SHA + content). #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct NoteEntry { @@ -144,25 +110,6 @@ pub struct NotesReadResponse { pub notes: std::collections::HashMap, } -/// Single result from CA prompt store batch read -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CAPromptStoreReadResult { - pub hash: String, - pub status: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub content: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub error: Option, -} - -/// Response from CA prompt store batch read -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CAPromptStoreReadResponse { - pub results: Vec, - pub success_count: usize, - pub failure_count: usize, -} - #[cfg(test)] mod tests { use super::*; @@ -280,20 +227,6 @@ mod tests { assert_eq!(ranges[2], serde_json::Value::Number(20.into())); } - #[test] - fn test_create_bundle_response_deserialization() { - let json = r#"{ - "success": true, - "id": "bundle123", - "url": "https://example.com/bundle123" - }"#; - - let response: CreateBundleResponse = serde_json::from_str(json).unwrap(); - assert!(response.success); - assert_eq!(response.id, "bundle123"); - assert_eq!(response.url, "https://example.com/bundle123"); - } - #[test] fn test_api_error_response_serialization() { let error = ApiErrorResponse { @@ -428,21 +361,4 @@ mod tests { let cloned = record.clone(); assert_eq!(record, cloned); } - - #[test] - fn test_cas_messages_object() { - use crate::authorship::transcript::Message; - - let messages = vec![Message::user("test".to_string(), None)]; - - let cas_msg = CasMessagesObject { - messages: messages.clone(), - }; - - let json = serde_json::to_string(&cas_msg).unwrap(); - assert!(json.contains("test")); - - let deserialized: CasMessagesObject = serde_json::from_str(&json).unwrap(); - assert_eq!(deserialized.messages.len(), 1); - } }