Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,13 @@
- **验证方式**:四条结构 contract(`include_str!` 断言源码里存在对应的 `configure_background_child` / `creation_flags`,沿用 `workspace_explorer/src/git/tests.rs` 风格)——`cargo test -p terminal --lib wsl_distributions`、`cargo test -p html-preview`、`cargo test -p workspace_explorer --lib backend`、`cargo test -p main --bin navop mcp_skill`;再跑受影响 crate 的 `cargo check --tests` 与 `cargo clippy --all-targets`(只比对改动文件是否有新增告警)。**macOS 上 `cfg(windows)` 分支根本不参与编译,本机无法验证「不闪窗」**,最终必须 Windows 实机启动一次确认。
- **适用范围**:`crates/terminal/src/wsl_distributions.rs`(启动期 WSL 识别,commit 57e31731b 引入的遗漏)、`crates/html-preview/src/browser.rs`(Windows 走 `cmd /C start`)、`crates/workspace_explorer/src/backend.rs`(容器后端 `docker exec`)、`main/src/settings/mcp_skill_install.rs`(`npx`/`node` 启动器),以及所有新增后台外部命令调用点;`workspace_explorer/src/git.rs`、`core/cloud_sync/personal/git_store.rs`、`extension-host/src/process.rs`、`remote_desktop/src/backends/rdp/transport.rs`、`remote_file_editor/src/external_launcher.rs`、`main/src/file_association.rs` 是已按此约定收口的正确样例。

- **标题**:GUI 进程 spawn `npx` 必须先解析真实路径、再把程序目录补进子进程 PATH,否则设置页装 Skill 报 `os error 2`
- **触发信号**:macOS 上从 Finder / Dock 启动的 Navop 点「安装 Navop Skill」失败,提示 `No such file or directory (os error 2)`;同一台机器在终端里跑同一条命令却成功。也适用于任何在 GUI 进程里 `Command::new("npx")` / `"node"` / `"pnpm"` 的后台调用。
- **根因 / 约束**:GUI 进程继承的 PATH 只有 `/usr/bin:/bin:/usr/sbin:/sbin`(`ps eww <pid>` 可证),而 npx 一般只装在 `/opt/homebrew/bin`。**只把它解析成绝对路径还不够**:npx 的 shebang 是 `#!/usr/bin/env node`,子进程 PATH 仍缺 `/opt/homebrew/bin` 时 `env` 找不到 node(复现:`env -i PATH=/usr/bin:/bin /opt/homebrew/bin/npx --version` → `env: node: No such file or directory`)。裸 `Command::new("npx")` 的失败信息是 Rust 的 `No such file or directory (os error 2)`,别和 Node CLI 自己吐的 `ENOENT: no such file or directory, open ...` 混淆。
- **正确做法**:别在这里写裸 `Command::new(launcher)`,用 `process_util::build_command(name, &args)`:它按「环境 PATH → 系统/家目录兜底目录(`/opt/homebrew/bin`、`/usr/local/bin`、`~/.local/bin`、nvm/fnm/volta/bun/pnpm 的 bin)→ 版本号降序」解析并校验可执行位,再把程序所在目录前置进子进程 PATH,之后照常 `configure_background_child`。持久化到 Codex / Claude 配置里的 `command = "npx"` **仍保持可移植的裸名**(`f821ed1b3` 的既有取舍),不要改成绝对路径。设置页的运行时状态也要用 `process_util::resolve_program` 真实探测,不要再无条件写「已就绪」。
- **验证方式**:`cargo test -p process-util`(PATH 优先、兜底目录、跳过不可执行、子进程 PATH 去重)、`cargo test -p main mcp_skill_install`(`skill_install_resolves_the_launcher_before_spawning` 源码契约);GUI 等价验证是把 PATH 设成 `/usr/bin:/bin:/usr/sbin:/sbin` 后跑解析并执行 `npx --version`。Windows 只有 `.cmd`/`.bat` 走 `cmd /C` 这一支,需实机确认。
- **适用范围**:`crates/process-util/src/program.rs`、`main/src/settings/mcp_skill_install.rs`、`main/src/settings/mcp_helper_install.rs`,以及任何在 GUI 进程里 spawn 包管理器启动器的调用点。

- **标题**:macOS 弹窗「关闭即复用」必须同时结束业务会话,并用计数把受控保留和泄漏分开
- **触发信号**:把弹窗关闭从 `remove_window()` 改成隐藏复用(`orderOut`)后,内存采样里 `GPUIView`/`CAMetalLayer` 只增不减;或反过来为了「彻底释放」把复用窗口改回销毁,于是 Touch Bar 机型又出现关闭闪退(issue #262)。
- **根因 / 约束**:隐藏的窗口仍然活在 GPUI 内容树里,而内容树**强引用** `PopupWindowContent.view`;复用注册表只存 `WeakEntity`,管不到这份强引用。所以「只隐藏不卸载」=上一次的业务 view(含数据、任务句柄)被一直扣着,用户不再打开那类窗口时就是纯泄漏;而销毁原生窗口又会触发 AppKit Touch Bar 观察者向已 dealloc 的对象注销并抛 ObjC 异常。两件事必须拆开:**原生窗口**隐藏复用(受控保留,上限=复用键数量 + 一次性弹窗的停放次数),**业务会话**关闭即结束。
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/process-util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition.workspace = true
publish.workspace = true

[dependencies]
dirs = { workspace = true }
tokio = { workspace = true, features = ["process"] }

[lints]
Expand Down
4 changes: 4 additions & 0 deletions crates/process-util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
mod program;

pub use program::{build_command, child_path_with_program_dir, resolve_program};

pub const CREATE_NO_WINDOW: u32 = 0x0800_0000;

#[must_use]
Expand Down
Loading
Loading