# Pi / DSH：可连续复用的 SearchBoost 升级

这里升级的是 **SearchBoost 在 Pi/DSH 中的集成**，不升级宿主 CLI 本身。

## 用户入口（beta.7 起）

```bash
npm install -g search-boost@latest --prefer-online  # 用户更新软件包；预发布显式用 @beta
search-boost                         # 管理 Agent 接入 → 刷新已有接入 → 选范围
search-boost refresh --dry-run
search-boost refresh -y              # 全部已有接入
search-boost refresh --workspace /path/to/project -y
```

刷新只使用当前持久安装的包，不查询 npm 最新版本、不自动更新 SearchBoost，不更新宿主 CLI。临时 npx 路径不能成为持久接入目标。`upgrade` / `--sync-only` 已移除。

旧 Pi/DSH 适配器来源迁移属于接入刷新；`migrate` 仅服务全局 `search-boost-mcp` npm 包更名，见[迁移说明](migration.md)。TUI 可选择精确 scope/profile；取消勾选不卸载，之后新发现的目标不会扩大选择。未选宿主的发现错误显示为跳过，不使已选且成功的范围失败；已选目标失效或真实执行失败仍阻塞。成功后重启/重新加载宿主；不要将宿主更新 npm 扩展当作本地资产也已同步的证据。

Grok 原生插件是单独可选项。原生更新后缓存仍不一致时，默认明确失败；完全退出 Grok后，可以单独确认 `--keep-data` / `--trust` 重建。CLI 显式同意为 `search-boost refresh -y --repair-grok-cache`，`-y` 本身不授予信任或重建同意。禁用插件不重装、不启用；不同来源、无法验证的仓库身份、共享仓库插件或危险别名拒绝自动重建。重建先验证源、绑定确认时的指纹，再验移除与新缓存；失败后报告实际阶段，不宣称回滚。旧名称数据保留原址，不保证自动迁移复用。刷新不会安装已不存在的插件，需审核源后通过安装入口重新接入。

## 共用流程

1. `lib/upgrade/index.mjs` 从当前软件包发现已有接入、按用户选择过滤，使用锁、备份、事务与载荷验收刷新；记录 `state/last-refresh.json`，部分成功不会显示为全部成功。
2. `lib/package-identity.mjs` 统一识别来源：npm/git 名称、本地包根目录、manifest 声明的 Pi extension、相对路径、file URL、受管 shim。版本不参与身份匹配；最近的外部 package.json 是边界，不能因为上层目录属于 SearchBoost 就接管用户扩展。
3. `lib/upgrade/integrations.mjs` 读取实际注册、校验目标包、拒绝降级，备份后更新；不触碰凭据、权限、用户模型配置。
4. 成功写入的准确路径与版本保存在 `~/.search-boost/state/package-sources.json`（支持 `SEARCH_BOOST_HOME`）。下一次旧目录失效时，只按**相同作用域、相同路径**恢复身份，不按文件名猜测。
5. 只有仍存在的宿主注册会成为升级目标。记录不能使已经卸载的集成重新出现；已有外部包/用户文件也不能被记录强行认领。

来源记录采用版本化 schema 和原子写入，并纳入注册事务的备份/恢复。全局 npm 更名另会记录已验证的旧包根目录/扩展入口，因此即使 migrate 先删除了全局旧包，后续 TUI 刷新 仍可识别其本地注册；migrate 本身不改 agent 配置。损坏或不支持的 schema 会明确报错，而不是猜测内容。已有安装在首次成功同步后获得记录；在此之前已经删除、且没有其他归属证据的任意本地路径不能安全自动认领。

## Pi

- 按用户和项目 scope 处理 `packages`、`extensions`、受管 shim，以及可证实归属的旧手工拷贝。
- 直接登记 `adapters/pi/index.js` 后，下次仍能找到包根目录，不依赖当前进程的安装路径。
- 保留对象形式的资源过滤、`autoload`、`[]` 禁用和直接 extension 的精确 include/exclude 前缀。冲突的双重注册会阻止升级，不擅自选一份启用。
- 检查实际来源版本，而不是用无关的 npm 缓存版本替代当前生效来源。受管目录被删除后仍可用记录中的版本拒绝降级。
- 从目标发行目录复制拥有标记的 agent/prompt 模板；用户自有文件不覆盖。手工目录整体归档到备份中，不删除其中用户添加的文件。
- 来源解析同时供状态检测、安装去重和卸载使用，升级后不会失去管理能力。

Pi 来源、作用域和过滤规则参考本机所装 Pi 的 `docs/packages.md`、`docs/settings.md`；不要依赖某个固定 CLI 版本的默认更新行为。

## DSH

逐一处理已登记 SearchBoost 的 profile，与 Install 共用包来源和启动逻辑。**Desktop 的保留 `desktop` profile 始终使用桌面版 bundled command**：先启动应用初始化，再完全退出后操作；缺失命令或应用锁时报告阻塞，不回退到 npm DSH。本地持久安装以绝对包路径复用，更新保留原来的启用/禁用选择；其他 CLI profiles 保持以下行为。详见 [Desktop 接入说明](dsh-desktop.md)。

CLI 源码 checkout 使用 `dsh plugin --profile <name> add <目标目录>`；npm 发布安装使用 `add search-boost@<版本>`，不把全局安装或 npx 缓存目录写成本地链接。缺少全局 `dsh` 或 `pnpm` 时，通过 `npm exec` 临时提供缺失命令，无需全局安装宿主。随后验证：

- profile manifest 的依赖来源切换到了目标目录或指定 npm 版本（允许 pnpm 保存的 `^` / `~` 前缀）；
- 源码链接的真实解析位置指向目标目录，而不是同版本旧副本；npm 安装的实际载荷版本必须与指定版本完全一致；
- 包名、版本以及必需 adapter 文件完整；
- bundle 顺序和原来的启用/禁用选择保留；
- 旧依赖清理后再次验证来源与载荷，不能只相信子进程退出码。

DSH 不一定会重新启用已经安装但禁用的 bundle；这不是失败。升级不以“出现在启用列表里”作为必要条件，也不会替用户启用它。

配置文件（含 `pnpm-workspace.yaml`）可回滚，包管理器对 `node_modules` 的副作用不能假装完全事务化。旧依赖清理发生在新注册验证通过之后；清理失败时保留新注册，报告部分失败及备份位置。解决阻塞后重跑相同命令。

宿主命令契约：[DSH CLI reference](https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/cli/reference/README.md)。

## 回归门禁

```bash
npm run test:refresh
```

包括旧包迁移、全局 npm 接管，以及 `scripts/test-host-upgrade.mjs`：

- 不使用仓库当前版本号作为唯一 fixture；模拟 `1.0.0 → 2.0.0 → 3.0.0`。
- 三个不同安装目录；删除所有旧目录后，用新进程验证下一次仍能发现注册。
- Pi package、直接路径、相对路径、file URL、排除前缀、shim、手工目录；DSH 启用和禁用 profile。
- 新进程实际 import fixture adapter，确认加载版本；不仅断言配置里出现新字符串。
- 同版本重试、dry-run、防降级、包管理器假成功、同版本错误链接、部分失败恢复、外部文件保护和卸载后不复活。

`scripts/test-dsh-desktop.mjs` 覆盖 Desktop / CLI 分别安装和删除、Desktop 更新和旧名迁移、禁用状态、缺失命令/应用锁阻塞、dry-run、失败回滚及诊断输出不泄密。绝对 Desktop 命令和 profile 全部位于测试目录，不操作真实桌面宿主。

`scripts/test-dsh-upgrade.mjs` 另外通过真实子进程启动器覆盖全局命令齐全、仅 npm、缺少 pnpm、缺少 dsh 四种环境，分别验证 checkout 和 npm 包来源；同时检查禁用状态、同版本重试、dry-run、错误版本/缺失文件及失败回滚。命令端点使用隔离 fixture，不下载真实 DSH。

`npm run test:isolation` 为全部自动测试提供模拟用户 HOME、重定位状态目录与假凭据，验证测试不会修改继承的配置、接入记录或源码树；`test:install` 执行其中的安装子集。所有入口统一使用 `scripts/isolate-tests.mjs`，详见[测试隔离说明](test-isolation.md)。真实项目目录不可用时仍阻止升级完成，不自动删除失效记录。

这些测试不证明用户机器上真实 Pi/DSH 已完成重启或加载；宿主行为由隔离替身模拟，全局 npm 迁移另通过本地 fixture registry 执行真实 npm。
