Skip to content

fix(agent): 修复 child_exec 被错误拼接 cwd 的问题#132

Merged
MistEO merged 5 commits intoMistEO:mainfrom
Windsland52:fix/agent
Mar 29, 2026
Merged

fix(agent): 修复 child_exec 被错误拼接 cwd 的问题#132
MistEO merged 5 commits intoMistEO:mainfrom
Windsland52:fix/agent

Conversation

@Windsland52
Copy link
Copy Markdown
Contributor

@Windsland52 Windsland52 commented Mar 27, 2026

  • child_exec 为裸命令名时(如 python)不再拼接 cwd,改为走 PATH
  • 仅对路径型 child_exec 基于 cwd 解析
  • 保留 normalize_path 的路径规范化处理

Sourcery 总结

修复代理子进程的执行方式:使裸命令名称使用系统 PATH,而只有类似路径的值才会相对于当前工作目录(cwd)进行解析。

错误修复:

  • 确保裸的 child_exec 命令名(例如 pythonnode)不再被错误地加上 cwd 前缀,而是依赖系统 PATH 进行解析。
  • 避免将绝对路径、以根目录为基础的路径或带盘符前缀的 child_exec 值相对于 cwd 进行解析,同时仍然对执行路径进行规范化处理。
  • 通过在创建进程之前对空值进行校验并抛出错误,防止在 child_exec 为空时启动代理。
Original summary in English

Summary by Sourcery

Fix agent child process execution so bare command names use the system PATH while only path-like values are resolved relative to cwd.

Bug Fixes:

  • Ensure bare child_exec command names (e.g. python, node) are no longer incorrectly prefixed with cwd and instead rely on system PATH resolution.
  • Avoid resolving absolute, root-based, or drive-prefixed child_exec values against cwd while still normalizing execution paths.
  • Prevent spawning an agent with an empty child_exec by validating and erroring on empty values before process creation.
Original summary in English

Sourcery 总结

修复代理子进程的执行方式:使裸命令名称使用系统 PATH,而只有类似路径的值才会相对于当前工作目录(cwd)进行解析。

错误修复:

  • 确保裸的 child_exec 命令名(例如 pythonnode)不再被错误地加上 cwd 前缀,而是依赖系统 PATH 进行解析。
  • 避免将绝对路径、以根目录为基础的路径或带盘符前缀的 child_exec 值相对于 cwd 进行解析,同时仍然对执行路径进行规范化处理。
  • 通过在创建进程之前对空值进行校验并抛出错误,防止在 child_exec 为空时启动代理。
Original summary in English

Summary by Sourcery

Fix agent child process execution so bare command names use the system PATH while only path-like values are resolved relative to cwd.

Bug Fixes:

  • Ensure bare child_exec command names (e.g. python, node) are no longer incorrectly prefixed with cwd and instead rely on system PATH resolution.
  • Avoid resolving absolute, root-based, or drive-prefixed child_exec values against cwd while still normalizing execution paths.
  • Prevent spawning an agent with an empty child_exec by validating and erroring on empty values before process creation.

Bug 修复:

  • 确保裸的 child_exec 命令名(例如 pythonnode)通过系统 PATH 进行解析,而不是与 cwd 进行拼接。
  • 仅对表示相对路径的 child_exec 值基于 cwd 进行解析,同时对所有执行路径继续保留 normalize_path 的处理。
Original summary in English

Sourcery 总结

修复代理子进程的执行方式:使裸命令名称使用系统 PATH,而只有类似路径的值才会相对于当前工作目录(cwd)进行解析。

错误修复:

  • 确保裸的 child_exec 命令名(例如 pythonnode)不再被错误地加上 cwd 前缀,而是依赖系统 PATH 进行解析。
  • 避免将绝对路径、以根目录为基础的路径或带盘符前缀的 child_exec 值相对于 cwd 进行解析,同时仍然对执行路径进行规范化处理。
  • 通过在创建进程之前对空值进行校验并抛出错误,防止在 child_exec 为空时启动代理。
Original summary in English

Summary by Sourcery

Fix agent child process execution so bare command names use the system PATH while only path-like values are resolved relative to cwd.

Bug Fixes:

  • Ensure bare child_exec command names (e.g. python, node) are no longer incorrectly prefixed with cwd and instead rely on system PATH resolution.
  • Avoid resolving absolute, root-based, or drive-prefixed child_exec values against cwd while still normalizing execution paths.
  • Prevent spawning an agent with an empty child_exec by validating and erroring on empty values before process creation.
Original summary in English

Sourcery 总结

修复代理子进程的执行方式:使裸命令名称使用系统 PATH,而只有类似路径的值才会相对于当前工作目录(cwd)进行解析。

错误修复:

  • 确保裸的 child_exec 命令名(例如 pythonnode)不再被错误地加上 cwd 前缀,而是依赖系统 PATH 进行解析。
  • 避免将绝对路径、以根目录为基础的路径或带盘符前缀的 child_exec 值相对于 cwd 进行解析,同时仍然对执行路径进行规范化处理。
  • 通过在创建进程之前对空值进行校验并抛出错误,防止在 child_exec 为空时启动代理。
Original summary in English

Summary by Sourcery

Fix agent child process execution so bare command names use the system PATH while only path-like values are resolved relative to cwd.

Bug Fixes:

  • Ensure bare child_exec command names (e.g. python, node) are no longer incorrectly prefixed with cwd and instead rely on system PATH resolution.
  • Avoid resolving absolute, root-based, or drive-prefixed child_exec values against cwd while still normalizing execution paths.
  • Prevent spawning an agent with an empty child_exec by validating and erroring on empty values before process creation.

- child_exec 为裸命令名时(如 python)不再拼接 cwd,改为走 PATH
- 仅对路径型 child_exec 基于 cwd 解析
- 保留 normalize_path 的路径规范化处理
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些高层次的反馈:

  • should_resolve_child_exec_from_cwd 中,你对 path.components() 调用了两次(先 count()next()),这会重建迭代器;可以考虑先捕获第一个组件,然后基于这一结果同时完成“只有单个组件”和“是否有目录层级”的检查,以简化逻辑并避免重复工作。
  • 对于应该通过 PATH 查找的裸命令名(例如 python),resolve_child_exec_path 仍然会把它们传给 normalize_path;如果 normalize_path 做的是类文件系统的路径规范化,你可能需要在处理非路径形式的裸命令时绕过它,以避免对命令名进行意料之外的变换。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- In `should_resolve_child_exec_from_cwd`, you iterate over `path.components()` twice (`count()` then `next()`), which reconstructs the iterator; consider capturing the first component once and basing both the “single component” and “has directory hierarchy” checks on that to simplify the logic and avoid repeated work.
- For bare command names that should go through PATH (e.g. `python`), `resolve_child_exec_path` still runs them through `normalize_path`; if `normalize_path` performs filesystem-style normalization, you might want to bypass it for non-path-like bare commands to avoid unexpected transformations on command names.

Sourcery 对开源项目免费——如果你喜欢我们的评审,请考虑帮忙分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English

Hey - I've left some high level feedback:

  • In should_resolve_child_exec_from_cwd, you iterate over path.components() twice (count() then next()), which reconstructs the iterator; consider capturing the first component once and basing both the “single component” and “has directory hierarchy” checks on that to simplify the logic and avoid repeated work.
  • For bare command names that should go through PATH (e.g. python), resolve_child_exec_path still runs them through normalize_path; if normalize_path performs filesystem-style normalization, you might want to bypass it for non-path-like bare commands to avoid unexpected transformations on command names.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `should_resolve_child_exec_from_cwd`, you iterate over `path.components()` twice (`count()` then `next()`), which reconstructs the iterator; consider capturing the first component once and basing both the “single component” and “has directory hierarchy” checks on that to simplify the logic and avoid repeated work.
- For bare command names that should go through PATH (e.g. `python`), `resolve_child_exec_path` still runs them through `normalize_path`; if `normalize_path` performs filesystem-style normalization, you might want to bypass it for non-path-like bare commands to avoid unexpected transformations on command names.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

…mmands raw

- simplify component parsing in should_resolve_child_exec_from_cwd
- avoid normalize_path for bare command names (e.g. python) so PATH lookup stays intact
- keep cwd-based resolution for relative path-like child_exec values
@Windsland52
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体性的反馈:

  • 用于判断 child_exec 是裸命令还是路径的逻辑在 should_resolve_child_exec_from_cwdresolve_child_exec_path 中都被重复实现了;建议抽取一个小的辅助函数(例如 is_bare_command(child_exec: &str) -> bool),以便更容易理解并保持这一行为的一致性。
  • 目前空字符串形式的 child_exec 会被当作相对路径处理,并最终解析为 cwd;建议显式处理空字符串的情况(例如更早返回错误),以避免无意中把工作目录本身当作命令来执行。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- 用于判断 `child_exec` 是裸命令还是路径的逻辑在 `should_resolve_child_exec_from_cwd``resolve_child_exec_path` 中都被重复实现了;建议抽取一个小的辅助函数(例如 `is_bare_command(child_exec: &str) -> bool`),以便更容易理解并保持这一行为的一致性。
- 目前空字符串形式的 `child_exec` 会被当作相对路径处理,并最终解析为 `cwd`;建议显式处理空字符串的情况(例如更早返回错误),以避免无意中把工作目录本身当作命令来执行。

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/maa_agent.rs" line_range="60-67" />
<code_context>
+/// - `python` / `node` 这类裸命令名:交给系统 PATH 查找,不拼接 cwd。
+/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
+/// - 绝对路径或带盘符前缀路径:按原值使用。
+fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
+    let path = Path::new(child_exec);
+    let mut components = path.components();
+    let first = components.next();
+    let second = components.next();
+
+    // 裸命令名(无目录层级)不应拼接 cwd
+    if first.is_some() && second.is_none() {
+        return matches!(first, Some(Component::CurDir | Component::ParentDir));
+    }
</code_context>
<issue_to_address>
**suggestion:** “裸命令”的检测逻辑被重复并拆分在两个函数中,随着时间推移可能会产生偏差。

`should_resolve_child_exec_from_cwd``resolve_child_exec_path` 都会重新获取路径的前两个组件,并且分别重新定义了“裸命令”的判定条件(`first.is_some() && second.is_none()` 对比 `matches!(first, Some(Component::Normal(_)))`)。建议抽取一个共享的辅助函数,比如 `fn is_bare_command(path: &Path) -> bool`,在两个地方共同使用,从而避免重复并保持判定标准的一致性。

建议实现如下:

```rust
use std::sync::{Arc, Mutex};
use std::thread;
use std::path::{Path, Component};
    ANSI_RE.replace_all(s, "").into_owned()
}

/// 判断给定路径是否是“裸命令名”, 即仅包含单个普通组件(无目录层级或前缀)。
///
/// 例如:
/// - `python` / `node` / `git`    -> 裸命令, 返回 true
/// - `./agent.py` / `../bin/tool` -> 非裸命令, 返回 false
/// - `subdir/tool`                -> 非裸命令, 返回 false
/// - 绝对路径或带盘符前缀路径     -> 非裸命令, 返回 false
fn is_bare_command(path: &Path) -> bool {
    let mut components = path.components();
    matches!(components.next(), Some(Component::Normal(_))) && components.next().is_none()
}

/// 判断 child_exec 是否应当作为相对路径(基于 cwd)解析。
///
/// - `python` / `node` 这类裸命令名:交给系统 PATH 查找,不拼接 cwd。
/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
/// - 绝对路径或带盘符前缀路径:按原值使用。
fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
    let path = Path::new(child_exec);

    // 裸命令交给 PATH 处理, 不拼接 cwd
    if is_bare_command(path) {
        return false;
    }

    let mut components = path.components();
    let first = components.next();

    match first {
        // 显式相对路径: ./xxx 或 ../xxx -> 基于 cwd 解析
        Some(Component::CurDir) | Some(Component::ParentDir) => true,
        // 绝对路径或带盘符前缀路径: 按原值使用, 不拼接 cwd
        Some(Component::Prefix(_)) | Some(Component::RootDir) => false,
        // 形如 `subdir/tool` 的相对路径: 基于 cwd 解析
        Some(Component::Normal(_)) => true,
        // 空字符串等情况: 保守起见不拼接 cwd
        None => false,
    }

```

在同一个文件中,还有一个函数 `resolve_child_exec_path`,目前是通过手动检查路径的前几个组件来重新实现“裸命令”的逻辑(例如使用 `first.is_some() && second.is_none()``matches!(first, Some(Component::Normal(_)))`)。为了彻底完成这次重构并避免重复,请更新该函数以使用新的辅助函数:

1. 将其内联的“裸命令”检查替换为 `if is_bare_command(&path) { ... }`2. 删除任何仅用于区分裸命令和其他路径而存在的重复 `components.next()` / `first` / `second` 处理逻辑。

这样可以将“裸命令”的判定标准集中到 `is_bare_command` 中,并防止不同函数之间产生不一致。
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/maa_agent.rs" line_range="61-70" />
<code_context>
+/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
+/// - 绝对路径或带盘符前缀路径:按原值使用。
+fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
+    let path = Path::new(child_exec);
+    let mut components = path.components();
+    let first = components.next();
+    let second = components.next();
+
+    // 裸命令名(无目录层级)不应拼接 cwd
+    if first.is_some() && second.is_none() {
+        return matches!(first, Some(Component::CurDir | Component::ParentDir));
+    }
+
+    if path.is_absolute() {
+        return false;
+    }
+
+    // Windows 盘符前缀(如 C:python.exe / C:\Python\python.exe)不拼接 cwd
+    if matches!(first, Some(Component::Prefix(_))) {
+        return false;
+    }
+
+    true
+}
+
</code_context>
<issue_to_address>
**question:** 空字符串或仅包含空白字符的 `child_exec` 会被当作相对路径处理,并最终解析为 `cwd`,这可能出乎意料。

对于空的 `child_exec``components()` 不会产生任何组件,因此会跳过“裸命令”的分支,`path.is_absolute()` 为 false,并且前缀检查也会被跳过。函数最终返回 `true`,因此 `resolve_child_exec_path` 会将 `""` 实际解析为 `cwd`。如果 `child_exec` 可能为空或无效,建议显式拒绝或跳过解析,而不是隐式地将其映射为 `cwd`。
</issue_to_address>

Sourcery 对开源项目是免费的 —— 如果你觉得这些 Review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进 Review 质量。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • The logic to determine whether child_exec is a bare command vs. a path is duplicated in both should_resolve_child_exec_from_cwd and resolve_child_exec_path; consider extracting a small helper (e.g., is_bare_command(child_exec: &str) -> bool) to make this behavior easier to reason about and keep consistent.
  • Right now an empty child_exec string would be treated as a relative path and effectively resolve to cwd; consider explicitly handling the empty-string case (e.g., returning an error earlier) to avoid unintentionally executing the working directory.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The logic to determine whether `child_exec` is a bare command vs. a path is duplicated in both `should_resolve_child_exec_from_cwd` and `resolve_child_exec_path`; consider extracting a small helper (e.g., `is_bare_command(child_exec: &str) -> bool`) to make this behavior easier to reason about and keep consistent.
- Right now an empty `child_exec` string would be treated as a relative path and effectively resolve to `cwd`; consider explicitly handling the empty-string case (e.g., returning an error earlier) to avoid unintentionally executing the working directory.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/maa_agent.rs" line_range="60-67" />
<code_context>
+/// - `python` / `node` 这类裸命令名:交给系统 PATH 查找,不拼接 cwd。
+/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
+/// - 绝对路径或带盘符前缀路径:按原值使用。
+fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
+    let path = Path::new(child_exec);
+    let mut components = path.components();
+    let first = components.next();
+    let second = components.next();
+
+    // 裸命令名(无目录层级)不应拼接 cwd
+    if first.is_some() && second.is_none() {
+        return matches!(first, Some(Component::CurDir | Component::ParentDir));
+    }
</code_context>
<issue_to_address>
**suggestion:** The “bare command” detection is duplicated and split across two functions, which could drift over time.

Both `should_resolve_child_exec_from_cwd` and `resolve_child_exec_path` re-derive the first two path components and each redefines the "bare command" check (`first.is_some() && second.is_none()` vs `matches!(first, Some(Component::Normal(_)))`). Consider extracting a shared helper like `fn is_bare_command(path: &Path) -> bool` and using it in both places to avoid duplication and keep the criteria consistent.

Suggested implementation:

```rust
use std::sync::{Arc, Mutex};
use std::thread;
use std::path::{Path, Component};
    ANSI_RE.replace_all(s, "").into_owned()
}

/// 判断给定路径是否是“裸命令名”, 即仅包含单个普通组件(无目录层级或前缀)。
///
/// 例如:
/// - `python` / `node` / `git`    -> 裸命令, 返回 true
/// - `./agent.py` / `../bin/tool` -> 非裸命令, 返回 false
/// - `subdir/tool`                -> 非裸命令, 返回 false
/// - 绝对路径或带盘符前缀路径     -> 非裸命令, 返回 false
fn is_bare_command(path: &Path) -> bool {
    let mut components = path.components();
    matches!(components.next(), Some(Component::Normal(_))) && components.next().is_none()
}

/// 判断 child_exec 是否应当作为相对路径(基于 cwd)解析。
///
/// - `python` / `node` 这类裸命令名:交给系统 PATH 查找,不拼接 cwd。
/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
/// - 绝对路径或带盘符前缀路径:按原值使用。
fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
    let path = Path::new(child_exec);

    // 裸命令交给 PATH 处理, 不拼接 cwd
    if is_bare_command(path) {
        return false;
    }

    let mut components = path.components();
    let first = components.next();

    match first {
        // 显式相对路径: ./xxx 或 ../xxx -> 基于 cwd 解析
        Some(Component::CurDir) | Some(Component::ParentDir) => true,
        // 绝对路径或带盘符前缀路径: 按原值使用, 不拼接 cwd
        Some(Component::Prefix(_)) | Some(Component::RootDir) => false,
        // 形如 `subdir/tool` 的相对路径: 基于 cwd 解析
        Some(Component::Normal(_)) => true,
        // 空字符串等情况: 保守起见不拼接 cwd
        None => false,
    }

```

There is another function `resolve_child_exec_path` in this file that currently re-derives the "bare command" logic by manually inspecting the first path components (e.g. via `first.is_some() && second.is_none()` or `matches!(first, Some(Component::Normal(_)))`). To fully apply the refactor and avoid duplication, update that function to use the new helper:

1. Replace its inline "bare command" checks with `if is_bare_command(&path) { ... }`.
2. Remove any duplicated `components.next()` / `first` / `second` handling that only exists to distinguish bare commands from other paths.

This will keep the criteria for bare commands centralized in `is_bare_command` and prevent them from drifting between the two functions.
</issue_to_address>

### Comment 2
<location path="src-tauri/src/commands/maa_agent.rs" line_range="61-70" />
<code_context>
+/// - `./agent.py` / `../bin/tool` / `subdir/tool`:视为相对路径,拼接 cwd。
+/// - 绝对路径或带盘符前缀路径:按原值使用。
+fn should_resolve_child_exec_from_cwd(child_exec: &str) -> bool {
+    let path = Path::new(child_exec);
+    let mut components = path.components();
+    let first = components.next();
+    let second = components.next();
+
+    // 裸命令名(无目录层级)不应拼接 cwd
+    if first.is_some() && second.is_none() {
+        return matches!(first, Some(Component::CurDir | Component::ParentDir));
+    }
+
+    if path.is_absolute() {
+        return false;
+    }
+
+    // Windows 盘符前缀(如 C:python.exe / C:\Python\python.exe)不拼接 cwd
+    if matches!(first, Some(Component::Prefix(_))) {
+        return false;
+    }
+
+    true
+}
+
</code_context>
<issue_to_address>
**question:** Empty or whitespace-only `child_exec` will be treated as a relative path and effectively resolve to `cwd`, which might be surprising.

For an empty `child_exec`, `components()` yields nothing, so the bare-command branch is skipped, `path.is_absolute()` is false, and the prefix check is skipped. The function then returns `true`, so `resolve_child_exec_path` effectively resolves `""` to `cwd`. If `child_exec` can be empty or otherwise invalid, consider explicitly rejecting or bypassing resolution instead of implicitly mapping it to `cwd`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

…cutable

- extract `is_bare_command` to centralize bare-command detection
- reuse shared classification in both resolve/decision paths to avoid drift
- keep bare commands raw for PATH lookup (skip normalize_path)
- validate `child_exec` at spawn time and return error when empty/whitespace
@Windsland52
Copy link
Copy Markdown
Contributor Author

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些总体反馈:

  • resolve_child_exec_pathshould_resolve_child_exec_from_cwd 这两个函数中,你都把 child_exec 解析成 Path 并调用了 is_bare_command,这有点重复;可以考虑把这部分逻辑整合起来,在一个地方对 child_exec 进行解析并分类(bare/relative/absolute/prefixed),然后复用结果以简化控制流。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In `resolve_child_exec_path` and `should_resolve_child_exec_from_cwd` you both parse `child_exec` into a `Path` and call `is_bare_command`, which is slightly redundant; consider consolidating the logic so `child_exec` is parsed and classified (bare/relative/absolute/prefixed) in one place and reused to simplify the control flow.

Sourcery 对开源项目是免费的——如果你觉得我们的 review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈来改进后续的 review。
Original comment in English

Hey - I've left some high level feedback:

  • In resolve_child_exec_path and should_resolve_child_exec_from_cwd you both parse child_exec into a Path and call is_bare_command, which is slightly redundant; consider consolidating the logic so child_exec is parsed and classified (bare/relative/absolute/prefixed) in one place and reused to simplify the control flow.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `resolve_child_exec_path` and `should_resolve_child_exec_from_cwd` you both parse `child_exec` into a `Path` and call `is_bare_command`, which is slightly redundant; consider consolidating the logic so `child_exec` is parsed and classified (bare/relative/absolute/prefixed) in one place and reused to simplify the control flow.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

…tion

- introduce `ChildExecKind` and `classify_child_exec` for one-pass parsing
- remove duplicated bare/relative/absolute checks across helper functions
- make `resolve_child_exec_path` branch on unified classification
- keep empty `child_exec` validation at spawn time
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 修复了启动 Agent 子进程时对 child_exec 的路径解析逻辑:让裸命令名(如 python/node)通过系统 PATH 解析,仅对相对路径型 child_exec 基于 cwd 进行拼接与规范化。

Changes:

  • 新增 child_exec 分类与解析逻辑:区分裸命令名/相对路径/绝对或带前缀路径。
  • 启动进程前对空 child_exec 做校验并返回明确错误。
  • 仅对相对路径型 child_exec 执行 cwd 拼接与 normalize_path 规范化。

- update `resolve_child_exec_path` doc comment to match actual normalization behavior
- treat inputs containing `/` or `\` as path-like (not bare commands)
- prevent cases like `python/` or `python\\` from being misclassified as PATH commands
@MistEO MistEO merged commit 046b498 into MistEO:main Mar 29, 2026
9 checks passed
@Windsland52 Windsland52 deleted the fix/agent branch April 4, 2026 05:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants