aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Larson <hello@phillarson.xyz>2026-08-05 18:43:53 -0700
committerGitHub <noreply@github.com>2026-08-06 04:43:53 +0300
commitfc824b99aba9389ffda75f19b3a4aee0ff6ca8b5 (patch)
tree48128ff39e9a18365f59f1acaadc7e0553ca57ec
parentbb4edc7f4e87130358d1795701c4f3f709aa7f21 (diff)
fix(detect): recognize versioned Python agent wrappers (#2188)
Co-authored-by: Can Celik <ogulcancelik@gmail.com>
-rw-r--r--src/detect/mod.rs65
1 files changed, 48 insertions, 17 deletions
diff --git a/src/detect/mod.rs b/src/detect/mod.rs
index 29115dff..de590f82 100644
--- a/src/detect/mod.rs
+++ b/src/detect/mod.rs
@@ -350,11 +350,11 @@ fn normalized_process_name(process: &crate::platform::ForegroundProcess) -> Stri
fn wrapped_agent_name_from_runtime_argv(runtime: &str, argv: Option<&[String]>) -> Option<String> {
let argv = argv?;
- let runtime = normalized_agent_lookup_name(path_basename(runtime));
+ let runtime_name = normalized_agent_lookup_name(path_basename(runtime));
- match runtime.as_str() {
+ match runtime_name.as_str() {
"node" | "bun" => script_arg_agent_name(argv, &["-e", "--eval", "-p", "--print"], &[]),
- "python" | "python3" => script_arg_agent_name(argv, &["-c"], &["-m"]),
+ name if is_python_runtime(name) => script_arg_agent_name(argv, &["-c"], &["-m"]),
"sh" | "bash" | "zsh" | "fish" => script_arg_agent_name(argv, &["-c"], &[]),
"cmd" => windows_cmd_arg_agent_name(argv),
"powershell" | "pwsh" => powershell_arg_agent_name(argv),
@@ -594,20 +594,29 @@ fn process_priority(process: &crate::platform::ForegroundProcess, normalized_nam
fn is_generic_runtime_or_shell(name: &str) -> bool {
let name = normalized_agent_lookup_name(path_basename(name));
- matches!(
- name.as_str(),
- "sh" | "bash"
- | "zsh"
- | "fish"
- | "tmux"
- | "node"
- | "bun"
- | "python"
- | "python3"
- | "cmd"
- | "powershell"
- | "pwsh"
- )
+ is_python_runtime(&name)
+ || matches!(
+ name.as_str(),
+ "sh" | "bash"
+ | "zsh"
+ | "fish"
+ | "tmux"
+ | "node"
+ | "bun"
+ | "cmd"
+ | "powershell"
+ | "pwsh"
+ )
+}
+
+fn is_python_runtime(name: &str) -> bool {
+ name == "python"
+ || name.strip_prefix("python").is_some_and(|version| {
+ !version.is_empty()
+ && version
+ .split('.')
+ .all(|part| !part.is_empty() && part.chars().all(|ch| ch.is_ascii_digit()))
+ })
}
// ---------------------------------------------------------------------------
@@ -852,6 +861,28 @@ mod tests {
}
#[test]
+ fn identify_agent_in_job_detects_python_version_wrapped_hermes() {
+ let job = crate::platform::ForegroundJob {
+ process_group_id: 123,
+ processes: vec![foreground_process(
+ 123,
+ "python3.12",
+ &[
+ "/nix/store/example/bin/python3.12",
+ "/nix/store/example/bin/hermes",
+ "--resume",
+ "session-id",
+ ],
+ )],
+ };
+
+ assert_eq!(
+ identify_agent_in_job(&job),
+ Some((Agent::Hermes, "hermes".to_string()))
+ );
+ }
+
+ #[test]
fn identify_agent_in_job_detects_nix_wrapped_codex_from_cmdline_argv0() {
let job = crate::platform::ForegroundJob {
process_group_id: 123,