claude_agent/common/
index.rs1use async_trait::async_trait;
7
8use super::{ContentSource, Named, SourceType};
9
10#[async_trait]
40pub trait Index: Named + Clone + Send + Sync + 'static {
41 fn source(&self) -> &ContentSource;
43
44 fn source_type(&self) -> SourceType;
46
47 fn priority(&self) -> i32 {
52 match self.source_type() {
53 SourceType::Project => 20,
54 SourceType::User => 10,
55 SourceType::Managed => 5,
56 SourceType::Builtin => 0,
57 SourceType::Plugin => -5,
58 }
59 }
60
61 fn to_summary_line(&self) -> String;
65
66 async fn load_content(&self) -> crate::Result<String> {
70 self.source().load().await
71 }
72
73 fn description(&self) -> &str {
75 ""
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use async_trait::async_trait;
82
83 use super::*;
84 use crate::common::Named;
85
86 #[derive(Clone, Debug)]
87 struct TestIndex {
88 name: String,
89 desc: String,
90 source: ContentSource,
91 source_type: SourceType,
92 }
93
94 impl Named for TestIndex {
95 fn name(&self) -> &str {
96 &self.name
97 }
98 }
99
100 #[async_trait]
101 impl Index for TestIndex {
102 fn source(&self) -> &ContentSource {
103 &self.source
104 }
105
106 fn source_type(&self) -> SourceType {
107 self.source_type
108 }
109
110 fn to_summary_line(&self) -> String {
111 format!("- {}: {}", self.name, self.desc)
112 }
113
114 fn description(&self) -> &str {
115 &self.desc
116 }
117 }
118
119 #[test]
120 fn test_priority_ordering() {
121 let builtin = TestIndex {
122 name: "test".into(),
123 desc: "desc".into(),
124 source: ContentSource::in_memory(""),
125 source_type: SourceType::Builtin,
126 };
127
128 let user = TestIndex {
129 name: "test".into(),
130 desc: "desc".into(),
131 source: ContentSource::in_memory(""),
132 source_type: SourceType::User,
133 };
134
135 let project = TestIndex {
136 name: "test".into(),
137 desc: "desc".into(),
138 source: ContentSource::in_memory(""),
139 source_type: SourceType::Project,
140 };
141
142 let plugin = TestIndex {
143 name: "test".into(),
144 desc: "desc".into(),
145 source: ContentSource::in_memory(""),
146 source_type: SourceType::Plugin,
147 };
148
149 assert!(project.priority() > user.priority());
150 assert!(user.priority() > builtin.priority());
151 assert!(builtin.priority() > plugin.priority());
152 assert_eq!(plugin.priority(), -5);
153 }
154
155 #[tokio::test]
156 async fn test_load_content() {
157 let index = TestIndex {
158 name: "test".into(),
159 desc: "desc".into(),
160 source: ContentSource::in_memory("full content here"),
161 source_type: SourceType::User,
162 };
163
164 let content = index.load_content().await.unwrap();
165 assert_eq!(content, "full content here");
166 }
167
168 #[test]
169 fn test_summary_line() {
170 let index = TestIndex {
171 name: "commit".into(),
172 desc: "Create git commits".into(),
173 source: ContentSource::in_memory(""),
174 source_type: SourceType::User,
175 };
176
177 assert_eq!(index.to_summary_line(), "- commit: Create git commits");
178 }
179}