aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-22 19:25:31 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-22 19:25:31 +0300
commitc25f116c5365b2a9dcb621432a7f96b3f5160d43 (patch)
tree7deb5fa47b2f7cf2b1e0773de1bb34067304912f /src
parentbf4e037c7de61c2f472b9a9286a3516ce5411612 (diff)
fix: detect cursor agent symlink aliases
refs #225
Diffstat (limited to 'src')
-rw-r--r--src/detect.rs58
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 ----