install.ps1 在 Windows 下一键安装失败:① 脚本带 UTF-8 BOM ② 不传 -Version 时解析出的版本号是垃圾值
环境
- Windows / PowerShell 7.6.0-rc.1
- pnpm 10.30.3
- dsh-better-sidebar 目标版本 0.12.2
- 网络:中国大陆,pnpm 的 registry 指向
https://registry.npmmirror.com(脚本内 $REGISTRY 默认写死 https://registry.npmjs.org)
问题一:install.ps1 带 UTF-8 BOM,脚本自述的 irm | iex 一键安装无法使用
脚本头部注释里推荐的用法:
irm https://raw.githubusercontent.com/omdsh-dev/DSH-better-sidebar/main/scripts/install.ps1 | iex
实际执行报错:
#: The term '#' is not recognized as a name of a cmdlet, function, script file, or executable program.
param:
Line |
39 | param(
| ~~~~~
| The term 'param' is not recognized as a name of a cmdlet, function, script file, or executable program.
原因:irm 返回的字符串开头保留了 BOM(U+FEFF),iex 把它当成命令名,导致第一行注释未被识别为注释;连锁效应是第 39 行的 param( 不再是首条语句,整个参数块失效。
此时脚本仍会继续往下跑,最终拼出的命令行是:
[install] 执行 dsh plugin --profile web add dsh-better-sidebar@ False False ...
ERR_PNPM_FETCH_404 GET https://registry.npmmirror.com/False: Not Found - 404
pnpm 把 False 当成包名去装,404 失败。
改用 -OutFile 存盘后再 pwsh -File 执行,这两条解析错误消失(PowerShell 读取文件时会正确处理 BOM),说明问题确实出在 BOM 上。
建议:scripts/install.ps1 以 UTF-8 without BOM 保存并提交。同时建议在文档里把一键安装写成对 BOM 免疫的形式,例如:
& ([scriptblock]::Create(((irm '<url>') -replace '^\uFEFF','')))
问题二:不传 -Version 时,Resolve-Spec 会返回非版本号字符串
绕开 BOM 后(pwsh -File install.ps1,不带 -Version):
[install] 执行 dsh plugin --profile web add dsh-better-sidebar@npm help ...
ERR_PNPM_NO_MATCHING_VERSION No matching version found for dsh-better-sidebar@npm
$SPEC 被解析成了 npm help。相关代码(第 65–81 行):
function Resolve-Spec {
param([string]$Given)
if ([string]::IsNullOrWhiteSpace($Given) -or $Given -eq 'latest') {
$v = $null
foreach ($tool in @('npm', 'pnpm')) {
if (Get-Command $tool -ErrorAction SilentlyContinue) {
$v = (& $tool view $PKG version "--registry=$REGISTRY" 2>$null | Select-Object -Last 1)
if ($v) { break }
}
}
if ($v) { return ([string]$v).Trim() }
Warn '无法联网解析最新版本(npm/pnpm 查询失败),回退为 latest,由 pnpm 直接解析。'
...
核心问题:$v 只判断了非空,没有校验内容是不是版本号。当 npm view 因为网络原因失败、但仍有内容落到 stdout 时,这段垃圾值会被原样当作版本号拼进 add 命令。76–78 行准备好的「解析失败回退 latest」分支因此永远走不到 —— 而回退到 latest 本来是能装成功的。
(顺带一提:2>$null 是否在所有 npm/pnpm 失败路径上都能拦住输出,可能也值得一并确认;本机的表现是有内容漏进了 stdout。)
-Version 0.12.2 显式传入时一切正常,安装、bundle 注册、旧挂载行清理都成功:
[install] bundle 已注册:dsh.profile.bundles 包含 dsh-better-sidebar(下次启动自动挂载)
[install] 无旧手动挂载行,跳过
[install] 安装完成:dsh-better-sidebar@0.12.2
建议修复:
$out = (& $tool view $PKG version "--registry=$REGISTRY" 2>$null | Select-Object -Last 1)
if ($out -and ("$out".Trim() -match '^\d+\.\d+\.\d+')) { $v = "$out".Trim(); break }
另外建议 $REGISTRY 的默认值不要写死 registry.npmjs.org,改为跟随用户已配置的 registry(例如 npm config get registry),否则在使用镜像源的环境下这一步几乎必然失败。
备注(非 bug)
dsh plugin add 过程中出现的一大批 missing peer @deepseek-ai/dsh-* / react / @xterm/xterm 警告,理解上应由 DSH 宿主在运行时提供,不需要装进 profile —— 如果确实如此,建议在 README 里加一句说明,避免使用者照着 pnpm 的 "Peer dependencies that should be installed" 提示去手动安装而装出两份 React。
install.ps1 在 Windows 下一键安装失败:① 脚本带 UTF-8 BOM ② 不传
-Version时解析出的版本号是垃圾值环境
https://registry.npmmirror.com(脚本内$REGISTRY默认写死https://registry.npmjs.org)问题一:
install.ps1带 UTF-8 BOM,脚本自述的irm | iex一键安装无法使用脚本头部注释里推荐的用法:
实际执行报错:
原因:
irm返回的字符串开头保留了 BOM(U+FEFF),iex把它当成命令名,导致第一行注释未被识别为注释;连锁效应是第 39 行的param(不再是首条语句,整个参数块失效。此时脚本仍会继续往下跑,最终拼出的命令行是:
pnpm 把
False当成包名去装,404 失败。改用
-OutFile存盘后再pwsh -File执行,这两条解析错误消失(PowerShell 读取文件时会正确处理 BOM),说明问题确实出在 BOM 上。建议:
scripts/install.ps1以 UTF-8 without BOM 保存并提交。同时建议在文档里把一键安装写成对 BOM 免疫的形式,例如:问题二:不传
-Version时,Resolve-Spec会返回非版本号字符串绕开 BOM 后(
pwsh -File install.ps1,不带-Version):$SPEC被解析成了npm help。相关代码(第 65–81 行):核心问题:
$v只判断了非空,没有校验内容是不是版本号。当npm view因为网络原因失败、但仍有内容落到 stdout 时,这段垃圾值会被原样当作版本号拼进add命令。76–78 行准备好的「解析失败回退latest」分支因此永远走不到 —— 而回退到latest本来是能装成功的。(顺带一提:
2>$null是否在所有 npm/pnpm 失败路径上都能拦住输出,可能也值得一并确认;本机的表现是有内容漏进了 stdout。)-Version 0.12.2显式传入时一切正常,安装、bundle 注册、旧挂载行清理都成功:建议修复:
另外建议
$REGISTRY的默认值不要写死registry.npmjs.org,改为跟随用户已配置的 registry(例如npm config get registry),否则在使用镜像源的环境下这一步几乎必然失败。备注(非 bug)
dsh plugin add过程中出现的一大批missing peer @deepseek-ai/dsh-*/react/@xterm/xterm警告,理解上应由 DSH 宿主在运行时提供,不需要装进 profile —— 如果确实如此,建议在 README 里加一句说明,避免使用者照着 pnpm 的 "Peer dependencies that should be installed" 提示去手动安装而装出两份 React。