diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-22 19:25:31 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-22 19:25:31 +0300 |
| commit | c25f116c5365b2a9dcb621432a7f96b3f5160d43 (patch) | |
| tree | 7deb5fa47b2f7cf2b1e0773de1bb34067304912f /src | |
| parent | bf4e037c7de61c2f472b9a9286a3516ce5411612 (diff) | |
fix: detect cursor agent symlink aliases
refs #225
Diffstat (limited to 'src')
| -rw-r--r-- | src/detect.rs | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/src/detect.rs b/src/detect.rs index 31d40b39..8479ea70 100644 --- a/src/detect.rs +++ b/src/detect.rs @@ -955,7 +955,22 @@ fn agent_name_from_path_token(token: &str) -> Option<String> { return None; } - let basename = path_basename(trimmed); + agent_name_from_basename(path_basename(trimmed)) + .or_else(|| resolved_agent_name_from_path_token(trimmed)) +} + +fn resolved_agent_name_from_path_token(token: &str) -> Option<String> { + let path = std::path::Path::new(token); + if path.components().count() < 2 { + return None; + } + + let resolved = std::fs::canonicalize(path).ok()?; + let basename = resolved.file_name()?.to_str()?; + agent_name_from_basename(basename) +} + +fn agent_name_from_basename(basename: &str) -> Option<String> { let agent = parse_agent_label(basename)?; Some(agent_label(agent).to_string()) } @@ -1007,6 +1022,19 @@ mod tests { } } + fn temp_detection_path(name: &str) -> std::path::PathBuf { + let unique = format!( + "herdr-detect-tests-{}-{}-{}", + name, + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("system time should be after unix epoch") + .as_nanos() + ); + std::env::temp_dir().join(unique) + } + // ---- Agent identification ---- #[test] @@ -1258,6 +1286,34 @@ mod tests { assert_eq!(cmdline_argv0_agent_name("/tmp/my-codex-helper"), None); } + #[cfg(unix)] + #[test] + fn identify_agent_in_job_resolves_cursor_agent_symlink_argv0() { + let dir = temp_detection_path("cursor-agent-symlink"); + std::fs::create_dir_all(&dir).expect("test directory should be created"); + let target = dir.join("cursor-agent"); + let link = dir.join("agent"); + std::fs::write(&target, b"#!/bin/sh\n").expect("target should be written"); + std::os::unix::fs::symlink(&target, &link).expect("symlink should be created"); + + let argv0 = link.to_string_lossy().into_owned(); + let job = crate::platform::ForegroundJob { + process_group_id: 42, + processes: vec![foreground_process( + 42, + "MainThread", + &[&argv0, "--use-system-ca", "/tmp/index.js"], + )], + }; + + assert_eq!( + identify_agent_in_job(&job), + Some((Agent::Cursor, "cursor".to_string())) + ); + + std::fs::remove_dir_all(&dir).ok(); + } + // ---- Workspace state rollup ---- // ---- No agent → Unknown ---- |
