DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

jcy0chenyuan0 /

jcy0chenyuan0/dsh-plugin-ipynb

Verified

DSH plugin: read/export Jupyter notebooks and preview .ipynb in the sidebar (nbformat 3/4).

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@b6cbb97c

dsh-plugin-ipynb

给 DeepSeek Harness(DSH)加上读 Jupyter Notebook的能力,两侧都管:

半边 干什么
Client(侧边栏) 在右侧边栏打开 .ipynb 时自动渲染成 notebook 视图 —— 不再是一坨原始 JSON。Markdown 单元格、代码单元格、流输出、DataFrame 表格、图片、报错回溯都在。
Host(模型工具) 给模型三个工具:ipynb_read(读单元格+输出)、ipynb_summary(目录与体检)、ipynb_export(导出 Markdown / Python / 纯文本)。

侧边栏预览

打开任意 .ipynb(文件树、引用链接、@ 引用都行),默认渲染器就是 Notebook,不需要点任何东西。 工具栏的渲染器下拉里另外还能选 Code(语法高亮的原始 JSON)和 Plain text(原文)。

渲染规则:

  • Markdown 单元格:走平台自己的 MarkdownText(@deepseek-ai/dsh-client-ui-primitives,和聊天区同一套), 所以标题、粗斜体、行内代码、围栏代码块、列表、引用、分隔线、链接、表格都全, 并且 $…$ / $$…$$ / \(…\) / \[…\] 的 TeX 由 KaTeX 排版(矩阵、分数、求和、希腊字母、 \begin{pmatrix} 之类都正常)。MathML 无障碍臂、公式字体都跟着平台走,不需要额外资源。
  • 代码单元格:等宽正文 + In [n] 执行序号。
  • text/latex / text/markdown 输出:也交给同一个渲染器 —— 已经是 $…$ 的按原样过, 裸 TeX 自动补上 $$…$$ 走 display 模式。
  • 输出:
    • stream:先剥 ANSI 颜色转义,再把 \r 覆盖式输出(tqdm 进度条)压成最终一行;
    • text/html:表格直接转成真 DOM 表格(pandas DataFrame 的主要形态,自动高度、可横向滚动);非表格 HTML 走 sandbox="" 的沙箱 iframe(脚本、同源全禁);
    • image/png|jpeg|gif|webp|bmp|svg+xml:data URI 直接内联;
    • error:整段回溯按错误色显示;
    • 其它 MIME(plotly / widget 之类):列出 MIME 名并说明未渲染,而不是静默空白。
  • 超长输出:单条超过 30000 字符截断并标注截掉多少。
  • 坏文件:不是合法 JSON、顶层不是对象、UTF-8 解不出来,都给一张说明卡,并指路去 Plain text。
  • 样式只用主题 token(--dsw-alias-*),明暗主题都跟随;不 import 任何 Harness 客户端包。

它是怎么挂进去的

ctx.documentPreviews.register({
  id: "dsh-plugin-ipynb/notebook",
  extensions: ["ipynb"],
  priority: "extension",        // 默认档;注册表按 rank 降序排,builtin 排它后面
  title: () => "Notebook",
  loading: "bytes-complete",    // 挂载即整文件读取;text-pages 要滚到底才续页,notebook 必须整份
  wrap: false
})
ctx.slots.inject("sidebar.right.tab.document", () => ctx.slots.register(
  { name: "sidebar.right.tab.document", key: "dsh-plugin-ipynb/notebook" }, Body))

纯文本兜底实现声明的是 extensions: [],永远排在命中列表之后,所以默认选中的就是我们,不是 Plain text。

文件

dsh-plugin-ipynb/
├─ client.js             # Client 半边:浏览器产物(window.__ModuleLoader__.load)
├─ lib/index.js          # Host 半边:三个模型工具
├─ lib/host.js           # loader 挂载点(export * 转发,见下)
├─ cordis.patch.yml.tpl  # bundle 补丁层模板(install 脚本生成 cordis.patch.yml)
├─ package.json          # dsh.bundle.patch + dsh.client + exports["./client"]
└─ test/
   ├─ smoke.mjs          # Host 半边 103 项
   ├─ client-smoke.mjs   # Client 半边 65 项(假 React 真渲染一遍组件树,含公式去向往)
   └─ fixtures/          # nbformat 3 / 4 / 损坏 / 空 / BOM 样本

安装

首次安装:先在本目录运行 install.ps1(Windows)或 node install.mjs(macOS/Linux)。 脚本按当前目录自动生成 cordis.patch.yml(已 .gitignore),不写死任何盘符。

plugin_manager install_bundle  file:<本目录的绝对路径>

装完在 GUI 的「设置 → 插件」里可见、可整体启用/停用。改 lib/index.js 或 client.js 立即生效(挂载用绝对路径,HMR 会重载客户端模块);只有改 cordis.patch.yml 才需要重装。

自测(零依赖):

node test/smoke.mjs          # 103/103
node test/client-smoke.mjs   # 65/65

两个坑(都踩过,别再踩)

1. 挂载点为什么是 lib/host.js 而不是 lib/index.js

ClientModuleRegistry 用 specifier 作键缓存包元数据(sourceKey = baseUrl + "\0" + loaderName), 而且这份缓存从不失效。本插件最初以 lib/index.js 挂载时,那份 package.json 还没有 dsh.client, 于是 null 被永久缓存 —— 之后补上 dsh.client 也不会被重新解析。

换一个 specifier 就能让扫描重新读一次 package.json。所以补丁挂的是 lib/host.js (一层 export * from "./index.js")—— 不要改回 lib/index.js,否则侧边栏渲染器会静默消失,直到 DSH 重启。

2. React.memo(...) 返回的是对象,不是函数

判断「这个导出能不能渲染」不能写 typeof x === "function":

primitives.MarkdownText            // memo(function MarkdownText(...) {...})
typeof primitives.MarkdownText     // "object"  ← 不是 "function"

createElement 完全接受它,但那个 typeof 守卫会判 false。v1.2.0 就是这么栽的: MarkdownText 明明取到了,却被判成不可用,静默退回自带的极简渲染,于是公式 两次都不渲染,而自测还是绿的(因为替身当时写成了普通函数,正好绕开守卫)。

现在 isRenderableType() 同时接受函数与带 $$typeof 的 memo/forwardRef 对象, 自测里的 MarkdownText 替身也改成 React.memo(...) 包出来的,专门守住这条。 另外:降级不再静默 —— 一旦退回自带渲染,notebook 头部会出现一个 「公式未渲染」的告警 chip(鼠标悬停给出具体原因)。

Host 工具用法

// ipynb_read
{ "path": "analysis/eda.ipynb", "include": ["code", "markdown"], "limit": 20 }
{ "path": "eda.ipynb", "includeSource": false }          // 只看输出
// ipynb_summary
{ "path": "eda.ipynb", "previewChars": 120 }
// ipynb_export
{ "path": "eda.ipynb", "format": "markdown", "out": "exports/eda.md" }

path 相对路径按会话工作目录解析,也接受绝对路径。out 同样按会话工作目录解析且 必须留在该目录内(.. 逃逸被拒);read-only 沙箱模式下一律拒绝写盘。

兼容性

刻意做了这些处理,都是实测踩过的坑:

  • nbformat 4 与 3 并存:cells 与 worksheets[].cells 都认;v3 的 heading 归一化成 Markdown 标题(按 level 补 #),input → source,prompt_number → execution_count, pyout → execute_result,pyerr → error;stream 的 stream 字段与 v4 的 name 字段都当流名读。
  • source / text 两种形态:字符串与「按行拆开的字符串数组」都拼回整段。
  • BOM / CRLF:UTF-8 BOM 会被剥掉。
  • 未知 output_type:不崩,降级成占位并在 warnings 里明说。
  • 坏文件明确报错:JSON 非法、顶层不是对象、路径不存在、目标是目录、超过体积上限(默认 32 MB) 各给各的错误信息,绝不返回半成品。
  • 零宿主依赖:lib/index.js 只 import Node 内置模块(以绝对路径挂载的插件没有可达的 node_modules,import "@deepseek-ai/dsh-tools" 会在导入阶段失败,而 loader 只报一句 failed to import);client.js 只 require 平台种子模块表里的词 —— react 与 @deepseek-ai/dsh-client-ui-primitives(见下),并把它声明进 dsh.client.external。 工具按 registry 强制的原始 JSON Schema 方言注册,Host 自测里那个 schema 校验器保证 「声明的 schema」和「实际返回的值」始终一致。

配置

cordis.patch.yml 里可选的挂载参数(省略即默认):

- insert:
    - id: plugin-ipynb-readonly-1
      name: '<本目录>\\lib\\host.js'
      config:
        maxBytes: 33554432       # 单个 notebook 的读取上限
        maxSourceChars: 20000    # 单格源码默认截断
        maxOutputChars: 4000     # 单条输出默认截断
        cwd: '<可选:工作区绝对路径>' # 拿不到会话工作目录时的兜底

只读声明

Host 侧只读 notebook,唯一的写能力是 ipynb_export 在你显式给 out 时写导出文件,且受会话沙箱与 工作目录围栏约束。Client 侧纯浏览器渲染,HTML 输出只走表格转 DOM(只取文本)或 sandbox="" 的 沙箱 iframe。不联网、不起子进程、不注入微信/QQ 之类的外部进程。


可移植性 / 换机器安装

这个仓库不包含本机绝对路径:cordis.patch.yml 由安装脚本按当前目录生成(已 .gitignore)。

换一台机器:

  1. git clone 本仓库到任意目录;
  2. 运行 powershell -ExecutionPolicy Bypass -File .\install.ps1(Windows)或 node install.mjs(macOS/Linux);
  3. 在 DSH 里执行 plugin_manager install_bundle file:<本目录的绝对路径>。

运行环境

  • Windows / macOS / Linux 均可:Host 侧只用 Node 内置模块,Client 侧是预打包浏览器 bundle。
  • Node 20+(DSH 自带);无需 npm install。
  • 不依赖 Jupyter 内核;只解析 .ipynb 文件本身。
—/ 5

No ratings yet

Verified DSH bundle

Commit b6cbb97c8a87

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout