diff options
| author | Eric Yue <yue1995pro@gmail.com> | 2026-06-15 21:50:24 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-15 16:50:24 +0300 |
| commit | 07261e09be60ac0c145685fd11f94351cc0e5ba6 (patch) | |
| tree | 771b0180c7a1560189547e6d23ef004ec1cf6d5c /tests/cli_wrapper.rs | |
| parent | 08bb0768ae224c8db04bbe016b050353ce13eee7 (diff) | |
feat: add devin cli detection and restore support (#622)
* feat: add devin cli detection and restore support
refs #606
* fix: keep devin integration session-only
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'tests/cli_wrapper.rs')
| -rw-r--r-- | tests/cli_wrapper.rs | 140 |
1 files changed, 136 insertions, 4 deletions
diff --git a/tests/cli_wrapper.rs b/tests/cli_wrapper.rs index 33cea043..53d91c43 100644 --- a/tests/cli_wrapper.rs +++ b/tests/cli_wrapper.rs @@ -544,7 +544,29 @@ fn run_copilot_hook(hook_input: &str) -> Option<serde_json::Value> { ) } +fn run_devin_hook( + action: &str, + hook_input: &str, + envs: &[(&str, &str)], +) -> Option<serde_json::Value> { + run_shell_hook_with_env( + "src/integration/assets/devin/herdr-agent-state.sh", + &[action], + hook_input, + envs, + ) +} + fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<serde_json::Value> { + run_shell_hook_with_env(asset_path, args, hook_input, &[]) +} + +fn run_shell_hook_with_env( + asset_path: &str, + args: &[&str], + hook_input: &str, + envs: &[(&str, &str)], +) -> Option<serde_json::Value> { let base = unique_test_dir(); fs::create_dir_all(&base).unwrap(); let socket_path = base.join("herdr.sock"); @@ -574,7 +596,8 @@ fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<s }); let hook_path = Path::new(env!("CARGO_MANIFEST_DIR")).join(asset_path); - let mut child = Command::new("bash") + let mut command = Command::new("bash"); + command .arg(hook_path) .args(args) .env("HERDR_ENV", "1") @@ -582,9 +605,11 @@ fn run_shell_hook(asset_path: &str, args: &[&str], hook_input: &str) -> Option<s .env("HERDR_PANE_ID", "p_test") .stdin(Stdio::piped()) .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .unwrap(); + .stderr(Stdio::piped()); + for (key, value) in envs { + command.env(key, value); + } + let mut child = command.spawn().unwrap(); let mut stdin = child.stdin.take().unwrap(); stdin.write_all(hook_input.as_bytes()).unwrap(); drop(stdin); @@ -696,6 +721,113 @@ fn copilot_hook_does_not_report_lifecycle_state() { } #[test] +fn devin_hook_ignores_prompt_session_list_fallback() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"UserPromptSubmit","prompt":"run tests"}"#, + &[ + ("DEVIN_PROJECT_DIR", "/tmp/project"), + ( + "HERDR_DEVIN_LIST_JSON", + r#"[{"id":"older-session","working_directory":"/tmp/other"},{"id":"devin-session","working_directory":"/tmp/project"}]"#, + ), + ], + ); + + assert!(request.is_none()); +} + +#[test] +fn devin_hook_reports_session_id_from_stdin_without_state() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"SessionStart","session_id":"devin-session","source":"startup"}"#, + &[("HERDR_DEVIN_LIST_JSON", r#"[{"id":"older-session"}]"#)], + ) + .expect("devin session start should report session identity"); + + assert_eq!(request["method"], "pane.report_agent_session"); + assert_eq!(request["params"]["agent"], "devin"); + assert_eq!(request["params"]["agent_session_id"], "devin-session"); + assert!(request["params"].get("state").is_none()); +} + +#[test] +fn devin_hook_prefers_hook_session_id_over_list() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"PreToolUse","sessionId":"fresh-session","tool_name":"exec"}"#, + &[ + ("DEVIN_PROJECT_DIR", "/tmp/project"), + ( + "HERDR_DEVIN_LIST_JSON", + r#"[{"id":"older-session","working_directory":"/tmp/project"}]"#, + ), + ], + ) + .expect("devin tool hook should report session identity"); + + assert_eq!(request["method"], "pane.report_agent_session"); + assert_eq!(request["params"]["agent_session_id"], "fresh-session"); + assert!(request["params"].get("state").is_none()); +} + +#[test] +fn devin_hook_reports_tool_session_from_list_without_state() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"PreToolUse","tool_name":"exec"}"#, + &[ + ("DEVIN_PROJECT_DIR", "/tmp/project"), + ( + "HERDR_DEVIN_LIST_JSON", + r#"[{"id":"older-session","working_directory":"/tmp/other"},{"id":"devin-session","working_directory":"/tmp/project"}]"#, + ), + ], + ) + .expect("devin tool hook should report session identity"); + + assert_eq!(request["method"], "pane.report_agent_session"); + assert_eq!(request["params"]["agent"], "devin"); + assert_eq!(request["params"]["agent_session_id"], "devin-session"); + assert!(request["params"].get("state").is_none()); +} + +#[test] +fn devin_hook_ignores_startup_session_list_fallback() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"SessionStart","source":"startup"}"#, + &[ + ("DEVIN_PROJECT_DIR", "/tmp/project"), + ( + "HERDR_DEVIN_LIST_JSON", + r#"[{"id":"stale-session","working_directory":"/tmp/project"}]"#, + ), + ], + ); + + assert!(request.is_none()); +} + +#[test] +fn devin_hook_ignores_non_matching_session_list_entries() { + let request = run_devin_hook( + "session", + r#"{"hook_event_name":"PreToolUse","tool_name":"exec"}"#, + &[ + ("DEVIN_PROJECT_DIR", "/tmp/project"), + ( + "HERDR_DEVIN_LIST_JSON", + r#"[{"id":"other-session","working_directory":"/tmp/other"}]"#, + ), + ], + ); + + assert!(request.is_none()); +} + +#[test] fn pane_run_sends_one_send_input_request_with_enter_key() { let base = unique_test_dir(); fs::create_dir_all(&base).unwrap(); |
