agent_workspace_contract/
io.rs1use super::*;
2
3pub const WORKSPACE_VERSION_CONFLICT_CODE: &str = "VERSION_CONFLICT";
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct WorkspaceVersionConflict {
7 pub expected: String,
8 pub actual: Option<String>,
9}
10
11impl fmt::Display for WorkspaceVersionConflict {
12 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
13 write!(
14 formatter,
15 "workspace file revision conflict: expected {}, actual {}",
16 self.expected,
17 self.actual.as_deref().unwrap_or("<missing>")
18 )
19 }
20}
21
22impl std::error::Error for WorkspaceVersionConflict {}
23
24pub fn content_revision(bytes: &[u8]) -> String {
26 use sha2::{Digest as _, Sha256};
27 format!("sha256:{:x}", Sha256::digest(bytes))
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct VersionedFile {
32 pub bytes: Vec<u8>,
33 pub revision: String,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct DirEntry {
39 pub name: String,
40 pub is_dir: bool,
41 pub size: Option<u64>,
42}
43
44#[cfg(test)]
45mod revision_tests {
46 use super::*;
47
48 #[test]
49 fn revision_is_sha256_and_separates_known_fnv_collision_inputs() {
50 let left = content_revision(b"costarring");
53 let right = content_revision(b"liquid");
54 assert_ne!(left, right);
55 for revision in [left, right] {
56 let digest = revision.strip_prefix("sha256:").unwrap();
57 assert_eq!(digest.len(), 64);
58 assert!(digest.bytes().all(|byte| byte.is_ascii_hexdigit()));
59 }
60 }
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65pub struct CmdOutput {
66 pub exit_code: i32,
67 pub stdout: String,
68 pub stderr: String,
69 pub stdout_truncated: bool,
70 pub stderr_truncated: bool,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct PortUrl {
76 pub port: u16,
77 pub url: String,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub host: Option<String>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub token: Option<SecretRef>,
84 #[serde(default)]
85 pub signed: bool,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
88 pub expires_in_seconds: Option<u64>,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92pub struct StaticPreviewServer {
93 pub id: String,
94 pub port: u16,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99pub struct GrepMatch {
100 pub file: String,
101 pub line_number: usize,
102 pub line: String,
103}