Skip to content

feat: 脚本程序区分启动器模式和直接启动模式#59

Open
ShadowLemoon wants to merge 10 commits into
mainfrom
feat/launcher-mode
Open

feat: 脚本程序区分启动器模式和直接启动模式#59
ShadowLemoon wants to merge 10 commits into
mainfrom
feat/launcher-mode

Conversation

@ShadowLemoon
Copy link
Copy Markdown
Collaborator

@ShadowLemoon ShadowLemoon commented May 20, 2026

Summary by CodeRabbit

  • New Features

    • 新增“启动进阶”模式:支持配置多个目标进程用于追踪
    • 新增可预设的多值输入组件,便于编辑列表型设置
  • Bug Fixes

    • 修复手风琴展开时的尺寸/间隙闪烁与布局不同步问题
    • 改进进程查找逻辑,降低误判率并避免匹配到启动前已存在进程
  • Improvements

    • 显示标签可点击以快速切换选项
    • 启动时自动迁移旧脚本配置并在需要时保存兼容结果

Review Change Stack

- 将脚本进程名配置迁移为候选进程列表
- 运行器区分直接启动和启动器启动场景
- 进程匹配统一规范化名称并避免匹配启动前已有进程
- 新增启动进阶折叠区和启动器模式开关
- 支持填写多个启动后实际运行的候选程序
- 将启动器模式校验错误定位到进阶区域
- 移除多余的 QDialog 枚举判断
- 直接使用弹窗 exec 结果判断是否保存备注
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 63861d9a-e2ff-4c9b-8534-c2059a41d130

📥 Commits

Reviewing files that changed from the base of the PR and between 6c0c8f9 and 56e8a4c.

📒 Files selected for processing (1)
  • src/one_dragon/utils/log_utils.py

Walkthrough

此 PR 引入启动器模式:增加进程名规范化工具、将脚本进程名改为多值并扩展配置与迁移逻辑,升级 ProcessManager 支持多目标查找/排除快照,新增多值设置卡与交互改进,并将功能整合到脚本运行器与脚本编辑界面。

Changes

Launcher Mode & Multi-Process Configuration

Layer / File(s) Summary
Process Name Utilities & Imports
src/script_chainer/utils/process_name_utils.py, src/script_chainer/config/script_config.py
新增 normalize_process_namenormalize_process_namesprocess_name_equalsformat_process_names_for_text,并在配置模块引入以支持兼容迁移与比较。
Config Enums & Data Structure
src/script_chainer/config/script_config.py
新增 ScriptLaunchMethod 与重构 ScriptProcessName 为多值,ScriptConfig 新增 game_labellauncher_modescript_process_name 改为 list[str] 并调整展示/校验属性与迁移实现。
Config Validation & Legacy Migration
src/script_chainer/config/script_config.py, src/script_chainer/context/script_chainer_context.py
实现脚本链配置迁移流程与自动持久化迁移:在上下文初始化时遍历 .yml 并触发一次性迁移加载,ScriptChainConfig 加载时对 script_list 执行迁移并在需要时保存。
Widget Components Enhancement
src/one_dragon_qt/widgets/setting_card/expand_setting_card_group.py, src/one_dragon_qt/widgets/setting_card/multi_value_display_combo_box_setting_card.py, src/one_dragon_qt/widgets/setting_card/value_display_editable_combo_box_setting_card.py, src/one_dragon_qt/view/setting/setting_push_interface.py
ExpandSettingCardGroup 新增 initial_expand 与布局同步/异步刷新机制;新增 MultiValueDisplayComboBoxSettingCard 多行输入与预设下拉组件;ValueDisplayEditableComboBoxSettingCard 增强显示标签点击展开下拉;设置界面相应精简 adapter 类型标注与初始展开调用。
Process Manager Multi-Process Support
src/script_chainer/services/process_manager.py
新增 find_process_by_infoscollect_matching_process_pidsbuild_process_infos,使用 process_name_equals 比较名,is_process_existedopen_process/search_process 签名改为接受目标列表并引入 _target_pid_snapshot 快照排除逻辑。
Script Edit UI - Launcher Mode Integration
src/script_chainer/gui/page/script_edit_interface.py
新增 launcher_mode_switchlaunch_advanced_group,将“启动后实际运行的程序”替换为 MultiValueDisplayComboBoxSettingCard,在读写配置时对多值结果做规范化并在校验失败时调整错误展示与强制展开进阶组。
Script Runner - Launcher Mode Execution
src/script_chainer/win_exe/script_runner.py
新增 _get_target_process_infos_format_process_hint,在 launcher 模式下传入多目标集合给 ProcessManager,并在等待/监控/清理阶段支持多目标检测、超时提示与只打印一次的提示逻辑。
Dialog Result Handling Simplification
src/script_chainer/gui/page/script_setting_cards.py
dialog.exec() == QDialog.DialogCode.Accepted 判定改为更简洁的 if dialog.exec(): 布尔判断。
Misc: Logging & Typing
src/one_dragon/utils/log_utils.py
日志路径处理改用 pathlib.Path,并在 get_logger 上添加返回类型注解。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

我是兔子钻进代码堆,🐇
把进程名理成整齐列,
多值卡片能添能删,
展开动画不再乱排列,
启动器守望目标无碍。 ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确总结了本次变更的核心内容:为脚本程序新增启动器模式和直接启动模式的区分功能。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/launcher-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/one_dragon_qt/widgets/setting_card/multi_value_display_combo_box_setting_card.py`:
- Around line 254-276: setValue currently rebuilds rows but doesn't propagate
the new value back to the adapter or emit the value_changed signal when called
with emit_signal=True (used by _on_preset_changed → setValue), so fix setValue
to, after rebuilding rows and refreshing layout (after _refresh_layout() /
setContent()), call the adapter's set_value with the current value
(adapter.set_value(self.getValue())) and then emit the value_changed signal
(value_changed.emit(...)) only when emit_signal is True; keep the existing
_block_signals behavior when emit_signal is False so no signals are emitted in
that case.

In `@src/script_chainer/config/script_config.py`:
- Line 4: Replace cross-platform PurePath usage with PureWindowsPath when
extracting a Windows-style launcher filename: import PureWindowsPath (instead of
PurePath) at the top, then update the two extraction sites — the
_infer_launcher_mode() method and the launch_program_name property — to
construct a PureWindowsPath from the stored launcher path and use its .name to
get the filename; keep Path for filesystem operations if used elsewhere but
ensure the filename extraction specifically uses PureWindowsPath to avoid
platform-dependent parsing.
- Around line 104-106: _infer_launcher_mode currently returns
bool(data.get('launcher_mode')) which treats any non-empty string (e.g. "false"
or "0") as True; change it to explicitly parse the value: read val =
data.get('launcher_mode'), if isinstance(val, bool) return val, if
isinstance(val, (int, float)) return bool(val), if isinstance(val, str) compare
val.lower().strip() against accepted true tokens ("true","1","yes","y","on") and
false tokens ("false","0","no","n","off") and return the corresponding boolean,
otherwise fall back to the original inference logic using script_process_names.
Ensure this logic is implemented in the _infer_launcher_mode function.

In `@src/script_chainer/gui/page/script_edit_interface.py`:
- Around line 373-381: The code currently only sets
self.script_process_name_opt.set_error_message(invalid_message) for the specific
launcher-mode messages but does not clear that control when other validation
errors occur; update the non-launcher error branch to clear the process-name
error state by calling self.script_process_name_opt.set_error_message(None) (or
the widget’s clear error method) before setting and showing self.error_label and
returning False, keeping existing use of
self.launch_advanced_group.setExpand(True) in the launcher-specific branch
unchanged.
- Around line 329-339: _sync_launch_advanced_summary currently calls
get_config_value() which parses the whole form (and can raise when unrelated
fields like timeout are invalid); change it to read only the specific UI
controls that affect the summary instead of calling get_config_value(): directly
query the launcher mode control and the process name input (the widgets that
populate config.launcher_mode and config.script_process_display_name) and then
set the summary via self.launch_advanced_group.card.setContent(summary); this
avoids parsing unrelated fields and prevents exceptions from breaking the Qt
slot.

In `@src/script_chainer/win_exe/script_runner.py`:
- Around line 369-390: The current launcher-mode branch switches to a global
name check (is_process_existed(script_config.script_process_name)), which can
misidentify other same-named processes; instead keep using the ProcessManager
instance to verify the actual target PID. Replace the launcher_mode branch so
that when script_config.launcher_mode is true you call pm.is_running() (the same
check used in the non-launcher branch) to set script_current_existed, rather
than is_process_existed(...); preserve the rest of the script_ever_existed /
script_closed / script_hint_printed logic and ensure pm is the same
ProcessManager used during startup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 93dd4089-43ca-48d5-afa5-db798d40c788

📥 Commits

Reviewing files that changed from the base of the PR and between cb39829 and 360aa36.

📒 Files selected for processing (10)
  • src/one_dragon_qt/view/setting/setting_push_interface.py
  • src/one_dragon_qt/widgets/setting_card/expand_setting_card_group.py
  • src/one_dragon_qt/widgets/setting_card/multi_value_display_combo_box_setting_card.py
  • src/one_dragon_qt/widgets/setting_card/value_display_editable_combo_box_setting_card.py
  • src/script_chainer/config/script_config.py
  • src/script_chainer/gui/page/script_edit_interface.py
  • src/script_chainer/gui/page/script_setting_cards.py
  • src/script_chainer/services/process_manager.py
  • src/script_chainer/utils/process_name_utils.py
  • src/script_chainer/win_exe/script_runner.py

Comment thread src/script_chainer/config/script_config.py Outdated
Comment thread src/script_chainer/config/script_config.py Outdated
Comment thread src/script_chainer/gui/page/script_edit_interface.py
Comment thread src/script_chainer/gui/page/script_edit_interface.py
Comment thread src/script_chainer/win_exe/script_runner.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/script_chainer/win_exe/script_runner.py (1)

88-99: 💤 Low value

PurePath 在 Windows 专用模块中可接受,但建议保持一致性。

Line 94 使用 PurePath(script_path).name 提取启动器文件名。由于此文件位于 win_exe 目录,仅在 Windows 上运行,PurePath 会正确解析 Windows 路径。

但为了与 script_config.py 中的修复保持一致(已改用 PureWindowsPath),建议统一使用 PureWindowsPath

可选:保持与 script_config.py 一致
-from pathlib import Path, PurePath
+from pathlib import Path, PureWindowsPath

 def _get_target_process_infos(script_path: str, configured_process_name: list[str]) -> list[ProcessInfo]:
-    launcher_name = PurePath(script_path).name
+    launcher_name = PureWindowsPath(script_path).name
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/script_chainer/win_exe/script_runner.py` around lines 88 - 99, The
function _get_target_process_infos uses PurePath to extract the launcher_name
from script_path; to keep Windows-specific path handling consistent with
script_config.py, replace PurePath with PureWindowsPath: import PureWindowsPath
from pathlib and compute launcher_name = PureWindowsPath(script_path).name so
Windows paths are parsed correctly in the win_exe module.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/script_chainer/win_exe/script_runner.py`:
- Around line 88-99: The function _get_target_process_infos uses PurePath to
extract the launcher_name from script_path; to keep Windows-specific path
handling consistent with script_config.py, replace PurePath with
PureWindowsPath: import PureWindowsPath from pathlib and compute launcher_name =
PureWindowsPath(script_path).name so Windows paths are parsed correctly in the
win_exe module.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a7efc59-c0d6-409b-be1d-17ad135922f1

📥 Commits

Reviewing files that changed from the base of the PR and between 360aa36 and 6c0c8f9.

📒 Files selected for processing (5)
  • src/one_dragon_qt/widgets/setting_card/multi_value_display_combo_box_setting_card.py
  • src/script_chainer/config/script_config.py
  • src/script_chainer/context/script_chainer_context.py
  • src/script_chainer/gui/page/script_edit_interface.py
  • src/script_chainer/win_exe/script_runner.py

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.

1 participant