# dsh-deliverables-accordion > **English**: [README.en.md](README.en.md) | **中文**: [README.md](README.md) DSH Web GUI「产物」行的**手风琴插件**(标准 Cordis 外部插件包):顶替 shipped 产物行, 默认折叠、点击展开后逐文件一行(类型徽标 / filename / 相对路径 / +N/-M),每行有「审查 / 打开」。 审查弹出模态框,从**宿主会话日志**取该文件该轮每次变更的完整 old→new 片段做 git 风格行级 diff (无字符截断,历史轮同样完整)。 ![产物手风琴](1.png) *产物手风琴(默认折叠的产物行,点击展开逐文件清单)* ![审查模态框展开](2.png) *点击「审查」后:变更块手风琴展开,git 风格行级 diff(全文写入直接展示完整内容)* ## 形态 - **Host 半**(`src/index.ts`):注册 `/deliverables-accordion/*` HTTP 路由;从 `ctx.sessions` 读取会话原始事件日志,按轮折叠产物索引、按文件还原完整变更流。 - **Client 半**(`src/client/`):注册 `conversation.chat.turnTail` 链项(priority -10,先于 shipped),经 `uiConversation` 折叠**轻量索引**(只含 seq/callId/path/op/行统计,**不含正文**); 审查时 `fetch` host 路由取完整原文。打开文件走 owner `openFile`(Host 能力)。 - 文案走 zh/en 字典;主题用 `--dsw-alias-*` token + 回退;样式以 diff 14.5px 为基准。 ## 安装(进 web profile) ```bash pnpm build # 产出 lib/index.js + lib/client.js pnpm pack # 产出 dsh-deliverables-accordion-0.1.0.tgz dsh plugin --profile web add ./dsh-deliverables-accordion-0.1.0.tgz # 重启 dsh web 后生效(浏览器半由 dsh.client manifest 发现) ``` 等效手工接入(照 dsh-mcp-settings / dsh-commandcode-usage 的现成模式): 把 tgz 作为依赖加进 `~/.dsh/profiles/web/package.json` 的 `dsh.profile.bundles` 与本包 `cordis.patch.yml`(insert `deliverables-accordion` 行)。 ## 开发 ```bash pnpm install pnpm build # tsdown 双产物 npx tsc --noEmit # 类型检查 ``` ## 数据契约(无废弃字段) - 会话 turn data(key `deliverablesAccordion`)**只发布轻量索引**: `{ files: [{ path, ops: [{ seq, callId, op, added, deleted, applied? }] }] }` —— **没有 oldText/newText/truncated**,正文一律由审查时 host 从会话日志取完整原文。 - shipped 的 `deliverables` key 不触碰;无产物轮 select 返回 null,shipped 行(或空)自然兜底。 - +N/-M 与消息流一致:逐 applied hunk 数 oldText/newText 的文本行(含上下文,同一 hunk 的 上下文行在两侧各计一次,等于 shipped DiffBlock 的 diffTotals 口径)。 - **正文权威来自宿主 `tool/result` 的 `meta.diffs`**(write/edit 每次成功都携带逐 hunk 的 old/new 片段,±3 上下文行)。host fold 与客户端索引在 result 到达时解析它:有旧侧 → 该变更 标 `applied`(真实变更区,审查渲染行级 diff,统计含删除侧);无 `meta.diffs`(真正的整文件 新建、或 identical 覆盖写)→ 整文新增兜底(审查标「全文写入」)。 - 徽标:`create`=新建;`write` 且带 applied 旧侧(宿主确实覆盖了已有内容)=覆盖;`write` 无旧侧时看本会话更早是否成功写过该路径(严格早于本次的首个 result,变更不把自己算作 先例),写过=覆盖,否则=新建;其余=修改。 ## 已知限制 - 覆盖未知旧内容的整文件 `write`,若宿主 `meta.diffs` 缺失(如 identical 重写、或第三方实现 不带结果元数据),没有可对比的旧快照,无删除侧;审查直接展示完整新内容并标「全文写入」。 - 手风琴徽标的 新建/覆盖 区分依赖会话内可观测的变更序列(跨轮记忆在页面生命周期内有效), host 审查对该路径真正首次写入(宿主的 applied 旧侧)才是权威。