mi6_core/framework/
amp.rs1use super::{FrameworkAdapter, ParsedHookInput};
36use crate::model::EventType;
37use std::path::PathBuf;
38
39pub struct AmpAdapter;
45
46impl FrameworkAdapter for AmpAdapter {
47 fn name(&self) -> &'static str {
48 "amp"
49 }
50
51 fn display_name(&self) -> &'static str {
52 "Amp"
53 }
54
55 fn project_config_path(&self) -> PathBuf {
56 PathBuf::from(".config/amp/settings.json")
58 }
59
60 fn user_config_path(&self) -> Option<PathBuf> {
61 dirs::home_dir().map(|h| h.join(".config/amp/settings.json"))
62 }
63
64 fn generate_hooks_config(
65 &self,
66 _enabled_events: &[EventType],
67 _mi6_bin: &str,
68 _otel_enabled: bool,
69 _otel_port: u16,
70 ) -> serde_json::Value {
71 serde_json::json!({
73 "_note": "Amp does not support hooks. Sessions are detected via process scanning.",
74 "status": "n/a",
75 "prompt": "n/a"
76 })
77 }
78
79 fn merge_config(
80 &self,
81 generated: serde_json::Value,
82 _existing: Option<serde_json::Value>,
83 ) -> serde_json::Value {
84 generated
86 }
87
88 fn parse_hook_input(
89 &self,
90 _event_type: &str,
91 stdin_json: &serde_json::Value,
92 ) -> ParsedHookInput {
93 ParsedHookInput {
95 session_id: stdin_json
96 .get("session_id")
97 .and_then(|v| v.as_str())
98 .map(String::from),
99 tool_name: stdin_json
100 .get("tool_name")
101 .and_then(|v| v.as_str())
102 .map(String::from),
103 cwd: stdin_json
104 .get("cwd")
105 .and_then(|v| v.as_str())
106 .map(String::from),
107 tool_use_id: None,
108 subagent_type: None,
109 spawned_agent_id: None,
110 permission_mode: None,
111 transcript_path: None,
112 session_source: None,
113 agent_id: None,
114 agent_transcript_path: None,
115 compact_trigger: None,
116 model: None,
117 duration_ms: None,
118 tokens_input: None,
119 tokens_output: None,
120 tokens_cache_read: None,
121 tokens_cache_write: None,
122 cost_usd: None,
123 prompt: None,
124 }
125 }
126
127 fn map_event_type(&self, framework_event: &str) -> EventType {
128 framework_event
130 .parse()
131 .unwrap_or_else(|_| EventType::Custom(framework_event.to_string()))
132 }
133
134 fn supported_events(&self) -> Vec<&'static str> {
135 vec![]
137 }
138
139 fn detection_env_vars(&self) -> &[&'static str] {
140 &[]
143 }
144
145 fn is_installed(&self) -> bool {
146 let amp_dir_exists = dirs::home_dir().is_some_and(|h| h.join(".amp").exists());
148 let config_dir_exists = dirs::home_dir().is_some_and(|h| h.join(".config/amp").exists());
149 let amp_binary_exists = dirs::home_dir().is_some_and(|h| h.join(".amp/bin/amp").exists());
150
151 amp_dir_exists || config_dir_exists || amp_binary_exists || which::which("amp").is_ok()
152 }
153
154 fn remove_hooks(&self, _existing: serde_json::Value) -> Option<serde_json::Value> {
155 None
157 }
158
159 fn has_mi6_hooks(&self, _local: bool, _settings_local: bool) -> bool {
160 self.is_installed()
163 }
164
165 fn resume_command(&self, _session_id: &str) -> Option<String> {
166 None
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn test_name() {
177 let adapter = AmpAdapter;
178 assert_eq!(adapter.name(), "amp");
179 assert_eq!(adapter.display_name(), "Amp");
180 }
181
182 #[test]
183 fn test_detection_env_vars() {
184 let adapter = AmpAdapter;
185 let vars = adapter.detection_env_vars();
186 assert!(vars.is_empty());
188 }
189
190 #[test]
191 fn test_supported_events_empty() {
192 let adapter = AmpAdapter;
193 assert!(adapter.supported_events().is_empty());
194 }
195
196 #[test]
197 fn test_map_event_type_unknown() {
198 let adapter = AmpAdapter;
199 assert_eq!(
200 adapter.map_event_type("SomeEvent"),
201 EventType::Custom("SomeEvent".to_string())
202 );
203 }
204
205 #[test]
206 fn test_parse_hook_input() {
207 let adapter = AmpAdapter;
208 let input = serde_json::json!({
209 "session_id": "T-123",
210 "tool_name": "Bash",
211 "cwd": "/projects/test"
212 });
213
214 let parsed = adapter.parse_hook_input("PreToolUse", &input);
215 assert_eq!(parsed.session_id, Some("T-123".to_string()));
216 assert_eq!(parsed.tool_name, Some("Bash".to_string()));
217 assert_eq!(parsed.cwd, Some("/projects/test".to_string()));
218 }
219}