dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DeepSeek Harness Web UI plugin: view and edit Excel/SpreadJS workbooks from the ui-all file tree.
GitHub · npm: @grapecity-software/dsh-spreadjs-editor
在 DeepSeek Harness Web UI 里,直接在右侧文件树中打开、查看和编辑 Excel / SpreadJS 文件。
A DeepSeek Harness Web UI plugin that opens, views, and edits Excel / SpreadJS files directly from the right-side file tree.

.xlsx、.xlsm、.csv、.sjs、.ssjson 文件。本插件单独使用就是完整的:打开、编辑、保存工作簿都不需要别的插件。但配上 driver,它会多出一件单独做不到的事——让 AI 直接改你屏幕上这份表。
本编辑器通过公开的SpreadJS 桥接契约支持其他 driver:driver 登记到 spreadjsBridgeRegistry,由用户选择后获取真实 Workbook 引用,无需依赖本 editor 的 npm 包。配套 @grapecity-software/dsh-spreadjs-driver 是其中一种实现,也能接入其他符合该契约的 SpreadJS editor。使用同一引擎之外,还需遵守实例身份、独占锁、取消和保存协议,并核对 SpreadJS 版本及模块支持。
本包不依赖任何 driver。SpreadJS、Designer 及扩展作为开发/构建依赖内联进浏览器产物,实例和授权始终由 editor 管理;DSH 与 React peers 由宿主提供。配套 Driver 不再包含 SpreadJS、Designer 或无头浏览器引擎。第三方 driver 使用自己的唯一 id;如需从服务端读取本 editor 的选择,设置文档命名空间为 spreadjs-editor,字段为 bridge。
两个插件都装在同一个 web profile 下——driver 的活工作簿能力只存在于 Web UI 里:
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-editor
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-driver
dsh --profile web
装完重启 DSH,打开任意一个表格文件,然后在 设置 → 电子表格编辑器 里选中 SpreadJS Driver。(没装任何 driver 时这一页只有「不使用」一项,编辑器行为与本功能不存在时完全一样。)
「装了」不等于「激活」:两个包都必须出现在 profile 的
dsh.profile.bundles里。光pnpm add或dsh plugin add不一定替你写进去,装完请开一个真实会话确认工具确实在场。
编辑器持有你打开的那份工作簿,每个 driver 登记为候选人;名册里可以有多个(比如我们的测试夹具),但只有一个会拿到工作簿——就是你在设置里选中的那一个。
选中 driver 后,AI 获得 sjs_live_open、sjs_live_execute 和 sjs_live_status。没有打开工作簿时,driver 可以请求 editor 打开文件并等待初始化;新文件可由 driver 从准备好的空白模板复制,Workbook 仍由 editor 创建和持有。
driver 执行期间 editor 会显示操作中提示,禁用 Designer 的鼠标/键盘编辑及冲突的保存、另存为、新建、导出入口。若用户关闭或切换 editor,销毁 Workbook 前会保存当前快照到现有恢复缓存,driver 返回中断;重新打开文件后检查已恢复的部分,再继续任务。该缓存只在当前页面生命周期内有效,不跨页面刷新,也不恢复 JavaScript 的执行位置。快照失败会明确写入控制台日志。
driver 的状态和执行按调用聊天隔离,并绑定当前文件的加载实例;重新加载即更新实例身份。恢复缓存使用完整聊天资源地址,不同聊天的同名文件不会互相恢复或清理。取消或超时后阻止后续自动保存;异步导出结束、写回之前再次检查任务权限。忽略取消信号的脚本仍持有编辑锁,直到结束或实例被销毁。已发送的写入可能完成,因此取消不能保证回滚。两侧插件需同时更新以支持实例身份协议。
0.2.0-rc.2:桥选择页使用 settings.section,选择结果保存在 editor 的设置文档中。开发依赖与宿主 peer 声明均以该 RC 为基线;旧版本和 alpha 不在支持范围内。| 组件 | 内置版本 |
|---|---|
| SpreadJS | 19.2.1 |
| SpreadJS Designer | 19.2.1 |
内置版本、授权状态与版权信息在 Designer「设置」标签的「关于」弹窗里。低版本 SpreadJS 可能无法打开本版本保存的 .sjs 或 .ssjson 文件;与旧版系统交换文件时,建议保留原文件并确认兼容性。
支持 DSH 0.2.0-rc.2,需要 Node.js ≥22.19。插件使用 DSH 自带的右侧栏,不需要安装任何第三方侧边栏插件。升级 DSH 时请同步升级插件;新的 RC 需重新验证后再调整支持声明。
| DSH 版本 | 状态 | 说明 |
|---|---|---|
0.2.0-rc.2 | 支持与验证基线 | 类型检查、215 项单测、构建、两个 smoke 与 verify:package 通过;运行中的 DSH 仍需重启后执行 probe:live 和界面验收 |
该 RC 提供工作簿所需的二进制后缀声明、内置只读预览、文档头部动作槽 sidebar.right.tab.document.actions 和设置分区 settings.section。本版不再声明兼容旧版 DSH。
插件内置 SpreadJS 和 Designer,无需编译。使用已安装的 DSH CLI 安装并启动:
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-editor
dsh --profile web
启动后,在 Web UI 右侧文件树中打开 .xlsx、.xlsm、.csv、.sjs 或 .ssjson 文件即可。
也可以通过 npx 安装并启动:
npx --yes @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add @grapecity-software/dsh-spreadjs-editor
npx --yes @deepseek-ai/dsh@0.2.0-rc.2 --profile web
旧版本用户请参阅升级说明。
保存的正式入口是 DSH 文档头部自己的工具栏(打开工作簿后,文件名旁边那颗「保存」)。它注册在 DSH 的官方动作槽 sidebar.right.tab.document.actions 里,与其它查看器的控件排在一起;有未保存改动时,「保存」前会多一个标记点,像 Excel 标题栏的 *。改动写回你打开的那个文件,不会再问你"要不要保存",因为按下保存本身就是你的意图。
同一份写回也挂在 Ctrl+S 和 Designer 工具栏上的保存按钮上:插件把 Designer 的 Save 命令重定向到写回,所以这两处按下都不会再弹出下载框。(Designer 自带的「文件」标签页已从 Ribbon 上隐藏,见本节末尾。)
这两颗头部按钮并不引用 DSH 的按钮组件——第三方客户端插件不能假定内部的 @deepseek-ai/* 包在运行时一定可解析,解析失败会连编辑器一起挂掉——而是照抄了邻居的规格:28px 高、padding: 0 6px、12px 字号、常态 --dsw-alias-label-secondary,悬停转 --dsw-alias-label-primary 并给 --dsw-alias-interactive-bg-hover 底色,禁用转 --dsw-alias-label-tertiary 且不再响应。也就是头部「查看器名称」与图标按钮的那一套;有一条单测钉住这些数值,避免以后悄悄漂移。
它们只在本插件负责的文件上画出来。这个动作槽对每个预览文件都会渲染,所以按钮要在插件自己的编辑器占据屏幕时才出现——否则工作区里每个 Markdown、图片、日志旁边都会多两颗按不动的按钮。产品自己的「用本地应用打开」也是这个形状:没有可打开的应用时就什么都不画。
顺序上它们排在「用本地应用打开」之前。槽位是 list,条目按公开的 order 排序(先 priority,再 order,最后才轮到注册顺序),插件注册在 -10 —— 而这正是 DSH 自己给「头部动作里排第一」用的值(dsh-client-ui-agent-preset 注册会话头部标签时就是 order: -10)。这样「先保存、再考虑外部打开」是确定的阅读顺序,也不再受插件加载顺序影响;未保存的标记点也因此落在这一组的第一项上,一眼就能看到。
Designer 自带的「文件」标签页已经从 Ribbon 上隐藏:插件不再改写它的私有菜单模板(那段改写已删掉),也不让它留在那里——因为「文件」页里的保存是下载副本,与上面那颗写回的保存只隔一次点击,两颗都在就是误存副本的来源。现在这个编辑器里只有一处保存:文档头部的「保存 / 另存为…」,加上 Ctrl+S。
代价是「文件」页里的其它分类(新建、打开、导入、导出、打印、信息)也一并看不到了——这是隐藏整页的必然结果,如果你需要其中某一项,告诉我,我们把它单独接回 Ribbon。隐藏方式是按产品公开的命令名(CommandNames.FileMenuButton)加它模板画出的元素类名做一条 CSS,作用域限定在本插件的面板内;这条规则有单测钉住,创建编辑器时控制台也会回报命中的元素数与它实际算出的 display,所以将来产品改名、规则失效会被看见,而不是悄悄多出一颗下载按钮。
.. 逃逸)直接拒绝。trustedHosts。头部工具栏上的「另存为…」把当前工作簿写到工作区的另一个路径——包括在 Designer 里重新置空的空白工作簿。它不碰原来那个文件。
报表.xlsx → 报表-副本.xlsx)。.xlsx、.xlsm、.csv、.sjs、.ssjson。写出格式由后缀决定,其它后缀会写出打不开的文件,所以在提交前就拦下。DSH 在标签页被切走时会卸载文档主体,平台也没有可供拦下的关闭钩子(关闭是同步的,文档定义里既无生命周期也没有否决点),所以这里不做「确认离开」的拦截,而是保证不丢:
*);面板右下角另有一个浮动胶囊,显示「未保存的改动」与「丢弃」操作。胶囊悬浮在表格上方,不占布局高度,保存成功后消失。如已获得许可证,在 web profile 的 cordis.patch.yml 中添加以下配置:
| Key | 默认值 | 说明 |
|---|---|---|
licenseKey | '' | SpreadJS 部署许可证。留空以带水印的试用模式运行。 |
designerLicenseKey | '' | 独立的 SpreadJS Designer 部署许可证。留空保持 Designer 试用状态。 |
maxSaveBytes | 67108864 | 单次保存允许的最大字节数;超出直接拒绝,不做截断。 |
trustedHosts | [] | 除本机回环地址外,额外允许调用保存接口的地址(局域网部署时使用)。 |
- id: spreadjs-editor
config:
licenseKey: 'YOUR_SPREADJS_KEY'
designerLicenseKey: 'YOUR_DESIGNER_KEY'
修改后重启 DSH 并刷新网页。
还有一项不写在这里:bridge 是「电子表格编辑器」设置页在 Web UI 里写的,代表用户选了哪一个桥。它同样属于本插件的配置,但不该手写进 patch——设置页会把写入结果如实报出来(写入被拒或失败时页面会说明),而手写的值不会经过这条检查。既没选过、又在 patch 里留空,含义相同:bridge: '' 等于「不使用」。本插件自身的设置页取代了 DSH 从这个 schema 自动生成的那一页,所以不会出现两个入口。
| 命令 | 验证内容 |
|---|---|
npm run typecheck、npm test | 类型契约,以及 215 个单元测试(保存路由的每条守卫、文件地址解析与地址构造、另存为的目标校验、默认名与失败文案、保存命令重定向的每条分支、编辑器主题桥的每条分支、查看器名称与二进制后缀声明的边界、未保存改动的缓存规则与脏状态跟踪的边界、打开时「用文件还是用缓存」的每个分支、面板状态胶囊的状态与操作矩阵、文档头部动作的发布/订阅/命令路由、按钮的尺寸字号颜色规格、「只在表格文件上出现」的判定与注册顺序,隐藏 Designer「文件」Tab 那条规则的两处身份与作用域,以及桥选择的方向与「写入被拒也要报出来」、桥字段是否真的声明为 volatile、名册自身的契约(重复 id 拒绝、disposer 语义、只在真的变化时通知)、名册与设置页在有无 settings 服务时的接线,以及设置页每一行确实是照 DSH 自己设置页的行规格画的) |
node scripts/smoke-client.mjs | 构建后的浏览器半结构:loader 包装、内联的 SpreadJS 与样式、外部依赖只有 react |
node scripts/smoke-node.mjs | 构建后的宿主半:路由注册、许可证配置,以及保存路径的真实写盘、冲突与越界拒绝 |
npm run probe:live | 对着正在运行的 DSH 跑一遍真实保存:真实 ctx.fs 的解析、落盘、冲突守卫、工作区越界;并核对进程里装的是不是本构建(插件版本与内置 SpreadJS 版本) |
npm run probe:live 要求 DSH 已重启到本版本。宿主半会在 /spreadjs/api/health 回报插件版本与内置 SpreadJS 版本,探针据此判断「正在跑的进程是不是这一版」——回报的版本与本构建不一致会直接判失败;如果进程里是很早的宿主半(连版本字段都没有),探针会说明需要重启,如果连保存路由都报 404,则说明那更是旧版。可选参数:--url(默认 http://127.0.0.1:3080)、--session <id>、--home <DSH_HOME>。探针会在会话工作区内建一个临时文件,结束时删除。
插件代码免费提供,采用 MIT 许可证。内置的 SpreadJS 和 Designer 是葡萄城商业产品,未配置许可证时可按其试用条款体验;插件免费不包含这两个产品的商业授权。
如用于正式部署或 SaaS 服务,请根据使用场景获取适用的 SpreadJS 和 Designer 授权。
.xlsx, .xlsm, .csv, .sjs, and .ssjson files.system still tracks the OS.This plugin is complete on its own: opening, editing and saving workbooks needs nothing else. Paired with the driver, though, it gains the one thing it cannot do alone — letting the AI edit the very sheet you have on screen.
This editor supports other drivers through the public SpreadJS bridge contract. A driver registers into spreadjsBridgeRegistry and receives the real Workbook only after explicit user selection, without an npm dependency on this editor. The companion @grapecity-software/dsh-spreadjs-driver is one implementation and can consume other compatible SpreadJS editors. Compatibility also requires document identity, leases, cancellation and save semantics, plus supported SpreadJS versions/modules.
This package depends on no driver. SpreadJS, Designer and extensions are build/dev dependencies inlined into the browser bundle; the editor owns the instance and licensing. DSH and React peers are supplied by the host. The companion Driver bundles no SpreadJS, Designer or headless engine. Third-party drivers use their own unique ids; the host-side selection document for this editor is namespace spreadjs-editor, field bridge.
Both plugins go into the same web profile — the driver's live-workbook capability exists only in the Web UI:
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-editor
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-driver
dsh --profile web
Restart DSH, open any spreadsheet file, then pick SpreadJS Driver under Settings → Spreadsheet Editor. (With no driver installed that page offers only "None", and the editor behaves exactly as it does without the feature.)
Installed is not the same as active: both packages have to appear in the profile's
dsh.profile.bundles.pnpm addordsh plugin adddoes not always write that for you, so after installing, open a real session and confirm the tools are actually there.
The editor owns the workbook you open; each driver registers as a candidate. The roster may hold several — our test fixture, for one — but exactly one is handed the workbook: the one you selected in Settings.
Selecting the driver enables sjs_live_open, sjs_live_execute and sjs_live_status. The driver can copy a template and ask this editor to open and initialize it. Import/export and Workbook ownership remain editor features.
Driver status and execution are confined to the calling chat and bound to the current loaded-document identity, renewed on every reload. Recovery snapshots use the full session resource address, so same-named files in different chats cannot restore or clear each other's buffers. Cancellation/timeout prevent subsequent automatic saves; the editor rechecks permission after export and before write-back. Scripts ignoring cancellation retain their edit lock until they settle or the instance is destroyed. A write already sent may complete; cancellation cannot guarantee rollback. Update both plugins for the identity protocol.
0.2.0-rc.2: the bridge picker uses settings.section and stores the choice in the editor settings document. Development dependencies and host peers target this RC; older releases and alpha builds are outside the supported baseline.| Component | Bundled version |
|---|---|
| SpreadJS | 19.2.1 |
| SpreadJS Designer | 19.2.1 |
The About button in the Designer's settings tab shows the bundled versions, the licence state and the copyright. Older SpreadJS versions may not open .sjs or .ssjson files saved by this version. When exchanging files with older systems, keep the original files and check compatibility.
Supports DSH 0.2.0-rc.2 and requires Node.js ≥22.19. The plugin uses the harness's own right Sidebar and needs no third-party sidebar plugin. Update the plugins alongside DSH; a newer RC needs verification before changing the supported baseline.
| DSH version | Status | Notes |
|---|---|---|
0.2.0-rc.2 | Supported and verified baseline | Typecheck, 215 unit tests, build, both smokes and verify:package pass; restart the running DSH before a separate probe:live and UI acceptance check |
This RC supplies the binary-suffix declaration, built-in read-only preview, document-header actions slot sidebar.right.tab.document.actions, and settings section settings.section. This version no longer declares support for older DSH releases.
The plugin includes SpreadJS and Designer, with no build step required. With the DSH CLI installed:
dsh plugin --profile web add @grapecity-software/dsh-spreadjs-editor
dsh --profile web
After startup, open .xlsx, .xlsm, .csv, .sjs, or .ssjson from the right-side file tree.
Alternatively, install and start through npx:
npx --yes @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add @grapecity-software/dsh-spreadjs-editor
npx --yes @deepseek-ai/dsh@0.2.0-rc.2 --profile web
For upgrades, see the release notes.
Save's official entry point is the harness's own document header — the Save button beside the file name once a workbook is open. It is registered in the actions slot sidebar.right.tab.document.actions published by DSH, next to the other viewers' own controls, and it carries a mark while anything is unsaved, like the * in Excel's title bar. It writes your changes back to the file you opened, and there is no second prompt, because pressing Save is the intent.
The same write-back is also on Ctrl+S and the Save button on the Designer's own toolbar: the plugin redirects the Designer's Save command, so neither of those reaches a download dialog any more. (The Designer's own File tab is hidden from the ribbon — see the end of this section.)
These two header buttons do not import the harness's button component — a third-party client plugin cannot assume an internal @deepseek-ai/* package resolves at runtime, and a failure there would take the whole editor down — so they copy the values from the controls beside them instead: 28px tall, padding: 0 6px, 12px text, --dsw-alias-label-secondary at rest, --dsw-alias-label-primary with the --dsw-alias-interactive-bg-hover background on hover, and --dsw-alias-label-tertiary with no response when disabled. That is exactly what the header's own viewer-name button and icon buttons do, and a unit test pins those values so they cannot drift unnoticed.
They are drawn only on the files this plugin handles. The slot renders for every previewed file, so the buttons appear only while this plugin's own editor is the body on screen — otherwise every markdown file, image and log in the workspace would carry two buttons that cannot do anything. The product's own open-in-app control works the same way: it draws nothing when there is no application to offer.
They are ordered before open-in-app. The slot is a list, and its entries sort by the documented order (priority first, then order, then registration sequence), where this plugin registers at -10 — the very value the harness itself uses for "first in a header actions list" (dsh-client-ui-agent-preset registers its session-header label at order: -10). That makes "save first, think about opening elsewhere second" a decided reading order rather than a side effect of plugin load order, and it puts the unsaved mark on the first item of the group, where the eye lands.
The Designer's own File tab is hidden from the ribbon. The plugin no longer rewrites its private menu template (that rewrite is gone), and it does not leave the tab in place either: the File tab's Save downloads a copy, one click away from the Save that writes the file back, and having both is how the wrong one gets pressed. This editor now has exactly one place to save — the document header's Save / Save As…, plus Ctrl+S.
The price is that the File tab's other categories (new, open, import, export, print, info) are not reachable from the UI any more; that is what hiding the page means. Say the word if you want one of them back on the ribbon and we will wire that one in. The hiding is one CSS rule keyed on the product's public command name (CommandNames.FileMenuButton) and the class its template draws, scoped to this plugin's panel; a unit test pins the rule, and creating the editor logs how many elements it matched and what display they compute to, so a rename in a future build shows up as a dead rule rather than as a quietly reappearing download button.
.. escapes — is refused.trustedHosts.另存为… in the same document header writes the workbook to a different path in the workspace — including a workbook that was reset to blank inside the Designer. The file it came from is left untouched.
report.xlsx → report-copy.xlsx)..xlsx, .xlsm, .csv, .sjs, .ssjson. The written format follows the suffix, so anything else would produce a file this editor cannot reopen; it is refused before the write.The harness unmounts a document body when its tab is hidden, and the platform offers no close hook to intercept (a close is synchronous, and a document definition has neither a lifecycle nor a veto point). So leaving is never blocked — and nothing is dropped either:
*. A floating pill at the bottom-right shows Unsaved changes and a Discard action. It costs no layout height and disappears after saving.If you have licenses, add the following to the web profile's cordis.patch.yml:
| Key | Default | Description |
|---|---|---|
licenseKey | '' | SpreadJS deployment key. Empty runs in evaluation mode with a watermark. |
designerLicenseKey |