fix(install): install.sh 的 PATH 守卫问错问题,装完新终端仍找不到 botmux - #1129
Merged
Conversation
install.sh 写启动文件前有一道
case ":$PATH:" in *":$INSTALL_DIR:"*) : ;; # already on PATH
它问的是「执行安装那个进程的 PATH 里有没有 INSTALL_DIR」,而决定
`botmux` 能不能用的是「用户以后开的终端有没有」——那是启动文件的属性,
不是当前进程的属性。这与 #1117 在 npm 侧(scripts/postinstall-bin.mjs)
修掉的是同一个错,curl 侧当时没跟上。
两者何时会分叉:botmux 自己就制造这个场景。daemon 会把 ~/.botmux/bin
前置进它 spawn 的每个 CLI 会话的 PATH(5 处 prependBotmuxBin),所以
在 botmux 会话里跑这个安装器,就会命中 skip 分支——零文件、零提示、
exit 0,而新终端里 `botmux` 依然 command not found。而自 #1047 起
npm 包没有 bin 字段,那个 launcher 是唯一入口,PATH 没配就等于没装上。
改法:删掉这层外壳,让写启动文件无条件执行。不需要这道闸,因为
下面本来就有两层各自独立的幂等,且都不依赖当前 PATH:
- path_line_present():文件里已有的行不再追加
- 写出去的那行自带 case 守卫:重复 source 也不会把 PATH 撑大
原注释整段保留并改写为「为什么不能加这道闸」,与 postinstall-bin.mjs
里同款说明保持一致。
## 实测(隔离 HOME,四格 A/B)
| dir 不在 PATH | dir 已在 PATH
修前 | 写 2 个文件 | 写 0 个(exit 0,无任何提示)← bug
修后 | 写 2 个文件 | 写 2 个文件
修后两列一致 = PATH 不再影响结果,这正是要的性质。
## 新增回归测试 test/install-sh-path-entry.test.ts(8 用例)
抽出 install.sh 里真实的 PATH 段执行,而不是断言脚本文本——原代码
文本上完全合理,错的只是「预置 PATH 下的行为」,纯文本断言抓不到。
⚠️ harness 必须整段取到 EOF:第一版从 posix_line= 起取,导致把闸
重新加回去(就加在那行上面)时 8 个用例全绿——即对本 bug 完全失明,
已实测。现改为从最后一个 helper 之后一路取到文件尾。
另加 assertHarnessIsWellFormed:本文件的症状就是「零文件」,若抽取
失败也会产出零文件,两者无法区分,故先证明 harness 语法合法且含
真实逻辑再下结论。
反变异 6/6 全红:
M1 把 $PATH 闸加回去 → 2 failed(即本 bug)
M2 per-shell 分发恒走 .profile → 4 failed
M3 path_line_present 恒 false → 2 failed
M4 写出的行丢掉自带 case 守卫 → 1 failed
M5 bash 只写 .bashrc 不写登录文件 → 3 failed
M6 awk 整元素比对改前缀比对 → 1 failed
每次变异后立即 cp 还原并 cmp 校验。
## 影响面
只动 install.sh 的 PATH 段 + 新增一个测试文件,不含 src/ 变更,
不影响 npm/pnpm/bun 安装路径(那半边由 #1117/#1119/#1122 负责)、
也不影响任何平台 / CLI / 会话类型的运行时行为。
测试:新文件 8/8 绿;install-sh-musl-asset / install-path-entry /
npm-binary-distribution 并集 99 passed,其中 npm-binary-distribution
有 2 条失败——已在干净 origin/master 的独立 worktree 上同样跑出
`2 failed | 33 passed`,逐字相同,属既有失败,与本 PR 无关。
Owner
Author
自动评审的初步意见(最终以维护者审阅为准)方向认同,改动逻辑站得住:这道闸问的是「跑安装器那个进程」的 PATH,而决定 独立复核过的几点(不是读描述得出的):
两条建议(都不阻断合入):
另外供参考(属既有缺口,非本 PR 引入,不必在本 PR 处理):两个变异体在 以上为自动评审的初步意见,可能有误判,最终以维护者审阅为准。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
install.sh在写启动文件前有一道闸:它问的是「执行安装那个进程的 PATH 里有没有
INSTALL_DIR」,而决定botmux能不能用的是「用户以后开的终端有没有」——那是启动文件的属性,不是当前进程的属性。这与 #1117 在 npm 侧(
scripts/postinstall-bin.mjs)修掉的是同一个错,curl 侧当时没跟上。那边留了整段⚠️ DO NOT GATE THIS ON process.env.PATH的注释讲这件事。两者何时会分叉:botmux 自己就制造这个场景。 daemon 会把
~/.botmux/bin前置进它 spawn 的每个 CLI 会话的 PATH(5 处prependBotmuxBin)。所以在 botmux 会话里跑这个安装器 ⟹ 命中 skip 分支 ⟹ 零文件、零提示、exit 0,而新终端里botmux依然command not found。而自 #1047 起 npm 包没有bin字段,那个 launcher 是唯一入口,PATH 没配就等于没装上。改法
删掉这层外壳,让写启动文件无条件执行。不需要这道闸,因为下面本来就有两层各自独立的幂等,且都不依赖当前 PATH:
path_line_present()case守卫原注释整段保留并改写成「为什么不能加这道闸」,与
postinstall-bin.mjs里同款说明保持一致——下一个人想「顺手优化一下」时能看到理由。实测:四格 A/B(隔离 HOME)
修后两列一致 = PATH 不再影响结果,这正是要的性质。
新增回归测试
test/install-sh-path-entry.test.ts(8 用例)抽出 install.sh 里真实的 PATH 段执行,而不是断言脚本文本——原代码文本上完全合理,错的只是「预置 PATH 下的行为」,纯文本断言抓不到。做法沿用已有的
install-sh-musl-asset.test.ts。harness 起初从
posix_line=开始抽。把闸重新加回去(就加在那行上面,正是原 bug 的位置)时 —— 8 个用例全绿。因为那道闸根本没被抽进来。现改为从最后一个 helper 之后一路取到 EOF,任何位置的闸都在范围内。另加
assertHarnessIsWellFormed():本文件的症状就是「零文件」,而抽取失败也会产出零文件,两者无法区分(甚至会把结论反过来:buggy 分支看着像 PASS)。所以先证明 harness 语法合法、且真的含有 writer / 幂等检查 / per-shell 分发,再下结论。反变异 6/6 全红
$PATH闸加回去(即本 bug).profilepath_line_present恒 falsecase守卫.bashrc不写登录文件每次变异后立即
cp还原并cmp校验(restored ✓)。影响面
只动
install.sh的 PATH 段 + 新增一个测试文件,不含src/变更。不影响 npm / pnpm / bun 安装路径(那半边由 #1117 / #1119 / #1122 负责),也不影响任何平台 / CLI / 会话类型的运行时行为。测试
sh -n install.sh语法通过。install-sh-path-entry+install-sh-musl-asset+install-path-entry+npm-binary-distribution并集:99 passed。npm-binary-distribution有 2 条失败(THE bun/pnpm BUG: a global LAYOUT…/SAFETY: a LOCAL dependency install…)。已在干净origin/master的独立 worktree 上同样跑出2 failed | 33 passed,逐字相同 ⟹ 属既有失败,与本 PR 无关(本 PR 没碰postinstall-bin.mjs)。相关:#1117(npm 侧同款修复)· #1128(文档改推 curl 为默认安装方式,其中已把本问题写成「已知限制」,本 PR 合入后应把那段删掉)
🤖 Generated with Claude Code