Skip to content

Comments

feat: 前置程序和自定义程序添加不重复启动选项#84

Merged
MistEO merged 8 commits intoMistEO:mainfrom
ShadowLemoon:feat/check-running-program
Feb 24, 2026
Merged

feat: 前置程序和自定义程序添加不重复启动选项#84
MistEO merged 8 commits intoMistEO:mainfrom
ShadowLemoon:feat/check-running-program

Conversation

@ShadowLemoon
Copy link
Contributor

@ShadowLemoon ShadowLemoon commented Feb 23, 2026

Summary by Sourcery

为启动程序新增可配置的 “skip-if-running(若已在运行则跳过)” 行为,并在后端和 UI 中集成跨平台的进程运行检查。

新功能:

  • 将跨平台的进程运行检查暴露为一个 Tauri 命令,并将其接入前端的 service API。
  • 为通用动作和 MXU_LAUNCH 任务引入 skip-if-running 选项,以避免启动重复的程序实例。
  • 使工具栏的预动作在目标程序已在运行时有条件地跳过执行,并输出适当的面向用户的日志。

增强:

  • 扩展特殊任务定义和表单,以展示与启动相关操作的 skip-if-running 开关。
  • 在所有支持的语言中添加本地化字符串,用于描述 skip-if-running 行为及预动作被跳过时的通知。

构建:

  • 在 Tauri 的 Windows 依赖集内启用 Windows ToolHelp 诊断功能,以支持进程枚举。
Original summary in English

Summary by Sourcery

Add configurable skip-if-running behavior for launching programs and integrate a cross-platform process running check across backend and UI.

New Features:

  • Expose a cross-platform process running check as a Tauri command and wire it into the frontend service API.
  • Introduce a skip-if-running option for generic actions and MXU_LAUNCH tasks to avoid starting duplicate program instances.
  • Make toolbar pre-actions conditionally skip execution when the target program is already running, with appropriate user-facing logs.

Enhancements:

  • Extend special task definitions and forms to surface the skip-if-running switch for launch-related operations.
  • Add localized strings in all supported languages describing the skip-if-running behavior and pre-action skip notifications.

Build:

  • Enable the Windows ToolHelp diagnostics feature in the Tauri Windows dependency set to support process enumeration.

新功能:

  • 在后端引入跨平台的进程运行检查工具,并将其作为 Tauri 命令对外暴露。
  • 为启动任务和自定义操作程序添加可配置的“如果正在运行则跳过”选项,对新建操作默认启用。
  • 允许 MXU_LAUNCH 任务在检测到基于完整可执行文件路径的现有实例时,有条件地跳过启动程序。

增强:

  • 更新工具栏工作流以遵循新的“如果正在运行则跳过”预操作行为,并在跳过执行时记录日志。
  • 扩展特殊任务定义和 UI 表单,以展示适用于启动相关操作的“如果正在运行则跳过”开关。
  • 在所有支持的语言中添加本地化字符串,用于描述“如果正在运行则跳过”的行为及相关用户提示信息。

构建:

  • 在 Tauri 的 Windows 依赖集里启用 Windows ToolHelp 诊断特性,以支持进程枚举。
Original summary in English

Summary by Sourcery

为启动程序新增可配置的 “skip-if-running(若已在运行则跳过)” 行为,并在后端和 UI 中集成跨平台的进程运行检查。

新功能:

  • 将跨平台的进程运行检查暴露为一个 Tauri 命令,并将其接入前端的 service API。
  • 为通用动作和 MXU_LAUNCH 任务引入 skip-if-running 选项,以避免启动重复的程序实例。
  • 使工具栏的预动作在目标程序已在运行时有条件地跳过执行,并输出适当的面向用户的日志。

增强:

  • 扩展特殊任务定义和表单,以展示与启动相关操作的 skip-if-running 开关。
  • 在所有支持的语言中添加本地化字符串,用于描述 skip-if-running 行为及预动作被跳过时的通知。

构建:

  • 在 Tauri 的 Windows 依赖集内启用 Windows ToolHelp 诊断功能,以支持进程枚举。
Original summary in English

Summary by Sourcery

Add configurable skip-if-running behavior for launching programs and integrate a cross-platform process running check across backend and UI.

New Features:

  • Expose a cross-platform process running check as a Tauri command and wire it into the frontend service API.
  • Introduce a skip-if-running option for generic actions and MXU_LAUNCH tasks to avoid starting duplicate program instances.
  • Make toolbar pre-actions conditionally skip execution when the target program is already running, with appropriate user-facing logs.

Enhancements:

  • Extend special task definitions and forms to surface the skip-if-running switch for launch-related operations.
  • Add localized strings in all supported languages describing the skip-if-running behavior and pre-action skip notifications.

Build:

  • Enable the Windows ToolHelp diagnostics feature in the Tauri Windows dependency set to support process enumeration.

Copy link
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 - 我发现了 3 个问题,并留下了一些总体反馈:

  • 在 Windows 的 check_process_running 中,使用手动构造的字节配合 OsStr::from_encoded_bytes_unchecked 来转换 entry.szExeFile 既不安全也不符合惯用法;建议直接在 u16 切片上使用 OsString::from_wide(通过 std::os::windows::ffi::OsStringExt)来避免潜在的编码问题和未定义行为。
  • ActionConfig 的注释说 skipIfRunning 的默认值是 false,但 ActionItem 中的 defaultActionAddTaskPanel 都将其初始化为 true;请统一注释或默认值,使文档说明的行为与实际初始化保持一致。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `check_process_running` on Windows, the conversion of `entry.szExeFile` using `OsStr::from_encoded_bytes_unchecked` with manually constructed bytes is both unsafe and not idiomatic; consider using `OsString::from_wide` (via `std::os::windows::ffi::OsStringExt`) on the `u16` slice directly to avoid potential encoding issues and undefined behavior.
- The `ActionConfig` comment says `skipIfRunning` is default `false`, but both `defaultAction` in `ActionItem` and `AddTaskPanel` initialize it to `true`; align the comment or the defaults so the documented behavior matches the actual initialization.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/system.rs" line_range="250-251" />
<code_context>
+            if Process32FirstW(snapshot, &mut entry).is_ok() {
+                loop {
+                    // 从 szExeFile 提取进程名
+                    let exe_name = OsStr::from_encoded_bytes_unchecked(
+                        &entry.szExeFile.iter()
+                            .take_while(|&&c| c != 0)
+                            .flat_map(|c| c.to_le_bytes())
</code_context>
<issue_to_address>
**issue (bug_risk):** The Windows process name extraction via `OsStr::from_encoded_bytes_unchecked` is incorrect and likely won’t compile on Windows; prefer decoding from UTF-16 directly.

`PROCESSENTRY32W::szExeFile` is UTF-16, so flattening `u16` to bytes and using `OsStr::from_encoded_bytes_unchecked` is incorrect. That API is also Unix-only on stable Rust, so this likely won’t compile on Windows. Instead, decode the UTF-16 directly:

```rust
let len = entry
    .szExeFile
    .iter()
    .position(|&c| c == 0)
    .unwrap_or(entry.szExeFile.len());
let exe_name = String::from_utf16_lossy(&entry.szExeFile[..len]).to_lowercase();
```

Then compare `exe_name` directly to `file_name_lower` without using `OsStr::from_encoded_bytes_unchecked`.
</issue_to_address>

### Comment 2
<location path="src/types/interface.ts" line_range="212" />
<code_context>
   program: string; // 程序路径
   args: string; // 附加参数
   waitForExit: boolean; // 是否等待进程退出(默认 true)
+  skipIfRunning: boolean; // 程序已运行时跳过执行(默认 false)
 }

</code_context>
<issue_to_address>
**nitpick:** The comment for `skipIfRunning`’s default doesn’t match the actual defaults used elsewhere.

This comment states the default is `false`, but both `ActionItem` and `AddTaskPanel` initialize `skipIfRunning` to `true`. Please either update the comment to `默认 true` or change those initializations to `false` so the documented default matches actual usage.
</issue_to_address>

### Comment 3
<location path="src/i18n/locales/ko-KR.ts" line_range="283" />
<code_context>
+    skipIfRunning: '실행 중이면 건너뛰기',
+    skipIfRunningHint:
+      '활성화하면 프로그램이 이미 실행 중인 경우 실행을 건너뛱니다. 게임 등의 재시작을 피하는 데 유용합니다',
+    preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뛰니다',
     waitingForDevice: '장치 준비 대기 중...',
     waitingForWindow: '윈도우 준비 대기 중...',
</code_context>
<issue_to_address>
**nitpick (typo):** There’s a small Korean typo in the `preActionSkipped` string.

In `preActionSkipped`, please change `건너뛰니다` to `건너뜁니다`:

```ts
preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뜁니다',
```

```suggestion
    preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뜁니다',
```
</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.
Original comment in English

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

  • In check_process_running on Windows, the conversion of entry.szExeFile using OsStr::from_encoded_bytes_unchecked with manually constructed bytes is both unsafe and not idiomatic; consider using OsString::from_wide (via std::os::windows::ffi::OsStringExt) on the u16 slice directly to avoid potential encoding issues and undefined behavior.
  • The ActionConfig comment says skipIfRunning is default false, but both defaultAction in ActionItem and AddTaskPanel initialize it to true; align the comment or the defaults so the documented behavior matches the actual initialization.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `check_process_running` on Windows, the conversion of `entry.szExeFile` using `OsStr::from_encoded_bytes_unchecked` with manually constructed bytes is both unsafe and not idiomatic; consider using `OsString::from_wide` (via `std::os::windows::ffi::OsStringExt`) on the `u16` slice directly to avoid potential encoding issues and undefined behavior.
- The `ActionConfig` comment says `skipIfRunning` is default `false`, but both `defaultAction` in `ActionItem` and `AddTaskPanel` initialize it to `true`; align the comment or the defaults so the documented behavior matches the actual initialization.

## Individual Comments

### Comment 1
<location path="src-tauri/src/commands/system.rs" line_range="250-251" />
<code_context>
+            if Process32FirstW(snapshot, &mut entry).is_ok() {
+                loop {
+                    // 从 szExeFile 提取进程名
+                    let exe_name = OsStr::from_encoded_bytes_unchecked(
+                        &entry.szExeFile.iter()
+                            .take_while(|&&c| c != 0)
+                            .flat_map(|c| c.to_le_bytes())
</code_context>
<issue_to_address>
**issue (bug_risk):** The Windows process name extraction via `OsStr::from_encoded_bytes_unchecked` is incorrect and likely won’t compile on Windows; prefer decoding from UTF-16 directly.

`PROCESSENTRY32W::szExeFile` is UTF-16, so flattening `u16` to bytes and using `OsStr::from_encoded_bytes_unchecked` is incorrect. That API is also Unix-only on stable Rust, so this likely won’t compile on Windows. Instead, decode the UTF-16 directly:

```rust
let len = entry
    .szExeFile
    .iter()
    .position(|&c| c == 0)
    .unwrap_or(entry.szExeFile.len());
let exe_name = String::from_utf16_lossy(&entry.szExeFile[..len]).to_lowercase();
```

Then compare `exe_name` directly to `file_name_lower` without using `OsStr::from_encoded_bytes_unchecked`.
</issue_to_address>

### Comment 2
<location path="src/types/interface.ts" line_range="212" />
<code_context>
   program: string; // 程序路径
   args: string; // 附加参数
   waitForExit: boolean; // 是否等待进程退出(默认 true)
+  skipIfRunning: boolean; // 程序已运行时跳过执行(默认 false)
 }

</code_context>
<issue_to_address>
**nitpick:** The comment for `skipIfRunning`’s default doesn’t match the actual defaults used elsewhere.

This comment states the default is `false`, but both `ActionItem` and `AddTaskPanel` initialize `skipIfRunning` to `true`. Please either update the comment to `默认 true` or change those initializations to `false` so the documented default matches actual usage.
</issue_to_address>

### Comment 3
<location path="src/i18n/locales/ko-KR.ts" line_range="283" />
<code_context>
+    skipIfRunning: '실행 중이면 건너뛰기',
+    skipIfRunningHint:
+      '활성화하면 프로그램이 이미 실행 중인 경우 실행을 건너뛱니다. 게임 등의 재시작을 피하는 데 유용합니다',
+    preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뛰니다',
     waitingForDevice: '장치 준비 대기 중...',
     waitingForWindow: '윈도우 준비 대기 중...',
</code_context>
<issue_to_address>
**nitpick (typo):** There’s a small Korean typo in the `preActionSkipped` string.

In `preActionSkipped`, please change `건너뛰니다` to `건너뜁니다`:

```ts
preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뜁니다',
```

```suggestion
    preActionSkipped: '전처리 프로그램 {{name}} 이(가) 실행 중이므로 건너뜁니다',
```
</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.

Copy link
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

为“前置程序/自定义程序”增加“已运行则跳过”的可配置选项:前端新增开关并在启动前置动作前调用后端进程检查;后端提供跨平台进程运行检测与 Tauri 命令,并扩展 MXU_LAUNCH 支持按完整路径检测到已运行时跳过启动;同时补全多语言文案与 Windows 进程枚举依赖特性。

Changes:

  • 前端:为前置动作(pre-action)新增 skipIfRunning 配置与 UI 开关,并在 Toolbar 启动流程中按需跳过执行。
  • 后端:新增 check_process_running/is_process_running,并在 MXU_LAUNCH custom action 中支持 skip_if_running
  • 国际化/构建:补齐各语言文案;Windows 启用 ToolHelp 相关 features 以支持进程枚举。

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/types/specialTasks.ts MXU_LAUNCH 增加“已运行则跳过”开关选项定义与 pipeline override 参数注入
src/types/interface.ts ActionConfig 增加 skipIfRunning 字段
src/services/maaService.ts 新增 isProcessRunning() 调用 Tauri 命令
src/components/Toolbar.tsx 启动前置动作前增加“已运行则跳过”判断与 UI 日志提示
src/components/AddTaskPanel.tsx 新建动作默认开启 skipIfRunning
src/components/ActionItem.tsx 动作编辑 UI 增加 skipIfRunning 开关并设置默认值
src/i18n/locales/* 增加相关文案(specialTask.launch.* / action.skipIfRunning* / action.preActionSkipped)
src-tauri/src/commands/system.rs 新增跨平台进程检查实现与 is_process_running Tauri 命令
src-tauri/src/mxu_actions.rs MXU_LAUNCH 支持 skip_if_running 并调用进程检查
src-tauri/src/lib.rs 注册 is_process_running 命令
src-tauri/Cargo.toml Windows 增加 ToolHelp feature 以支持进程枚举

@MistEO
Copy link
Owner

MistEO commented Feb 23, 2026

@sourcery-ai review

Copy link
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 - 我在这里给出了一些整体性的反馈:

  • 在 macOS 的 check_process_running 实现中,proc_listallpids 被当作返回字节大小来处理(let num_pids = actual as usize / std::mem::size_of::<i32>()),但该 API 实际上返回的是 PID 的数量,所以你可以去掉这个除法,直接遍历 &pids[..actual as usize],以避免出现静默跳过某些进程的情况。
  • 对于 macOS 的 extern "C" libproc 调用(proc_listallpids/proc_pidpath),建议在 extern 块上显式添加 #[link(name = "proc")],以确保在所有构建配置下都能正确链接。
  • 新的 check_process_running 函数在所有平台上每次检查都会记录一条 info 日志;如果这个函数被频繁调用(例如通过工具栏或 MXU 启动操作),你可能需要把这些日志降级为 debug!,或者用详细模式(verbose flag)进行控制,以避免在正常使用中产生过多日志。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- In the macOS `check_process_running` implementation, `proc_listallpids` is treated as returning a byte size (`let num_pids = actual as usize / std::mem::size_of::<i32>()`), but the API actually returns the count of PIDs, so you can drop the division and iterate over `&pids[..actual as usize]` to avoid silently skipping processes.
- For the macOS `extern "C"` libproc calls (`proc_listallpids`/`proc_pidpath`), consider adding an explicit `#[link(name = "proc")]` on the extern block to ensure correct linkage on all build configurations.
- The new `check_process_running` function logs an info line for every check on all platforms; if this is called frequently (e.g., from the toolbar or MXU launch actions), you may want to downgrade these to `debug!` or guard them behind a verbose flag to avoid log spam in normal usage.

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

Hey - I've left some high level feedback:

  • In the macOS check_process_running implementation, proc_listallpids is treated as returning a byte size (let num_pids = actual as usize / std::mem::size_of::<i32>()), but the API actually returns the count of PIDs, so you can drop the division and iterate over &pids[..actual as usize] to avoid silently skipping processes.
  • For the macOS extern "C" libproc calls (proc_listallpids/proc_pidpath), consider adding an explicit #[link(name = "proc")] on the extern block to ensure correct linkage on all build configurations.
  • The new check_process_running function logs an info line for every check on all platforms; if this is called frequently (e.g., from the toolbar or MXU launch actions), you may want to downgrade these to debug! or guard them behind a verbose flag to avoid log spam in normal usage.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the macOS `check_process_running` implementation, `proc_listallpids` is treated as returning a byte size (`let num_pids = actual as usize / std::mem::size_of::<i32>()`), but the API actually returns the count of PIDs, so you can drop the division and iterate over `&pids[..actual as usize]` to avoid silently skipping processes.
- For the macOS `extern "C"` libproc calls (`proc_listallpids`/`proc_pidpath`), consider adding an explicit `#[link(name = "proc")]` on the extern block to ensure correct linkage on all build configurations.
- The new `check_process_running` function logs an info line for every check on all platforms; if this is called frequently (e.g., from the toolbar or MXU launch actions), you may want to downgrade these to `debug!` or guard them behind a verbose flag to avoid log spam in normal usage.

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.

Copy link
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

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

@MistEO
Copy link
Owner

MistEO commented Feb 23, 2026

刚刚 revert 掉了之前的一个 rs 的 PR,有冲突了现在,请帮忙看一下

Copy link
Contributor Author

@ShadowLemoon ShadowLemoon left a comment

Choose a reason for hiding this comment

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

done

Copy link
Contributor Author

@ShadowLemoon ShadowLemoon left a comment

Choose a reason for hiding this comment

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

windows测试运行良好 我没有其它系统

@MistEO MistEO merged commit d59e328 into MistEO:main Feb 24, 2026
9 checks passed
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.

2 participants