Something went wrong. Try again.
daemon connecting Claude Code sessions to the JamJum JP-mini via usb or bluetooth
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228//! Session identity: which kind of session a pad shows, and its key.
use serde_json::Value;
/// A session padmon shows. Keys are validated where they enter padmon (the hook environment/// and the socket).#[derive(Clone, Debug, PartialEq, Eq, Hash)]pub enum SessionKey { /// An iTerm2 pane, by its upper-cased session UUID. ITerm(String), /// A local Claude Desktop session, by its `local_…` ID, exactly as Claude Desktop sets it. Desktop(String),}
pub(crate) fn is_canonical_uuid(s: &str) -> bool { s.len() == 36 && s.bytes().enumerate().all(|(i, c)| match i { 8 | 13 | 18 | 23 => c == b'-', _ => c.is_ascii_hexdigit(), })}
/// Upper-cased iTerm2 session UUID from `ITERM_SESSION_ID` (`w0t0p0:<UUID>`).pub fn pane_uuid(iterm_session_id: &str) -> Option<String> { let (_, uuid) = iterm_session_id.split_once(':')?; is_canonical_uuid(uuid).then(|| uuid.to_ascii_uppercase())}
/// Whether `s` is a Desktop session ID as Claude Desktop's deep link accepts it:/// `^local_[A-Za-z0-9-]{1,64}$`.pub fn is_desktop_id(s: &str) -> bool { s.strip_prefix("local_").is_some_and(|rest| { (1..=64).contains(&rest.len()) && rest.bytes().all(|c| c.is_ascii_alphanumeric() || c == b'-') })}
/// The session a hook or statusline call belongs to, from its environment; `None` means drop/// the call. Only interactive sessions count: `claude -p` and SDK sessions set another entrypoint.pub fn from_env( entrypoint: Option<&str>, iterm_session_id: Option<&str>, host_session_id: Option<&str>,) -> Option<SessionKey> { match entrypoint { Some("claude-desktop") => host_session_id .filter(|id| is_desktop_id(id)) .map(|id| SessionKey::Desktop(id.to_string())), None | Some("cli") => pane_uuid(iterm_session_id?).map(SessionKey::ITerm), Some(_) => None, }}
impl SessionKey { /// The socket field naming this session, and its value. pub fn wire_field(&self) -> (&'static str, &str) { match self { SessionKey::ITerm(uuid) => ("pane", uuid), SessionKey::Desktop(id) => ("desktop", id), } }
/// The session a socket line names; `None` unless it has exactly one session field and that /// field is valid. A line naming a cloud session is refused: only padmon's own poller (Plan B) /// creates those. pub fn from_wire(v: &Value) -> Option<SessionKey> { if v.get("cloud").is_some() { return None; } match (v.get("pane"), v.get("desktop")) { (Some(pane), None) => { let pane = pane.as_str()?; is_canonical_uuid(pane).then(|| SessionKey::ITerm(pane.to_ascii_uppercase())) } (None, Some(id)) => { let id = id.as_str()?; is_desktop_id(id).then(|| SessionKey::Desktop(id.to_string())) } _ => None, } }}
#[cfg(test)]mod tests { use super::*; use serde_json::json;
const ISID: &str = "w0t0p0:5E38C7C8-E1CA-414E-A41F-6AACAC2BF28A"; const UUID: &str = "5E38C7C8-E1CA-414E-A41F-6AACAC2BF28A";
const DESKTOP: &str = "local_576accf0-fe50-4468-b9e2-1198ccb96327";
fn pane() -> SessionKey { SessionKey::ITerm(UUID.to_string()) }
fn desktop() -> SessionKey { SessionKey::Desktop(DESKTOP.to_string()) }
#[test] fn pane_uuid_accepts_canonical_and_uppercases() { assert_eq!(pane_uuid(ISID).as_deref(), Some(UUID)); assert_eq!(pane_uuid(&ISID.to_lowercase()).as_deref(), Some(UUID)); }
#[test] fn pane_uuid_rejects_malformed() { for bad in [ UUID, "w0t0p0:", "w0t0p0:--help", "w0t0p0:5E38C7C8-E1CA-414E-A41F-6AACAC2BF28", "w0:5E38C7C8xE1CA-414E-A41F-6AACAC2BF28A", "w0:../../etc/passwd", ] { assert_eq!(pane_uuid(bad), None, "{bad}"); } }
#[test] fn from_env_takes_interactive_iterm_panes_only() { assert_eq!(from_env(None, Some(ISID), None), Some(pane())); assert_eq!(from_env(Some("cli"), Some(ISID), None), Some(pane())); assert_eq!(from_env(Some("sdk-cli"), Some(ISID), None), None); assert_eq!(from_env(Some("cli"), None, None), None); assert_eq!(from_env(Some("cli"), Some("garbage"), None), None); }
#[test] fn pane_wire_roundtrip() { let key = pane(); let (k, v) = key.wire_field(); assert_eq!(SessionKey::from_wire(&json!({ k: v })), Some(pane())); assert_eq!( SessionKey::from_wire(&json!({"pane": UUID.to_lowercase()})), Some(pane()), "upper-cased as today" ); assert_eq!(SessionKey::from_wire(&json!({"pane": "x"})), None); assert_eq!(SessionKey::from_wire(&json!({})), None); }
#[test] fn desktop_ids_match_claude_desktops_pattern() { for ok in [ "local_576accf0-fe50-4468-b9e2-1198ccb96327", "local_A", &format!("local_{}", "a".repeat(64)), ] { assert!(is_desktop_id(ok), "{ok}"); } for bad in [ "local_", "LOCAL_abc", "session_01R5os3td8mvNK2GgxVwwMJW", "local_a&x=1", "local_a#b", "local_a/../b", "local_a b", "local_a_b", &format!("local_{}", "a".repeat(65)), ] { assert!(!is_desktop_id(bad), "{bad}"); } }
#[test] fn from_env_takes_desktop_sessions_by_host_session_id() { let d = Some(DESKTOP); assert_eq!(from_env(Some("claude-desktop"), None, d), Some(desktop())); assert_eq!( from_env(Some("claude-desktop"), Some(ISID), d), Some(desktop()), "a Desktop session with an iTerm2 environment is still a Desktop session" ); assert_eq!(from_env(Some("claude-desktop"), Some(ISID), None), None); assert_eq!( from_env(Some("claude-desktop"), None, Some("local_a#b")), None ); assert_eq!( from_env(Some("sdk-cli"), None, d), None, "claude -p inside a Desktop session" ); assert_eq!( from_env(Some("cli"), Some(ISID), d), Some(pane()), "cli keeps using the pane" ); assert_eq!(from_env(Some("cli"), None, d), None); }
#[test] fn desktop_wire_roundtrip() { let key = desktop(); let (k, v) = key.wire_field(); assert_eq!(k, "desktop"); assert_eq!(SessionKey::from_wire(&json!({ k: v })), Some(desktop())); }
#[test] fn desktop_key_keeps_its_case_on_the_wire() { assert_eq!( SessionKey::from_wire(&json!({"desktop": "local_AbC-9"})), Some(SessionKey::Desktop("local_AbC-9".to_string())) ); }
#[test] fn from_wire_needs_exactly_one_valid_session() { for bad in [ json!({"pane": UUID, "desktop": DESKTOP}), json!({"pane": UUID, "desktop": 7}), json!({"pane": UUID, "cloud": "session_01R5os3td8mvNK2GgxVwwMJW"}), json!({"cloud": "session_01R5os3td8mvNK2GgxVwwMJW"}), json!({"desktop": "local_a&x=1"}), json!({"desktop": "session_01R5os3td8mvNK2GgxVwwMJW"}), json!({"desktop": 7}), json!({"pane": null, "desktop": null}), ] { assert_eq!(SessionKey::from_wire(&bad), None, "{bad}"); } }}