Skip to content

fix: 修复本机安装的代码助手因缺少 PATH 无法启动的问题 - #127

Merged
Yurken merged 1 commit into
masterfrom
codex/dsh-startup-path
Sep 17, 2026
Merged

Yurken merged 1 commit into
masterfrom
codex/dsh-startup-path

Conversation

@Yurken

@Yurken Yurken commented Sep 17, 2026

Copy link
Copy Markdown
Owner

改动说明

macOS 上由 Finder / Dock 启动的 GUI 进程只继承最小 PATH(/usr/bin:/bin:/usr/sbin:/sbin)。代码助手 CLI 普遍以 #!/usr/bin/env node 这类 shebang 启动,而现有实现只解决了「找到可执行文件」这一半:find_dsh() 会遍历扩展候选目录并正确命中 /opt/homebrew/bin/dsh,但 spawn 时仍原样继承最小 PATH。

结果解释器不可见,进程立即退出,界面只显示 DSH 进程已退出(exit status: 127),stderr 为 env: node: No such file or directory。用户通过 Homebrew 安装本机 dsh 后即无法启动,且报错信息无法指向真实原因。

实现范围

  • 新增 platform/process_env.rs:login_shell_path()(zsh -lic 'printf %s "$PATH"',OnceLock 缓存)、augmented_path()、apply_augmented_path()。PATH 顺序为 登录 shell → 当前进程 → 可执行文件所在目录 → 各模块兜底目录,去重后写入子进程环境。
    • 带上「可执行文件所在目录」是为了覆盖 nvm、pnpm 等工具链安装形态:这类环境下 CLI 与解释器通常同处一个 bin 目录,只把可执行文件绝对路径找出来并不够。
  • 接入 dsh_process::launch_command 的 Auto / Bundled / External 三个分支;extra_bin_dirs 提升为 pub(crate) 供 dsh.rs 复用。
  • 同步修复同类缺陷:dsh_runtime_validate_external 版本探测、pi_web_process::launch_web、opencode_process::launch_web 与 validate_secure_version、codex_process::launch_app_server。
  • 不包含:运行时发现逻辑本身的重写;未改动前端代码。

验证

  • 相关包 type-check —— cargo check --lib 通过,仅存量 warning
  • 相关 lint —— CI 的 Rust 任务只运行 cargo test,未配置 clippy/fmt
  • 单元/组件测试 —— cargo test 396 passed / 0 failed / 4 ignored
  • E2E(不涉及前端关键路径)
  • 手工验证

验证命令与结果:

# 修复前:最小 PATH 下启动 dsh,复现 127
$ env -i HOME="$HOME" PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
    /opt/homebrew/bin/dsh web --host 127.0.0.1 --port 0 --no-open
env: node: No such file or directory      → exit 127

# 修复后:注入增强 PATH
$ env -i HOME="$HOME" PATH="/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin" \
    /opt/homebrew/bin/dsh web --host 127.0.0.1 --port 0 --no-open
dsh web: http://127.0.0.1:57846/?token=... → 正常监听回环端口

$ cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml
test result: ok. 396 passed; 0 failed; 4 ignored

新增测试覆盖:扩展目录保留、可执行文件所在目录注入、目录去重、PATH 确实写入子进程(platform::process_env 4 例),以及 dsh_process 中直指本缺陷的回归用例。

风险与兼容性

  • 注入的 PATH 只作用于小妍托管的子进程,不修改用户 shell、shell 配置或系统环境变量。
  • command.env("PATH", ...) 为覆盖写入,但增强结果包含原有 PATH,不会丢失既有可见性;顺序上登录 shell 优先,与用户在终端中执行 CLI 的解析结果一致。
  • login_shell_path() 首次调用会拉起一次登录 shell 并缓存,仅在首次启动某类助手时产生一次性开销;该 shell 调用失败时静默降级为当前 PATH 加兜底目录。
  • Windows 分支不受影响:login_shell_path() 返回 None,仍按原逻辑合并当前 PATH、APPDATA/npm 与兜底目录。
  • 无数据迁移;回滚只需还原本次提交,不涉及持久化格式变更。

自检

  • PR 聚焦单一主题,未夹带无关格式化或生成物
  • 未提交密钥、个人路径、真实研究数据或未经授权素材
  • 已补充必要测试、文档与 CHANGELOG
  • 已阅读 CONTRIBUTING.md 和 docs/development-principles.md

macOS 上由 Finder / Dock 启动的 GUI 进程只继承最小 PATH
(/usr/bin:/bin:/usr/sbin:/sbin)。代码助手 CLI 普遍以
#!/usr/bin/env node 这类 shebang 启动,此前只解决了“找到可执行文件”:
find_dsh 会遍历扩展候选目录,但 spawn 时仍原样继承最小 PATH,
导致解释器不可见,进程以 127 退出并报 env: node: No such file or directory。

新增 platform/process_env.rs,统一构造并注入增强 PATH:
登录 shell PATH(zsh -lic,OnceLock 缓存)→ 当前进程 PATH →
可执行文件所在目录 → 各模块兜底目录,去重后写入子进程环境。
带上可执行文件所在目录是为了覆盖 nvm、pnpm 等工具链安装形态,
这类环境下 CLI 与解释器通常同处一个 bin 目录。

接入范围:
- dsh_process::launch_command 的 Auto / Bundled / External 三个分支
- dsh_runtime_validate_external 的版本探测
- pi_web_process::launch_web、opencode_process::launch_web 与 validate_secure_version
- codex_process::launch_app_server

验证:最小 PATH 下执行 dsh web,修复前 exit=127 并输出
env: node: No such file or directory,修复后正常输出回环监听地址。
cargo check --lib 通过,新增 5 个测试全部通过。
@Yurken
Yurken merged commit 41706ab into master Sep 17, 2026
6 checks passed
@Yurken
Yurken deleted the codex/dsh-startup-path branch September 17, 2026 04:34
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