use serde::Deserialize;
use super::ExtraFields;
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum ClaudeRecord {
User {
message: Message,
#[serde(flatten)]
meta: RecordMeta,
},
Assistant {
message: Message,
#[serde(flatten)]
meta: RecordMeta,
},
System {
#[serde(default)]
subtype: Option<String>,
#[serde(flatten)]
extra: ExtraFields,
},
Attachment {
#[serde(flatten)]
extra: ExtraFields,
},
FileHistorySnapshot {
#[serde(flatten)]
extra: ExtraFields,
},
FileHistoryDelta {
#[serde(flatten)]
extra: ExtraFields,
},
AiTitle {
#[serde(flatten)]
extra: ExtraFields,
},
PermissionMode {
#[serde(flatten)]
extra: ExtraFields,
},
Mode {
#[serde(flatten)]
extra: ExtraFields,
},
LastPrompt {
#[serde(flatten)]
extra: ExtraFields,
},
QueueOperation {
#[serde(flatten)]
extra: ExtraFields,
},
PrLink {
#[serde(flatten)]
extra: ExtraFields,
},
FrameLink {
#[serde(flatten)]
extra: ExtraFields,
},
AgentName {
#[serde(flatten)]
extra: ExtraFields,
},
Started {
#[serde(flatten)]
extra: ExtraFields,
},
Result {
#[serde(flatten)]
extra: ExtraFields,
},
WorktreeState {
#[serde(flatten)]
extra: ExtraFields,
},
ForkContextRef {
#[serde(flatten)]
extra: ExtraFields,
},
#[serde(other)]
Unknown,
}
impl ClaudeRecord {
pub fn tag(&self) -> Option<&'static str> {
Some(match self {
ClaudeRecord::User { .. } => "user",
ClaudeRecord::Assistant { .. } => "assistant",
ClaudeRecord::System { .. } => "system",
ClaudeRecord::Attachment { .. } => "attachment",
ClaudeRecord::FileHistorySnapshot { .. } => "file-history-snapshot",
ClaudeRecord::FileHistoryDelta { .. } => "file-history-delta",
ClaudeRecord::AiTitle { .. } => "ai-title",
ClaudeRecord::PermissionMode { .. } => "permission-mode",
ClaudeRecord::Mode { .. } => "mode",
ClaudeRecord::LastPrompt { .. } => "last-prompt",
ClaudeRecord::QueueOperation { .. } => "queue-operation",
ClaudeRecord::PrLink { .. } => "pr-link",
ClaudeRecord::FrameLink { .. } => "frame-link",
ClaudeRecord::AgentName { .. } => "agent-name",
ClaudeRecord::Started { .. } => "started",
ClaudeRecord::Result { .. } => "result",
ClaudeRecord::WorktreeState { .. } => "worktree-state",
ClaudeRecord::ForkContextRef { .. } => "fork-context-ref",
ClaudeRecord::Unknown => return None,
})
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct RecordMeta {
#[serde(default)]
pub uuid: Option<String>,
#[serde(default)]
pub parent_uuid: Option<String>,
#[serde(default)]
pub is_sidechain: bool,
#[serde(default)]
pub session_id: Option<String>,
#[serde(default)]
pub cwd: Option<String>,
#[serde(default)]
pub git_branch: Option<String>,
#[serde(flatten)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Message {
#[serde(default)]
pub role: Option<String>,
#[serde(default)]
pub model: Option<String>,
#[serde(default)]
pub content: MessageContent,
#[serde(flatten)]
pub extra: ExtraFields,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum MessageContent {
Text(String),
Blocks(Vec<super::ContentBlock>),
}
impl Default for MessageContent {
fn default() -> Self {
MessageContent::Blocks(Vec::new())
}
}