Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions app/src/terminal/cli_agent_sessions/listener/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,27 @@ pub fn is_agent_supported(agent: &CLIAgent) -> bool {
| CLIAgent::Codex
| CLIAgent::Gemini
| CLIAgent::Auggie
| CLIAgent::Pi
)
}

/// Creates the appropriate handler for the given CLI agent.
fn create_handler(agent: &CLIAgent) -> Option<Box<dyn CLIAgentSessionHandler>> {
match agent {
// Auggie is supported via the community-maintained auggie-warp plugin
// (https://github.com/augmentmoogi/auggie-warp), which emits the same
// Auggie and Pi are supported via community-maintained plugins
// (https://github.com/augmentmoogi/auggie-warp,
// https://github.com/badlogic/pi-mono), which emit the same
// structured OSC 777 events as the first-party Claude/OpenCode/Gemini
// plugins. We don't ship an install flow for it — we just listen.
CLIAgent::Claude | CLIAgent::OpenCode | CLIAgent::Gemini | CLIAgent::Auggie => {
Some(Box::new(DefaultSessionListener))
}
// plugins. We don't ship install flows for them — we just listen.
CLIAgent::Claude
| CLIAgent::OpenCode
| CLIAgent::Gemini
| CLIAgent::Auggie
| CLIAgent::Pi => Some(Box::new(DefaultSessionListener)),
CLIAgent::Codex => Some(Box::new(CodexSessionHandler)),
CLIAgent::Amp
| CLIAgent::Droid
| CLIAgent::Copilot
| CLIAgent::Pi
| CLIAgent::CursorCli
| CLIAgent::Goose
| CLIAgent::Unknown => None,
Expand Down Expand Up @@ -287,4 +290,44 @@ mod tests {
};
assert!(handler.handle_event(event).is_some());
}

#[test]
fn pi_is_supported() {
assert!(is_agent_supported(&CLIAgent::Pi));
}

#[test]
fn pi_uses_default_handler_with_rich_status() {
assert!(agent_supports_rich_status(&CLIAgent::Pi));
}

#[test]
fn pi_default_handler_skips_session_start() {
let mut handler = DefaultSessionListener;
let event = CLIAgentEvent {
v: 1,
agent: CLIAgent::Pi,
event: CLIAgentEventType::SessionStart,
session_id: None,
cwd: None,
project: None,
payload: CLIAgentEventPayload::default(),
};
assert!(handler.handle_event(event).is_none());
}

#[test]
fn pi_default_handler_forwards_stop() {
let mut handler = DefaultSessionListener;
let event = CLIAgentEvent {
v: 1,
agent: CLIAgent::Pi,
event: CLIAgentEventType::Stop,
session_id: None,
cwd: None,
project: None,
payload: CLIAgentEventPayload::default(),
};
assert!(handler.handle_event(event).is_some());
}
}
14 changes: 14 additions & 0 deletions app/src/terminal/cli_agent_sessions/mod_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,20 @@ fn parse_auggie_stop_notification() {
assert_eq!(notif.payload.response.as_deref(), Some("Memory is safe"));
}

#[test]
fn parse_pi_stop_notification() {
// Mirrors what the community pi-mono plugin emits on the Stop hook —
// matches the Auggie shape and uses `"agent":"pi"`, which `resolve_agent`
// already maps to `CLIAgent::Pi` via `command_prefix()`.
let body = r#"{"v":1,"agent":"pi","event":"stop","session_id":"abc","cwd":"/tmp/proj","project":"proj","query":"write a haiku","response":"Memory is safe"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();

assert_eq!(notif.agent, CLIAgent::Pi);
assert_eq!(notif.event, CLIAgentEventType::Stop);
assert_eq!(notif.payload.query.as_deref(), Some("write a haiku"));
assert_eq!(notif.payload.response.as_deref(), Some("Memory is safe"));
}

#[test]
fn apply_event_preserves_input_session() {
let input_state = CLIAgentInputState::Open {
Expand Down
Loading