use crate::types::permission::Ruleset;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Session {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub project_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub directory: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub summary: Option<SessionSummary>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub share: Option<ShareInfo>,
#[serde(default)]
pub title: String,
#[serde(default)]
pub version: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub time: Option<SessionTime>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub permission: Option<Ruleset>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub revert: Option<RevertInfo>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionSummary {
pub additions: u64,
pub deletions: u64,
pub files: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub diffs: Option<Vec<FileDiffLite>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FileDiffLite {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub file: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub before: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub after: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub additions: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deletions: Option<u64>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShareInfo {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub secret: Option<String>,
pub url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionTime {
pub created: i64,
pub updated: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub compacting: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub archived: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RevertInfo {
pub message_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub part_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub snapshot: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub diff: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateSessionRequest {
#[serde(rename = "parentID", default, skip_serializing_if = "Option::is_none")]
pub parent_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub permission: Option<Ruleset>,
#[serde(skip)]
pub directory: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct SessionCreateOptions {
pub parent_id: Option<String>,
pub title: Option<String>,
pub directory: Option<String>,
pub permission: Option<Ruleset>,
}
impl SessionCreateOptions {
pub fn new() -> Self {
Self::default()
}
pub fn with_parent_id(mut self, parent_id: impl Into<String>) -> Self {
self.parent_id = Some(parent_id.into());
self
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn with_directory(mut self, directory: impl Into<String>) -> Self {
self.directory = Some(directory.into());
self
}
pub fn with_permission(mut self, permission: Ruleset) -> Self {
self.permission = Some(permission);
self
}
}
impl From<SessionCreateOptions> for CreateSessionRequest {
fn from(value: SessionCreateOptions) -> Self {
Self {
parent_id: value.parent_id,
title: value.title,
permission: value.permission,
directory: value.directory,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateSessionRequest {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SummarizeRequest {
pub provider_id: String,
pub model_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub auto: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RevertRequest {
pub message_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub part_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SessionStatus {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub active_session_id: Option<String>,
#[serde(default)]
pub busy: bool,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SessionDiff {
#[serde(default)]
pub diff: String,
#[serde(default)]
pub files: Vec<String>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TodoItem {
pub id: String,
pub content: String,
#[serde(default)]
pub completed: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub priority: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_session_deserialize() {
let json = r#"{
"id": "s1",
"projectId": "p1",
"directory": "/path/to/project",
"title": "Test Session",
"version": "1.0",
"time": {"created": 1234567890, "updated": 1234567890}
}"#;
let session: Session = serde_json::from_str(json).unwrap();
assert_eq!(session.id, "s1");
assert_eq!(session.title, "Test Session");
}
#[test]
fn test_session_minimal() {
let json = r#"{"id": "s1"}"#;
let session: Session = serde_json::from_str(json).unwrap();
assert_eq!(session.id, "s1");
assert!(session.project_id.is_none());
}
#[test]
fn test_session_with_optional_fields() {
let json = r#"{
"id": "s1",
"projectId": "p1",
"directory": "/path",
"title": "Test",
"version": "1.0",
"time": {"created": 1234567890, "updated": 1234567890},
"parentId": "s0",
"share": {"url": "https://example.com/share/s1"}
}"#;
let session: Session = serde_json::from_str(json).unwrap();
assert_eq!(session.parent_id, Some("s0".to_string()));
assert!(session.share.is_some());
}
}