Skip to main content

agent_migrate_core/
manifest.rs

1use std::collections::BTreeMap;
2
3use jiff::Timestamp;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::bundle::BundleError;
8use crate::{AgentKind, BundleRelativePath, PathMapping, Scope, SecretRef};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11pub struct SchemaVersion {
12    major: u16,
13    minor: u16,
14}
15
16impl SchemaVersion {
17    pub const V1: Self = Self { major: 1, minor: 0 };
18
19    /// Creates a supported Bundle schema version.
20    ///
21    /// # Errors
22    ///
23    /// Returns [`BundleError::UnsupportedMajor`] when `major` is not supported.
24    pub fn new(major: u16, minor: u16) -> Result<Self, BundleError> {
25        if major != Self::V1.major {
26            return Err(BundleError::UnsupportedMajor(major));
27        }
28        Ok(Self { major, minor })
29    }
30
31    #[must_use]
32    pub const fn major(self) -> u16 {
33        self.major
34    }
35
36    #[must_use]
37    pub const fn minor(self) -> u16 {
38        self.minor
39    }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
43#[serde(transparent)]
44pub struct BundleId(Uuid);
45
46impl BundleId {
47    #[must_use]
48    pub const fn from_uuid(value: Uuid) -> Self {
49        Self(value)
50    }
51
52    #[must_use]
53    pub fn new() -> Self {
54        Self(Uuid::new_v4())
55    }
56}
57
58impl Default for BundleId {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
65#[serde(rename_all = "snake_case")]
66pub enum FileKind {
67    Skill,
68    Mcp,
69    Instructions,
70    Command,
71    Agent,
72    Hook,
73    Settings,
74    Passthrough,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78pub struct FileRecord {
79    pub kind: FileKind,
80    pub mode: u32,
81    pub sha256: String,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85pub struct SourceDescriptor {
86    pub agent: AgentKind,
87    pub agent_version: String,
88    pub scope: Scope,
89    pub platform: String,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct SourceEnvironment {
94    agent_version: String,
95    scope: Scope,
96    platform: String,
97}
98
99impl SourceEnvironment {
100    #[must_use]
101    pub fn new(
102        agent_version: impl Into<String>,
103        scope: Scope,
104        platform: impl Into<String>,
105    ) -> Self {
106        Self {
107            agent_version: agent_version.into(),
108            scope,
109            platform: platform.into(),
110        }
111    }
112}
113
114impl SourceDescriptor {
115    #[must_use]
116    pub fn new(agent: AgentKind, environment: SourceEnvironment) -> Self {
117        Self {
118            agent,
119            agent_version: environment.agent_version,
120            scope: environment.scope,
121            platform: environment.platform,
122        }
123    }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct Manifest {
128    pub schema: SchemaVersion,
129    pub bundle_id: BundleId,
130    pub created_at: Timestamp,
131    pub source: SourceDescriptor,
132    pub files: BTreeMap<BundleRelativePath, FileRecord>,
133    #[serde(default, skip_serializing_if = "Vec::is_empty")]
134    pub path_mappings: Vec<PathMapping>,
135    #[serde(default, skip_serializing_if = "Vec::is_empty")]
136    pub secret_references: Vec<SecretRef>,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub struct ManifestIdentity {
141    schema: SchemaVersion,
142    bundle_id: BundleId,
143    created_at: Timestamp,
144}
145
146impl ManifestIdentity {
147    #[must_use]
148    pub const fn new(schema: SchemaVersion, bundle_id: BundleId, created_at: Timestamp) -> Self {
149        Self {
150            schema,
151            bundle_id,
152            created_at,
153        }
154    }
155}
156
157impl Manifest {
158    #[must_use]
159    pub fn new(identity: ManifestIdentity, source: SourceDescriptor) -> Self {
160        Self {
161            schema: identity.schema,
162            bundle_id: identity.bundle_id,
163            created_at: identity.created_at,
164            source,
165            files: BTreeMap::new(),
166            path_mappings: Vec::new(),
167            secret_references: Vec::new(),
168        }
169    }
170
171    #[must_use]
172    pub fn with_path_mappings(mut self, path_mappings: Vec<PathMapping>) -> Self {
173        self.path_mappings = path_mappings;
174        self
175    }
176
177    #[must_use]
178    pub fn with_secret_references(mut self, secret_references: Vec<SecretRef>) -> Self {
179        self.secret_references = secret_references;
180        self
181    }
182}