Skip to main content
C

dsh-better-file-viewer

chanyuenpang/dsh-better-file-viewer

An independent file session view for DSH, with tree and column navigation, image galleries, JSON inspection, and document previews without replacing the original sidebar.

Install

dsh plugin --profile web add github:chanyuenpang/dsh-better-file-viewer

README

Better file viewer

独立的 DSH「文件」会话视图。新增会话视图,不改动、接管或替换原侧栏。

安装(无需克隆源码)

适配基线:DSH Desktop/Web 0.2.2-rc.1。在 DSH Desktop 的插件管理器中选择安装,输入预构建包地址:

https://github.com/chanyuenpang/dsh-better-file-viewer/releases/download/v0.1.12/dsh-better-file-viewer-0.1.12.tgz

普通 Web profile 可使用:

dsh plugin --profile web add https://github.com/chanyuenpang/dsh-better-file-viewer/releases/download/v0.1.12/dsh-better-file-viewer-0.1.12.tgz

安装包已包含浏览器构建产物,无需本地构建或手动复制文件。插件市场条目正在提交;收录后可搜索 dsh-better-file-viewer。是否需要刷新或重启以插件管理器的结果为准,不会自动重启 DSH。

Office 预览依赖宿主的 officeToPdf 服务;本插件不安装 Office 转换运行时。不支持的宿主版本未经过兼容性验证。

功能

  • 文件导航与预览同屏,可放在左、右、上、下;鼠标拖动或键盘方向键调整分隔。左右采用文件树,上下采用横向层级分栏(一级一列、各列独立滚动),降低目录导航的竖直高度需求。
  • 左右树中,点击目录名称可展开/收起并浏览该目录图片;箭头也可展开/收起。层级分栏中点击文件夹进入下一列,点击已展开的文件夹或列标题可收起后续层级。
  • 空目录及没有图片的目录,预览内容区留白,不显示“空文件夹/没有图片”或零图片标题;读取中、失败和目录截断仍有明确反馈。
  • 顶部仅保留一条紧凑图标栏:布局入口显示方向图标,点击仍使用原生选择器;文件夹图标切换目录显示。回根、刷新、返回目录及图片翻页都有图标、tooltip和可访问名称,不再重复显示完整目录/路径文字行。
  • 文件树、层级分栏和图片卡片名称前有类型图标;文件夹区分展开/收起,未知文件使用通用图标。
  • 目录图片按可见区域加载缩略图;点击图片进入独立预览,可前后浏览、返回目录。先点击图片/图片区获得焦点,Ctrl + 加号(或Ctrl+=)/减号调整大小:目录中改变缩略图尺寸,单张图片中改变图片缩放。也支持鼠标悬停图片区时按住Ctrl滚轮:向上放大、向下缩小,无需先点击。不增加工具栏按钮。
  • 非 JSON 文件使用独立 fork 的官方预览:文本、Markdown、代码、图片、HTML、PDF、Excel/CSV/TSV、Office 转 PDF。格式支持和安全策略继承固定版本实现。
  • JSON 使用 super-json-editor 的结构导航,默认只读、无 Raw 编辑;按用户最新要求完整保留默认 object/表格/控件/配色/装饰,仅隔离样式作用域和适配预览容器尺寸。
  • 四种布局均限制在当前会话视图可用区域内:文件树和预览各自滚动,外层不共同滚动。只在文件视图隐藏聊天输入区,保持编辑器挂载和草稿不变。
  • 优先消费原生发给 better-files 的 viewRequest。对已切换文件 tab、却未传入定位请求的客户端,增加只观察可信本地文件点击的短期地址交接:不阻止或替换原导航,同一会话及 Conversation occurrence 的文件视图挂载后取回地址。0.1.4 的真实点击已由用户确认可用,运行时也记录到目标请求消费、正确选中文件及官方预览资源地址。
  • 支持中英文,外层文件视图使用 DSH 主题;SJE 按用户要求保留原默认配色。布局方向是插件自己的浏览器偏好。

入口:有内容的会话顶部,与「聊天 / 轨迹 / 上下文」同级的「文件」。窄窗口可能收进官方的更多菜单;空白会话是否显示视图导航遵循官方会话页。

边界

  • 只读:不保存、重命名、删除或新建文件。不注册模型工具或新的 Host 文件 API。
  • 文件根目录取自当前会话 cwd。目录限制、文件权限和大小上限由 DSH 文件服务执行。
  • 缩略图最多四个并发,单张 8 MiB;更大的图片可点击后使用官方分支的完整预览。
  • JSON 结构浏览上限 16 MiB;非法 JSON 显示原文与解析错误,不伪造空对象。
  • 目录手动刷新。非 JSON 预览的文件变更观察沿用官方资源机制;JSON 用工具栏刷新。
  • Office 转换要求当前 DSH 提供 officeToPdf;无服务时显示官方缺失服务提示。
  • 页面切换会释放当前预览与目录请求;切换四向布局不重新建立预览。
  • 未在浏览器完成的交互不得仅凭安装或 Slot 注册宣称验证通过,参见交付记录。

开发

Node 版本应满足构建依赖要求。工作区依赖安装无需执行安装脚本:

pnpm install --ignore-scripts
pnpm run build
pnpm test

已提交的 vendor/dsh 是固定版本 0.2.2-rc.1 npm 构件;下载/校验方式见 scripts/fetch-vendor.mjs。 JSON 源码快照包含文件哈希;更新时执行 scripts/snapshot-editor.mjs ,再检查差异。 构建脚本只生成本项目的 client*.js、.build 和依赖许可证;不修改 DSH 或上游 editor。

安装使用 DSH 插件管理器,选择本项目目录作为 bundle。只插入 better-file-viewer 一行,不覆盖任何现有条目。

架构

  • src/client.jsx:会话文件页、树、图库、JSON 和独立预览 occurrence。
  • src/core.mjs:地址、布局、JSON、并发和生命周期的可测试核心。
  • scripts/fork-preview.mjs:带上游锚点断言的隔离适配,失败即停止构建。
  • scripts/build.mjs:本地编译所需官方 primitives/store,宿主 React 保持 external;PDF/Excel/frontmatter 保持自包含懒加载。
  • betterFiles.preview Factory 独立拥有 betterFiles.document 等子 Slot;服务、locale 和 CSS 标识均与官方侧栏分开。

原侧栏继续运行未改动的官方组件,本插件不使用 sidebarRight/sidebarRightTabs,也不从注册表抓取官方组件实例。

初版 0.1.0 交付验证(2026-11-12)

  • 构建成功,14 项自动化测试全部通过:地址编码、四向比例、目录排序、JSON、预览独立取消、缩略图并发、命名空间/原侧栏隔离、懒加载语法、元数据和 CSS 作用域。
  • 插件管理器返回 application=applied、warnings=[]。
  • 已连接客户端的实时 Inspect 确认 conversation.view 中 better-files 为 active;betterFiles.preview Factory 与八种独立格式 renderer 均已注册。
  • 安装后再次检查原 sidebar.right.tab.document:八种原版 renderer 仍 active,原 owner 不变。只增加本插件的一行,没有覆盖原侧栏。
  • 已核实已安装中英文元数据、图标导出与有效 SVG XML,并检查安装包文件清单。
  • 未完成画面/点击端到端验证:可用的自动浏览器没有当前 GUI 的已认证会话。不能把 live 注册或语法测试等同于实际渲染验收;尤其 PDF/Office/Excel 的逐格式交互、明暗主题视觉与图标实际显示仍待在已登录页面检查。

修复版 0.1.1(2026-11-12)

  • 根据当前固定版本 ConversationContent/DefaultConversationViews 的 DOM 合同,只在自己的直接 View 根节点存在时约束宿主 viewArea 高度、禁止共享 scroller 滚动,并视觉隐藏其同级 composer seat。没有替换输入组件,也不写入草稿。
  • 去掉依赖不确定父高度的根 height:100%,改为可收缩的 flex 高度链。左右/上下均使用零最小值 Grid 轨道和固定 6px 分隔,树/预览内部滚动。
  • src/navigation.mjs 解析本会话 file resource、原生路径、file URL,或 JSON 字符串信封 {address/path, sessionId?, line?}。消费 viewRequest 后调用 completeViewRequest;按请求对象身份处理重复点击,拒绝跨会话资源和非文件 URL。工作区外文件保留预览能力,但不尝试列举工作区外目录。
  • 目录缓存、展开和选择使用标准化路径 key;Windows 大小写/分隔符差异不会导致无法展开或高亮。定位只滚动树自身,不使用会带动外层页面的 scrollIntoView。
  • src/json-base.css 恢复编辑器布局变量、基础字体、字段标签/值两列排版、小屏折行、只读值边框、表格与内部滚动,继续使用局部作用域和宿主主题。
  • 构建成功,30 项测试通过。重新启用当前安装返回 application=applied、warnings=[];live Inspect 确认 better-files 与独立 Factory active,原侧栏八种 renderer 仍 active。
  • 本轮仍未取得自动浏览器的 GUI 登录态,未声称完成截图或点击端到端验收。刷新当前 GUI 后应重点复测:四方向独立滚动/分隔拖动、切回聊天草稿保留、会话文件链接自动打开、JSON 对象/数组排版。

0.1.2 当前修订

  • 按用户最新要求撤销 SJE 精简和二次排版,完整保留上游默认样式声明,包括 object/表格/控件、字体、配色、阴影和布局变量。仅重写样式作用域与动画名称以免污染宿主,并用少量几何规则约束嵌入尺寸;取消强制单页/超大compactBreakpoint/隐藏标题。
  • 自动测试逐项比较默认 object/表格/控件规则与上游原文、保留根变量及配色、验证作用域和嵌入规则不修改外观。构建成功,31项测试通过;尚未完成真实浏览器视觉验收。
  • 真实链接发送端已核实:当前安装 ui-chat/lib/client.js:15490–15494 的 openFile 直接调用 sidebarRight.openResource;0.1.1只补了viewRequest接收端,未打通真实发送链路。需要额外的Chat文件打开桥接,而不能继续宣称链接问题已修复;原侧栏仍未改动。

0.1.4 文件点击地址交接

  • 0.1.3 的真实复现已确认:文件视图实际挂载,但 viewRequest=null、selected=null,尚未触发预览。此前仅看官方 Chat 源码就断言整个路由未通、需要 fork Chat,是不成立的推断,已撤回。
  • 0.1.4 不替换 Chat、不改写 sidebarRight、不注册侧栏类型,也不阻止默认点击。仅在可信用户文件点击时暂存地址;已存在的导航打开本插件后,由自己的视图取回并消费。
  • 临时地址按 Session 与实际 Conversation DOM occurrence 隔离,5秒过期、一次确认、最多16个待交接会话;无关用户点击清空待交接,原生 viewRequest 始终优先。不会通过读取聊天正文或猜测文件名定位。
  • 兼容层依赖当前固定版本的 Conversation data 标记、本地链接 href,或 Markdown 文件按钮的 fileLink 类和完整路径 title;已对上游实际按钮代码加回归断言。按钮未暴露的行号不会猜测;URI自带的行号保留。后续官方标记改变需更新兼容层。
  • 42项测试通过;Client Inspect 已确认实际加载build=0.1.4。尚待用户再次点击后的运行时“捕获→交接→消费→选中文件”验证,未将单元测试或注册当作成功预览。

0.1.5 目录交互优化(2026-11-13)

  • 用户已确认0.1.4点击文件自动预览可用。实时Inspect记录到README请求被消费、selected指向真实路径、previewKind=official-fork,随后用户也正常浏览了源码文件。本轮保留该地址交接机制,不再替换Chat或改动侧栏。
  • 空目录及无图片目录的内容区留白,树中也不再插入空目录占位行;图片数量标题只在有图片时显示。加载、失败、重试和截断反馈不隐藏。
  • 左右树的文件夹名称使用与箭头同一可逆展开状态,重复点击即可收起;根目录按钮保持返回根目录而非切换根节点。
  • 上下布局使用Miller列:根目录、一级子目录、二级子目录各占一列;点文件夹进入下一列,点已展开目录或列标题收起分支,点同级目录替换后续列。每列有独立纵向滚动,整体仅横向滚动,新列自动移入可视范围。左右仍保留缩进树。
  • 列路径从当前folder派生,不另建易失步的目录选择状态;点击会话文件后仍按原导航定位到父目录。布局改变不重建当前预览,分隔拖动与仅预览继续保留。
  • 构建成功,49项测试通过;重新加载返回applied、无warnings,Client Inspect确认build=0.1.5;原侧栏八种renderer仍active。新增目录交互的真实画面/完整点击验收未由自动浏览器完成,需在当前GUI确认。

0.1.6 图标工具栏(2026-11-13)

  • 布局关闭态由反映当前方向的本地图标展示,真实原生select覆盖相同点击区域(不display:none、不从可访问树移除)。保留原生四向选择、键盘和Escape行为,外围focus-within显示焦点框。
  • 文件夹图标用于目录区显示/隐藏,aria-pressed=true表示目录区显示;名称保持稳定,tooltip提示当前动作。不再显示“仅预览/显示文件树”按钮文字。
  • 合并插件自己的顶部工具栏和预览路径/返回行,删除树顶部完整目录行及插件额外JSON标识行。回根、刷新、返回目录、图片前后浏览仍保留;当前路径在tooltip中可查。SJE默认工具栏和导航列标题不改。
  • 图标为本地原创currentColor SVG,不引入私有UI模块或第三方图标运行时。
  • 构建成功,53项测试通过。插件重载applied且无warnings,实时Inspect确认build=0.1.6及视图正常挂载。新图标工具栏未由自动浏览器完成画面/原生选择器交互验收,需在当前GUI确认。

0.1.7 图片快捷缩放和类型图标(2026-11-13)

  • 按用户最新选择,不增加缩放按钮。先点击图片或图片区使本插件获得焦点,再用Ctrl+加号/等号放大、Ctrl+减号缩小,支持小键盘加减。输入框、textarea、contenteditable、原生布局select及本组件之外不接管按键。
  • 目录缩略图的基准宽度默认130px,按32px步进,限制80–400px;CSS变量控制网格和图片高度,不改变图片组件key,也不因尺寸变化主动重新读文件。小窗口同样支持调整。
  • 单张图片将快捷键转发给独立fork的当前预览occurrence,复用原生setZoom、范围限制、中心锚定和平移。只在图片尺寸就绪后绑定命令,移除时清理;不同预览实例不共享命令。若初始fit-width低于原生最小缩放,缩小不会反向放大。
  • 树、层级列、目录列标题和图片卡片名称使用本地原创类型SVG。覆盖文件夹、图片、PDF、表格、文档、Markdown、配置/数据、代码、文本、压缩包、音频、视频、字体、二进制及通用文件。文件夹元数据优先于扩展名,专用图标区分展开状态;现有箭头/名称toggle不变,不加载外部图标库或字体。
  • 预览变化导致原焦点元素被移除时,仅在焦点已回到body的情况下恢复本视图焦点;点击非交互图片区也可聚焦,不打断编辑控件。
  • 构建成功,64项测试通过,含分类、边界尺寸、键盘保护、原生缩放命令/实例隔离和适配锚点。插件重载applied、无warnings,实时Inspect确认build=0.1.7。实际浏览器按键、整页缩放是否受浏览器/桌面宿主拦截、图标视觉仍需用户在当前GUI验收;未将静态/单元测试等同于按键实测。

0.1.8 Ctrl滚轮(2026-11-13)

  • 鼠标悬停目录图片区,按住Ctrl滚轮向上放大缩略图、向下缩小;无需先点击,不增加按钮。Ctrl加减仍保留。
  • 仅目录gallery容器注册原生passive:false wheel监听,取消这次已接管事件的默认整页缩放/滚动并阻止继续传播,切换到单图、空目录、卸载时清理。普通滚轮、其他区域、输入控件、Alt/Meta组合、已处理或不可取消事件不接管。
  • 归一化像素/行/页单位,单包像素量封顶40,指数缩放并保留两位小数,基准宽度仍限制80–400px,兼容触控板细小输入。尺寸改变仍只调整CSS变量,不重建缩略图或主动重读文件。
  • 单图不加第二层wheel监听,继续使用独立官方fork原生Ctrl滚轮、鼠标锚定和平移;补方向边界保护,初始fit低于最小缩放时向下滚动不会反向放大。
  • 构建成功,70项测试通过;插件重载applied、无warnings,实时Client Inspect确认build=0.1.8。实际浏览器/桌面鼠标滚轮和视觉效果未自动端到端验收,需在当前GUI确认。

0.1.9 直接打开文件后的目录加载(2026-11-13)

  • 用户报告从会话直接打开文件后,子目录长期显示loading。实时Client诊断确认workspaceFilesHandleStable=false:每次读取ctx.remote.workspaceFiles得到的traced服务句柄引用不同,不能直接作为React异步加载生命周期依赖。
  • 旧代码在请求消费/确认后父组件重渲染时,把新服务引用传入目录组件,触发effect清理、取消所有在途祖先目录请求;重新setup却只载入cwd,已经消费的定位请求不再调度祖先,因而子目录停在loading。
  • 文件服务改为每个FilesView稳定memo的轻量转发层,实际操作时再读取当前服务,并保留方法receiver、参数和AbortSignal;引用变化不再取消目录请求,同时避免固定保留过期服务句柄。JSON/缩略图也不会因此无故重读。
  • 目录请求协调器记住全部已需目录;stop中止请求并把内部loading转idle,start恢复所有中断祖先,不只cwd。通过任务身份+signal+激活状态防止旧结果覆盖新任务;刷新取消旧任务、卸载不再发布,失败仍明确显示并可重试。
  • 新增目录请求start/ready/failed/aborted有界诊断,不读取文件内容;构建成功,79项测试通过。异步测试覆盖深层定位、句柄变化、并发去重、取消/重启、忽略不协作旧请求、刷新竞态、失败重试和卸载。
  • 插件重载applied、无warnings,实时Inspect确认build=0.1.9及服务引用不稳定;用户原始直接打开场景仍需在当前GUI复测,未把协调器单元测试或服务身份探针当成完整浏览器验收。原侧栏、预览与布局交互不改。

0.1.12 聊天图片文件链接定位(2026-11-13)

  • 用户已确认0.1.9普通文件点击及目录加载修复有效。本次真实点击记录来自另一个会话:图片文件按钮带fileLink类,却没有title、href或子img;原导航已打开文件页,但request和selected均为空。对应官方MarkdownFileLink在有图片悬停预览时有意省略路径title,导致旧交接器拿不到地址。
  • 不替换Chat,不修改原组件或侧栏,也不使用React私有字段、悬停浮层位置、按钮文字来猜路径。通过一个返回null的新增header utility,使用标准useChat selector保留当前已提交Chat源的引用;不增加按钮、不扫描会话日志、不轮询,卸载即释放。
  • 仅真实、普通左键点击缺title的原生fileLink按钮时,按其data-chat-node-key、Markdown块及该块内链接序号,对照同Session已完成/中断assistant节点的原文。使用本地固定版本官方GFM解析器、引用定义表及parseFileLink恢复目标,核对块/链接数量及最多16个已知路径标题,源不一致时不猜目标。
  • 解析器收集数据,不执行组件、TeX渲染或图片读取;支持同名文案、引用链接、链接包裹的缩略图、脚注、空格/转义、行号,并排除代码、外链和单纯内嵌图片。内嵌图片按钮/上传附件继续保持原行为,不将blob/data URL猜作本地文件。
  • 恢复出的真实目标继续交给原有Session/Conversation occurrence隔离、5秒TTL的请求消费链。原点击处理不取消、不阻止传播;文件服务稳定facade、目录取消恢复、官方预览fork、布局和缩放不改。
  • 0.1.10/0.1.11仅为本次定位阶段的只读诊断版本,未作为图片修复发行。诊断现在可发现本页最多16个已观测Session、最近6条图片点击元数据,并有前台页专用Provider,避免按错误会话或后台页查记录;不采集图片字节、消息正文、外链查询参数或凭据。初始agent工具schema未增加,Provider按需发现。
  • 构建成功,94项测试通过;当前已加载0.1.12,nativeLinkCollector=true,实际观察到非可视Chat来源组件挂载。用户在原问题场景复测后明确确认图片已可打开;这是实际用户验收,不是自动浏览器端到端测试。

许可证

见 LICENSE、THIRD_PARTY_NOTICES.md 和 THIRD_PARTY_LICENSES.txt。 super-json-editor 是用户提供的私有项目快照;对外发布前需先补充其再分发授权。本包当前为 private。

Related plugins