abyss_agent_hook/harness/
id.rs1use std::{borrow::Borrow, fmt};
4
5use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
6
7#[derive(Clone, Copy, Debug)]
9#[non_exhaustive]
10pub enum BuiltInHarness {
11 Codex,
13 ClaudeCode,
15 ClaudeDesktop,
17}
18
19impl BuiltInHarness {
20 #[must_use]
22 pub const fn id(self) -> &'static str {
23 match self {
24 Self::Codex => "codex",
25 Self::ClaudeCode => "claude-code",
26 Self::ClaudeDesktop => "claude-desktop",
27 }
28 }
29}
30
31#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
33pub struct HarnessId(String);
34
35impl HarnessId {
36 #[must_use]
38 pub fn as_str(&self) -> &str {
39 &self.0
40 }
41
42 #[must_use]
44 pub(crate) fn is_reserved(&self) -> bool {
45 matches!(
46 self.as_str(),
47 "codex" | "claude-code" | "claude-desktop" | "openclaw"
48 )
49 }
50}
51
52impl From<BuiltInHarness> for HarnessId {
53 fn from(value: BuiltInHarness) -> Self {
54 Self(value.id().to_owned())
55 }
56}
57
58impl Borrow<str> for HarnessId {
59 fn borrow(&self) -> &str {
60 self.as_str()
61 }
62}
63
64impl fmt::Display for HarnessId {
65 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
66 formatter.write_str(self.as_str())
67 }
68}
69
70impl Serialize for HarnessId {
71 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
72 where
73 S: Serializer,
74 {
75 serializer.serialize_str(self.as_str())
76 }
77}
78
79impl<'de> Deserialize<'de> for HarnessId {
80 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
81 where
82 D: Deserializer<'de>,
83 {
84 let value = String::deserialize(deserializer)?;
85 let value = if value == "claude-cli" {
86 BuiltInHarness::ClaudeCode.id().to_owned()
87 } else {
88 value
89 };
90 if value.is_empty()
91 || value.len() > 64
92 || !value.bytes().all(|byte| {
93 byte.is_ascii_lowercase()
94 || byte.is_ascii_digit()
95 || matches!(byte, b'.' | b'_' | b'-')
96 })
97 {
98 return Err(D::Error::custom(
99 "Harness id must contain 1-64 lowercase ASCII letters, digits, '.', '_', or '-'",
100 ));
101 }
102 Ok(Self(value))
103 }
104}