bamboo_server/handlers/command/
types.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize, Clone)]
5#[serde(rename_all = "lowercase")]
6pub enum CommandType {
7 Prompt,
9 Workflow,
11 Skill,
13 Mcp,
15}
16
17#[derive(Debug, Serialize, Clone)]
19pub struct CommandItem {
20 pub id: String,
21 pub name: String,
22 pub display_name: String,
23 pub description: String,
24 #[serde(rename = "type")]
25 pub command_type: String,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub category: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub tags: Option<Vec<String>>,
30 pub metadata: serde_json::Value,
31}
32
33#[derive(Debug, Default, Deserialize)]
34pub struct ListCommandsQuery {
35 #[serde(default)]
36 pub workspace_path: Option<String>,
37 #[serde(default)]
38 pub session_id: Option<String>,
39}
40
41#[derive(Debug, Default, Deserialize)]
42pub struct GetCommandQuery {
43 #[serde(default)]
44 pub workspace_path: Option<String>,
45 #[serde(default)]
46 pub session_id: Option<String>,
47 #[serde(default)]
48 pub arguments: Option<String>,
49}
50
51#[derive(Debug, Serialize)]
53pub struct CommandListResponse {
54 pub commands: Vec<CommandItem>,
55 pub total: usize,
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn test_command_type_serialization() {
64 let workflow = CommandType::Workflow;
65 assert_eq!(serde_json::to_string(&workflow).unwrap(), "\"workflow\"");
66
67 let prompt = CommandType::Prompt;
68 assert_eq!(serde_json::to_string(&prompt).unwrap(), "\"prompt\"");
69
70 let skill = CommandType::Skill;
71 assert_eq!(serde_json::to_string(&skill).unwrap(), "\"skill\"");
72
73 let mcp = CommandType::Mcp;
74 assert_eq!(serde_json::to_string(&mcp).unwrap(), "\"mcp\"");
75 }
76
77 #[test]
78 fn test_command_type_deserialization() {
79 let workflow: CommandType = serde_json::from_str("\"workflow\"").unwrap();
80 assert!(matches!(workflow, CommandType::Workflow));
81
82 let skill: CommandType = serde_json::from_str("\"skill\"").unwrap();
83 assert!(matches!(skill, CommandType::Skill));
84
85 let mcp: CommandType = serde_json::from_str("\"mcp\"").unwrap();
86 assert!(matches!(mcp, CommandType::Mcp));
87 }
88
89 #[test]
90 fn test_command_type_clone() {
91 let cmd = CommandType::Workflow;
92 let cloned = cmd.clone();
93 assert!(matches!(cloned, CommandType::Workflow));
94 }
95
96 #[test]
97 fn test_command_type_debug() {
98 let cmd = CommandType::Skill;
99 let debug_str = format!("{:?}", cmd);
100 assert!(debug_str.contains("Skill"));
101 }
102
103 #[test]
104 fn test_command_item_serialization() {
105 let item = CommandItem {
106 id: "cmd-1".to_string(),
107 name: "test_command".to_string(),
108 display_name: "Test Command".to_string(),
109 description: "A test".to_string(),
110 command_type: "workflow".to_string(),
111 category: Some("general".to_string()),
112 tags: Some(vec!["test".to_string()]),
113 metadata: serde_json::json!({"key": "value"}),
114 };
115
116 let json = serde_json::to_string(&item).unwrap();
117 assert!(json.contains("cmd-1"));
118 assert!(json.contains("test_command"));
119 assert!(json.contains("Test Command"));
120 assert!(json.contains("workflow"));
121 assert!(json.contains("category"));
122 assert!(json.contains("tags"));
123 }
124
125 #[test]
126 fn test_command_item_skip_none_fields() {
127 let item = CommandItem {
128 id: "cmd-2".to_string(),
129 name: "test".to_string(),
130 display_name: "Test".to_string(),
131 description: "Desc".to_string(),
132 command_type: "skill".to_string(),
133 category: None,
134 tags: None,
135 metadata: serde_json::json!(null),
136 };
137
138 let json = serde_json::to_string(&item).unwrap();
139 assert!(!json.contains("category"));
140 assert!(!json.contains("tags"));
141 }
142
143 #[test]
144 fn test_command_item_debug() {
145 let item = CommandItem {
146 id: "id".to_string(),
147 name: "name".to_string(),
148 display_name: "Display".to_string(),
149 description: "desc".to_string(),
150 command_type: "mcp".to_string(),
151 category: None,
152 tags: None,
153 metadata: serde_json::json!({}),
154 };
155
156 let debug_str = format!("{:?}", item);
157 assert!(debug_str.contains("CommandItem"));
158 }
159
160 #[test]
161 fn test_command_list_response_serialization() {
162 let response = CommandListResponse {
163 commands: vec![],
164 total: 0,
165 };
166
167 let json = serde_json::to_string(&response).unwrap();
168 assert!(json.contains("\"commands\":[]"));
169 assert!(json.contains("\"total\":0"));
170 }
171
172 #[test]
173 fn test_command_list_response_with_commands() {
174 let item = CommandItem {
175 id: "1".to_string(),
176 name: "cmd".to_string(),
177 display_name: "Command".to_string(),
178 description: "Test".to_string(),
179 command_type: "workflow".to_string(),
180 category: None,
181 tags: None,
182 metadata: serde_json::json!({}),
183 };
184
185 let response = CommandListResponse {
186 commands: vec![item],
187 total: 1,
188 };
189
190 let json = serde_json::to_string(&response).unwrap();
191 assert!(json.contains("\"total\":1"));
192 }
193
194 #[test]
195 fn test_command_list_response_debug() {
196 let response = CommandListResponse {
197 commands: vec![],
198 total: 0,
199 };
200
201 let debug_str = format!("{:?}", response);
202 assert!(debug_str.contains("CommandListResponse"));
203 }
204}