1use serde::Serialize;
2
3pub const BUNDLE_MANIFEST_SCHEMA_VERSION: &str = "agentctl.debug.bundle.v1";
4pub const BUNDLE_MANIFEST_VERSION: u32 = 1;
5pub const BUNDLE_MANIFEST_FILE_NAME: &str = "manifest.json";
6pub const BUNDLE_ARTIFACTS_DIR: &str = "artifacts";
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
9#[serde(rename_all = "kebab-case")]
10pub enum ArtifactStatus {
11 Collected,
12 Failed,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
16pub struct BundleArtifact {
17 pub id: String,
18 pub path: String,
19 pub status: ArtifactStatus,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub error: Option<String>,
22}
23
24impl BundleArtifact {
25 pub fn collected(id: impl Into<String>, path: impl Into<String>) -> Self {
26 Self {
27 id: id.into(),
28 path: path.into(),
29 status: ArtifactStatus::Collected,
30 error: None,
31 }
32 }
33
34 pub fn failed(
35 id: impl Into<String>,
36 path: impl Into<String>,
37 error: impl Into<String>,
38 ) -> Self {
39 Self {
40 id: id.into(),
41 path: path.into(),
42 status: ArtifactStatus::Failed,
43 error: Some(error.into()),
44 }
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
49pub struct BundleSummary {
50 pub total_artifacts: usize,
51 pub collected: usize,
52 pub failed: usize,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
56pub struct BundleManifest {
57 pub schema_version: &'static str,
58 pub manifest_version: u32,
59 pub command: &'static str,
60 pub output_dir: String,
61 pub partial_failure: bool,
62 pub summary: BundleSummary,
63 pub artifacts: Vec<BundleArtifact>,
64}
65
66impl BundleManifest {
67 pub fn from_artifacts(output_dir: String, artifacts: Vec<BundleArtifact>) -> Self {
68 let failed = artifacts
69 .iter()
70 .filter(|artifact| artifact.status == ArtifactStatus::Failed)
71 .count();
72 let collected = artifacts.len().saturating_sub(failed);
73
74 Self {
75 schema_version: BUNDLE_MANIFEST_SCHEMA_VERSION,
76 manifest_version: BUNDLE_MANIFEST_VERSION,
77 command: "debug.bundle",
78 output_dir,
79 partial_failure: failed > 0,
80 summary: BundleSummary {
81 total_artifacts: artifacts.len(),
82 collected,
83 failed,
84 },
85 artifacts,
86 }
87 }
88}