1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
+ ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
120 lines
10 KiB
Markdown
120 lines
10 KiB
Markdown
# 89-对话内文件预览——采纳官方推荐库现成插件(2026-09-14 落地)
|
||
|
||
- 日期:2026-09-14 | 状态:🔄 **进行中**(L2 机制级已验证;L5 用户实测待做)
|
||
- 触发:用户原话 ——「**这个 univer 太重了,有没有别的方式可以做个插件让用户点击对话中的文件,可以在会话栏旁边的窗口中打开展示**」→ 追加「**需要查官方推荐库是否有类似插件,是重新开发还是改造**」
|
||
|
||
> **TL;DR**
|
||
> **不重新开发、也不改造 univer** —— 官方推荐库里有现成的,且有一个与我们的 dsh 版本**精确匹配**:
|
||
> **`@softspark/[email protected]`(tgz 65 KB = univer 的 1/650)**。
|
||
> 它**包住官方的 `remote.session.openWorkspacePath`**,接管"对话里点文件"的手势,弹只读预览弹窗;卸载即恢复原生行为。
|
||
> 已导入候选池(**兼容预检 `level: ok`,无需声明信任**)→ 在 guest 启用 → 实例重启探活 `success`;
|
||
> 页面客户端插件 **46 → 47**,其 `inject` **4 个全部可满足**(避开"静默挂死"老坑)。
|
||
|
||
---
|
||
|
||
## 背景与动机
|
||
|
||
- univer 插件(`dsh-univer-office`)**重**:tgz 42 MB、网关进程常驻 ~350 MB、还带原生绑定(glibc 门禁)。
|
||
- 用户要的是**轻量替代**:**点对话里的文件 → 在会话栏旁边的窗口展示**。
|
||
- 用户明确要求先查**官方推荐库**再决定"重新开发还是改造"(对应 `dsh-decision-method` 的 **U2 能扩展就不新建**)。
|
||
|
||
## 「官方推荐库」是什么(本次查清)
|
||
|
||
| 来源 | 说明 |
|
||
|---|---|
|
||
| **`Awesome-DeepSeek-Harness-Plugins`**(`github.com/web-casa/Awesome-DeepSeek-Harness-Plugins`) | 社区整理的官方索引,数据源 = **cordis.run 插件索引**,自称 **331 个插件**(分 5 类:Dev Assistants 78 / Workflow 37 / Themes&UI 90 / Data Integration 8 / Productivity 118) |
|
||
| **npm** `keywords:dsh-plugin` 搜索 + 具体包元数据 | 取真名、版本、`dsh` 声明、依赖范围、体积 |
|
||
| ⚠️ `cordis.run/data/plugins.json` | **直连 403**(需要浏览器的 UA/上下文)⇒ 走 README 与 npm 两条路 |
|
||
|
||
**dsh 客户端能力现状(本次实测)**:
|
||
- **没有官方 viewer/preview 注册点**(全客户端包 grep 无 `registerViewer` 类 API);
|
||
- 但布局里有 **`details` 列**(会话栏旁边、可拖宽)与 **`shell.overlay`** 浮层;
|
||
- 官方 **`dsh-client-ui-deliverables`** 已把「本轮产出文件」渲染成**可点击 chips**(点击走 chat 视图的 `openFile`,该 opener 由宿主能力提供、在无桌面宿主的实例里基本是空转);
|
||
- 平台侧已有 **`GET /api/fs/download?path=`**(`requireAuth` + 限定调用者根内 + 大小限制)且**跨域放行**
|
||
(实测 `access-control-allow-origin: https://guest.alotbuy.com` + `allow-credentials: true` ⇒ 200、536 KB 真读到)。
|
||
|
||
## 方案对比(**含"不做"**)
|
||
|
||
| 方案 | 内容 | 判定 | 理由 |
|
||
|---|---|---|---|
|
||
| **A 复用现成插件** | 从官方推荐库挑一个,走既有投放通道 | ✅ **采纳** | 零开发、可回滚(卸载即恢复原生)、体积最小 |
|
||
| B 自己写轻量插件 | 纯客户端 + `shell.overlay` 右侧抽屉 + 拦截官方 chips 点击 | ❌ 否决 | 需复刻「产出文件」解析逻辑或做 DOM 拦截(耦合官方类名);**有现成的就不该造**(U2) |
|
||
| C 改造 univer | 让它变轻 | ❌ 否决 | 42 MB 与网关常驻是它的**架构**(协作网关 + 原生绑定),改造=重写 |
|
||
| D 改造官方 deliverables / sidebar | 直接改官方包 | ⛔ **不可** | **R2 不改官方 dsh 主程序与缓存** |
|
||
| **不做**(保持现状) | 用户只能下载后本地打开 | ❌ 否决 | 用户明确的痛点在"会话里看" |
|
||
|
||
## 候选体检(**判据三关**,可复用)
|
||
|
||
> **闸 1** 依赖的官方包**存在**吗(不存在的包 ⇒ 客户端 fiber **静默挂死**)|
|
||
> **闸 2** 有没有依赖**被平台角色补丁禁用**的官方包(`dsh-client-ui-settings-models` / `-settings-plugins` / `-settings-plugin-inventory` / `-cordis` / `dsh-client-hmr` / `dsh-host-directory-picker-auto`)(同上,静默挂死)|
|
||
> **闸 3** `peerDependencies` 的 `@deepseek-ai/*` 版本范围**是否覆盖我们的 dsh 版本**(**0.1.2-rc.1**)
|
||
|
||
| 候选 | 体积 | 判定 | 依据 |
|
||
|---|---|---|---|
|
||
| ✅ **`@softspark/dsh-file-preview` v2.0.0** | **65 KB** | **采纳** | peer **精确锁 `0.1.2-rc.1`(=本站版本)**;inject = `client-locale` / `api-remotes` / `api-session-controller` / `client-ui-renderer` **全在且未被禁**;`exports["./client"].default` 形态(被 dsh 接受);读文件走**官方 host Remote seam**;patch 自述"包住 `remote.session.openWorkspacePath` 接管对话文件打开手势,移除即恢复原生" |
|
||
| ❌ `dsh-file-viewer` v0.3.5 | 5.7 MB | 否决 | inject 含 **`@deepseek-ai/dsh-client-runtime`(本站不存在)** ⇒ 静默挂死 |
|
||
| ❌ `@deepseek-ai/dsh-client-ui-sidebar-documentpreview` | 6.8 MB | 否决 | 面向 **0.1.5** 系(依赖 `dsh-client-ui-sidebar-right`,本站只有 `-ui-sidebar`)⇒ 版本不匹配;且 **R1 不升 dsh** |
|
||
| ❌ `dsh-file-review` v0.8.1 | 1.5 MB | 否决 | inject 含 **`ui-settings-plugins`(被平台角色补丁禁)** ⇒ 静默挂死 |
|
||
| ❌ `dsh-at-file` / `@linxin666/dsh-client-ui-aionui-panel` | — | 否决 | 同样注入不存在的 `dsh-client-runtime` |
|
||
| ❌ `dsh-local-filetree` / `dsh-split-panes` | — | 不可得 | npm 无此名(README 未给包名)⇒ 需再溯源 |
|
||
| ⏸ `dsh-better-sidebar` + `@huanlin/…-office` | 14 MB + 22 MB | 备选 | 功能最强(VSCode 式右栏 + Office 预览),但**合计 ~36 MB**、30 依赖,且依赖 `dsh-client-ui-sidebar-right`(本站无)⇒ 与"轻量"诉求相悖 |
|
||
|
||
## 实现
|
||
|
||
1. `curl` 取 tgz(`https://registry.npmjs.org/@softspark/dsh-file-preview/-/dsh-file-preview-2.0.0.tgz`,65 247 B)→ scp 到服务器;
|
||
2. admin `POST /api/plugins/business`(base64 上传 + 安全/兼容预检)⇒
|
||
`{"ok":true, "version":"2.0.0", "compat":{"level":"ok","findings":[],"platformPkgs":223}, "trustedOverride":false}`
|
||
—— **预检全过,未使用 trust override** ✓(warning 有 `vm-eval`(打包产物里的动态求值)与 `network-egress`(README 链接),**非阻塞**);
|
||
3. `POST /api/plugins/mine/apply`(guest 启用)⇒ 任务 `success / 完成`(平台自动重启实例 + 探活);
|
||
4. 实装路径:`…/profiles/web/node_modules/@softspark/dsh-file-preview` ✓。
|
||
|
||
## 验证记录
|
||
|
||
| 级别 | 手段 | 结果 |
|
||
|---|---|---|
|
||
| L2 机制 | 实装存在性 | ✅ `node_modules/@softspark/dsh-file-preview` |
|
||
| L2 机制 | 实例页面 `__DSH_BOOT__` 清单 | ✅ 客户端插件 **46 → 47**;`@softspark/dsh-file-preview` 行 inject 4 个 **差集为空**(无可满足性问题) |
|
||
| L2 机制 | 平台侧预检 | ✅ `compat.level = ok`(判据 A/B 均过) |
|
||
| **L5 用户实测** | 硬刷新后**点击对话里的文件** | ⏳ **待用户确认**(本机无 Chromium,渲染类只能到此) |
|
||
|
||
## 事故 / 踩坑记录
|
||
|
||
- **`cordis.run/data/plugins.json` 直连 403** ⇒ 官方索引要走 README / npm 两条替代路径。
|
||
- **npm 包名不等于清单里的短名**:`dsh-local-filetree` / `dsh-split-panes` 在 npm 无此名(`dsh-local-filetree` 疑似本地/未发布)。
|
||
- **本机 shell 丢 PATH**:`rm`/`cat` 变 shim 报错、`curl "$(cat f)"` 空参数 ⇒ 每次先 export PortableGit 的 `usr/bin`+`mingw64/bin`。
|
||
- **Windows python 与 git-bash 的 `/tmp` 不是同一目录** ⇒ 两边传文件要统一用 `D:/...` 或在同一侧读写。
|
||
|
||
## 回滚 / 注意
|
||
|
||
- **回滚 = 在功能管理里停用该插件**(`mine/apply` 传 `enabled:false`)⇒ 平台 `pnpm remove` + 重启;**卸载即恢复原生文件打开行为**(patch 自述)。
|
||
- 与 univer **并存无冲突**(两者入口不同:univer 管 `.univer` 的协作预览,本插件管"对话里的文件"只读预览)。
|
||
- ⚠️ 第三方插件升级前**仍要过三关**(见上)——尤其别让它新版本引入 `dsh-client-runtime` 之类不存在的包。
|
||
- 候选池里新增了 `@softspark/[email protected]`(id 即包名)。
|
||
|
||
---
|
||
|
||
## 追加(2026-09-14 14:xx · **能力边界实测 + 三条后续建议的逐条处置**)
|
||
|
||
> 触发:用户「**按照你的建议处理**」。
|
||
|
||
### 一、该插件的能力边界(读包内 `lib/client.js` 的分派表实测)
|
||
|
||
| 类型 | 支持 | 渲染方式 |
|
||
|---|---|---|
|
||
| **文本类**(`md` `markdown` `txt` `log` `json` `yaml` `yml` `csv` `js` `ts` `tsx` `jsx` `py` `sh` `sql` `html` `css` `xml`) | ✅ | `kind: text` / `html`(**sanitize** 后渲染) |
|
||
| **图片**(`png` `jpg` `jpeg` `gif` `webp` `svg`) | ✅ | `kind: image` / `svg`(base64 内联) |
|
||
| **PDF** | ✅ | `kind: pdf` |
|
||
| **`xlsx` / `docx` / `pptx` / `.univer`** | ❌ | 命中 `unsupported`(有兜底提示);另有 **「too large」大小上限**(阈值写在代码里,未命名常量) |
|
||
|
||
- host 半边(`host.js` 15 KB)职责 = **会话授权 + 只读工作区文件**(`workspace` / `path.resolve` / `base64`)⇒ 与平台 `fs-guard` 同思路,**权限收窄** ✓。
|
||
|
||
### 二、三条建议的处置
|
||
|
||
| 建议 | 处置 | 理由 |
|
||
|---|---|---|
|
||
| ① L5(用户硬刷新后点对话里的文件) | ⏳ **归用户** | 本机无 Chromium,渲染类只能到此(`dsh-decision-method` §4.3 L5 口径) |
|
||
| ② Office 预览:装 36 MB 组合 **或** 让 AI 出 HTML | **两条都不做 —— 改走已有能力** | 用户早上问的"xlsx 能不能在会话里看",**答案已从「不能」变成「可以」**:`univer_import` 自 **0.2.28**(本日 §八 接通 glibc 2.35)起可用 ⇒ 导进 `.univer` 即在线看;要轻量则让 AI 出 `csv`/`html`。**无需再装任何东西** |
|
||
| ③ **停用 univer 省内存**(我上一条的💡建议) | **❌ 我自己否决**(记录在案) | 它承载用户**明说的核心用法** ——「AI 生成 md/doc/excel + Univer 在线看」;而"太重"的痛点已由本插件覆盖,且 univer 网关是**按需启动 + 空闲自停**(常驻成本主要就是 42 MB 磁盘)。⇒ **要停的前置动作** = 先把 `office-file-generation` 技能迁出 univer(改由独立载体承载),**之后**才可安全停用;该迁移等用户明确说"停"再做 |
|
||
|
||
> 📌 两者定位互补,**并存**:本插件管「对话里任意文件 → 只读预览」(文本/图片/PDF);univer 管「Office 双向 + `.univer` 协作预览/编辑」。
|