Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
@@ -0,0 +1,410 @@
use super::event::{parse_event, CLIAgentEvent, CLIAgentEventPayload, CLIAgentEventType};
use super::{
CLIAgentInputEntrypoint, CLIAgentInputState, CLIAgentSession, CLIAgentSessionContext,
CLIAgentSessionStatus, CLIAgentSessionsModel,
};
use crate::ai::blocklist::{InputConfig, InputType};
use crate::terminal::CLIAgent;
#[test]
fn parse_stop_notification() {
let body = r#"{"v":1,"agent":"claude","event":"stop","session_id":"abc","cwd":"/tmp/proj","project":"proj","query":"write a haiku","response":"Memory is safe","transcript_path":"/tmp/t.jsonl"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.v, 1);
assert_eq!(notif.agent, CLIAgent::Claude);
assert_eq!(notif.event, CLIAgentEventType::Stop);
assert_eq!(notif.session_id.as_deref(), Some("abc"));
assert_eq!(notif.cwd.as_deref(), Some("/tmp/proj"));
assert_eq!(notif.project.as_deref(), Some("proj"));
assert_eq!(notif.payload.query.as_deref(), Some("write a haiku"));
assert_eq!(notif.payload.response.as_deref(), Some("Memory is safe"));
assert_eq!(
notif.payload.transcript_path.as_deref(),
Some("/tmp/t.jsonl")
);
}
#[test]
fn cli_agent_session_context_title_like_text_uses_trimmed_summary() {
let context = CLIAgentSessionContext {
summary: Some(" Reviewing changes ".to_string()),
query: Some("Latest prompt".to_string()),
..Default::default()
};
assert_eq!(
context.title_like_text(),
Some("Reviewing changes".to_string())
);
}
#[test]
fn cli_agent_session_context_latest_user_prompt_uses_trimmed_query() {
let context = CLIAgentSessionContext {
summary: Some("Reviewing changes".to_string()),
query: Some(" Latest prompt ".to_string()),
..Default::default()
};
assert_eq!(
context.latest_user_prompt(),
Some("Latest prompt".to_string())
);
}
#[test]
fn cli_agent_session_context_title_helpers_ignore_empty_text() {
let context = CLIAgentSessionContext {
summary: Some(" ".to_string()),
query: Some("".to_string()),
..Default::default()
};
assert_eq!(context.title_like_text(), None);
assert_eq!(context.latest_user_prompt(), None);
}
#[test]
fn parse_permission_request_notification() {
let body = r#"{"v":1,"agent":"claude","event":"permission_request","session_id":"abc","cwd":"/tmp/proj","project":"proj","summary":"Wants to run Bash: rm -rf /tmp","tool_name":"Bash","tool_input":{"command":"rm -rf /tmp"}}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.event, CLIAgentEventType::PermissionRequest);
assert_eq!(
notif.payload.summary.as_deref(),
Some("Wants to run Bash: rm -rf /tmp")
);
assert_eq!(notif.payload.tool_name.as_deref(), Some("Bash"));
assert_eq!(
notif.payload.tool_input_preview.as_deref(),
Some("rm -rf /tmp")
);
}
#[test]
fn parse_permission_request_with_file_path() {
let body = r#"{"v":1,"agent":"claude","event":"permission_request","session_id":"abc","cwd":"/tmp","project":"tmp","tool_name":"Write","tool_input":{"file_path":"/tmp/test.py","content":"print('hi')"}}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(
notif.payload.tool_input_preview.as_deref(),
Some("/tmp/test.py")
);
}
#[test]
fn parse_idle_prompt_notification() {
let body = r#"{"v":1,"agent":"claude","event":"idle_prompt","session_id":"abc","cwd":"/tmp","project":"tmp","summary":"Claude is waiting for your input"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.event, CLIAgentEventType::IdlePrompt);
assert_eq!(
notif.payload.summary.as_deref(),
Some("Claude is waiting for your input")
);
}
#[test]
fn parse_session_start_notification() {
let body = r#"{"v":1,"agent":"claude","event":"session_start","session_id":"abc","cwd":"/tmp","project":"tmp","plugin_version":"1.1.0"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.event, CLIAgentEventType::SessionStart);
assert_eq!(notif.payload.plugin_version.as_deref(), Some("1.1.0"));
}
#[test]
fn returns_none_for_wrong_sentinel() {
let body = r#"{"v":1,"agent":"claude","event":"stop"}"#;
assert!(parse_event(Some("Claude Code"), body).is_none());
}
#[test]
fn returns_none_for_missing_title() {
let body = r#"{"v":1,"agent":"claude","event":"stop"}"#;
assert!(parse_event(None, body).is_none());
}
#[test]
fn returns_none_for_invalid_json() {
assert!(parse_event(Some("warp://cli-agent"), "not json").is_none());
}
#[test]
fn handles_unknown_event_type() {
let body = r#"{"v":1,"agent":"claude","event":"some_future_event"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(
notif.event,
CLIAgentEventType::Unknown("some_future_event".to_string())
);
}
#[test]
fn handles_missing_optional_fields() {
let body = r#"{"event":"stop"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.v, 1);
assert_eq!(notif.agent, CLIAgent::Unknown);
assert_eq!(notif.event, CLIAgentEventType::Stop);
assert!(notif.session_id.is_none());
assert!(notif.cwd.is_none());
assert!(notif.project.is_none());
assert!(notif.payload.query.is_none());
}
#[test]
fn handles_special_characters_in_values() {
let body = r#"{"v":1,"agent":"claude","event":"stop","query":"what does \"hello\" mean?","response":"It means greeting. Use: printf(\"hello\")"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(
notif.payload.query.as_deref(),
Some("what does \"hello\" mean?")
);
assert_eq!(
notif.payload.response.as_deref(),
Some("It means greeting. Use: printf(\"hello\")")
);
}
#[test]
fn rejects_unsupported_schema_version() {
let body = r#"{"v":2,"agent":"claude","event":"stop"}"#;
assert!(parse_event(Some("warp://cli-agent"), body).is_none());
}
#[test]
fn defaults_to_v1_when_version_missing() {
let body = r#"{"agent":"claude","event":"stop","query":"hi"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.v, 1);
assert_eq!(notif.payload.query.as_deref(), Some("hi"));
}
#[test]
fn explicit_v1_parses_correctly() {
let body = r#"{"v":1,"agent":"claude","event":"stop","query":"test"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.v, 1);
assert_eq!(notif.payload.query.as_deref(), Some("test"));
}
#[test]
fn parse_prompt_submit_notification() {
let body = r#"{"v":1,"agent":"claude","event":"prompt_submit","session_id":"abc","cwd":"/tmp/proj","project":"proj","query":"fix the bug"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.event, CLIAgentEventType::PromptSubmit);
assert_eq!(notif.payload.query.as_deref(), Some("fix the bug"));
}
#[test]
fn parse_tool_complete_notification() {
let body = r#"{"v":1,"agent":"claude","event":"tool_complete","session_id":"abc","cwd":"/tmp/proj","project":"proj","tool_name":"Bash"}"#;
let notif = parse_event(Some("warp://cli-agent"), body).unwrap();
assert_eq!(notif.event, CLIAgentEventType::ToolComplete);
assert_eq!(notif.payload.tool_name.as_deref(), Some("Bash"));
}
#[test]
fn parse_auggie_stop_notification() {
// Mirrors what the community auggie-warp plugin emits on the Stop hook.
let body = r#"{"v":1,"agent":"auggie","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::Auggie);
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 {
entrypoint: CLIAgentInputEntrypoint::CtrlG,
previous_input_config: InputConfig {
input_type: InputType::Shell,
is_locked: false,
},
previous_was_lock_set_with_empty_buffer: true,
};
let mut session = CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state,
should_auto_toggle_input: false,
listener: None,
remote_host: None,
plugin_version: None,
draft_text: None,
custom_command_prefix: None,
};
let event = CLIAgentEvent {
v: 1,
agent: CLIAgent::Claude,
event: CLIAgentEventType::PermissionRequest,
session_id: Some("abc".to_string()),
cwd: Some("/tmp/proj".to_string()),
project: Some("proj".to_string()),
payload: CLIAgentEventPayload {
summary: Some("Needs approval".to_string()),
..Default::default()
},
};
session.apply_event(&event);
assert_eq!(session.input_state, input_state);
}
#[test]
fn is_remote_returns_true_when_remote_host_is_set() {
let session = CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
plugin_version: None,
draft_text: None,
remote_host: Some("user@devbox".to_owned()),
custom_command_prefix: None,
};
assert!(session.is_remote());
}
#[test]
fn is_remote_returns_false_when_remote_host_is_none() {
let session = CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
remote_host: None,
plugin_version: None,
draft_text: None,
custom_command_prefix: None,
};
assert!(!session.is_remote());
}
#[test]
fn local_failure_is_shared_across_local_sessions() {
let mut model = CLIAgentSessionsModel::new();
model.record_plugin_auto_failure(CLIAgent::Claude, None);
assert!(model.has_plugin_auto_failed(CLIAgent::Claude, &None));
}
#[test]
fn local_failure_does_not_affect_remote_host() {
let mut model = CLIAgentSessionsModel::new();
model.record_plugin_auto_failure(CLIAgent::Claude, None);
let remote = Some("user@devbox".to_owned());
assert!(!model.has_plugin_auto_failed(CLIAgent::Claude, &remote));
}
#[test]
fn remote_failure_does_not_affect_local() {
let mut model = CLIAgentSessionsModel::new();
model.record_plugin_auto_failure(CLIAgent::Claude, Some("user@devbox".to_owned()));
assert!(!model.has_plugin_auto_failed(CLIAgent::Claude, &None));
}
#[test]
fn remote_failures_are_independent_per_host() {
let mut model = CLIAgentSessionsModel::new();
let host_a = Some("user@host-a".to_owned());
let host_b = Some("user@host-b".to_owned());
model.record_plugin_auto_failure(CLIAgent::Claude, host_a.clone());
assert!(model.has_plugin_auto_failed(CLIAgent::Claude, &host_a));
assert!(!model.has_plugin_auto_failed(CLIAgent::Claude, &host_b));
}
#[test]
fn failure_tracking_is_independent_per_agent() {
let mut model = CLIAgentSessionsModel::new();
model.record_plugin_auto_failure(CLIAgent::Claude, None);
assert!(model.has_plugin_auto_failed(CLIAgent::Claude, &None));
assert!(!model.has_plugin_auto_failed(CLIAgent::Gemini, &None));
}
#[test]
fn session_start_sets_plugin_version() {
let mut session = CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
plugin_version: None,
draft_text: None,
remote_host: None,
custom_command_prefix: None,
};
let event = CLIAgentEvent {
v: 1,
agent: CLIAgent::Claude,
event: CLIAgentEventType::SessionStart,
session_id: Some("abc".to_owned()),
cwd: Some("/tmp".to_owned()),
project: Some("proj".to_owned()),
payload: CLIAgentEventPayload {
plugin_version: Some("1.5.0".to_owned()),
..Default::default()
},
};
session.apply_event(&event);
assert_eq!(session.plugin_version.as_deref(), Some("1.5.0"));
}
#[test]
fn session_start_without_plugin_version_leaves_none() {
let mut session = CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
plugin_version: None,
draft_text: None,
remote_host: None,
custom_command_prefix: None,
};
let event = CLIAgentEvent {
v: 1,
agent: CLIAgent::Claude,
event: CLIAgentEventType::SessionStart,
session_id: Some("abc".to_owned()),
cwd: None,
project: None,
payload: CLIAgentEventPayload::default(),
};
session.apply_event(&event);
assert_eq!(session.plugin_version, None);
}