Skip to main content

kaizen/interchange/
diff_attribution.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2//! Diff attribution DTOs. Raw patches stay opt-in.
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
7pub struct DiffAttributionOptions {
8    pub include_raw_patch: bool,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct DiffAttribution {
13    pub session_id: String,
14    pub commit: String,
15    pub summary: DiffSummary,
16    #[serde(default, skip_serializing_if = "Vec::is_empty")]
17    pub files: Vec<FileDiffAttribution>,
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub raw_patch: Option<String>,
20}
21
22#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
23pub struct DiffSummary {
24    pub files_changed: u32,
25    pub additions: u32,
26    pub deletions: u32,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct FileDiffAttribution {
31    pub path: String,
32    pub change: DiffChangeKind,
33    pub additions: u32,
34    pub deletions: u32,
35    #[serde(default, skip_serializing_if = "Vec::is_empty")]
36    pub hunks: Vec<DiffHunkAttribution>,
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub raw_patch: Option<String>,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42#[serde(rename_all = "snake_case")]
43pub enum DiffChangeKind {
44    Added,
45    Modified,
46    Deleted,
47    Renamed { previous_path: String },
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
51pub struct DiffHunkAttribution {
52    pub old_start: u32,
53    pub new_start: u32,
54    pub old_lines: u32,
55    pub new_lines: u32,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub prompt_fingerprint: Option<String>,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub raw_patch: Option<String>,
60}
61
62impl DiffAttributionOptions {
63    pub fn include_raw_patch() -> Self {
64        Self {
65            include_raw_patch: true,
66        }
67    }
68}
69
70impl DiffAttribution {
71    pub fn new(session_id: impl Into<String>, commit: impl Into<String>) -> Self {
72        Self {
73            session_id: session_id.into(),
74            commit: commit.into(),
75            summary: DiffSummary::default(),
76            files: Vec::new(),
77            raw_patch: None,
78        }
79    }
80
81    pub fn with_raw_patch(
82        mut self,
83        raw_patch: impl Into<String>,
84        options: DiffAttributionOptions,
85    ) -> Self {
86        if options.include_raw_patch {
87            self.raw_patch = Some(raw_patch.into());
88        }
89        self
90    }
91}