DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Tool Notion — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
T

dsh-tool-notion

Tool Notion

Notion block conversion for DeepSeek Harness: turn an exported block array into Notion-flavoured Markdown and back, with rich-text runs split at annotation boundaries and every lossy step reported. No API client and no external dependency.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:yuehancn/dsh-tool-notion#4ddc6e73266c795bb5f895b2032ac1e029eab846
READMECompatibilityVersions

Compatibility and provenance

Tool Notion is published as dsh-tool-notion and currently resolves to version 1.0.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
github
Registry updated
10/2/2026

Versions

1.0.0stable
10/2/2026

Related plugins

Loading related plugins…

Latest
1.0.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
any
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/2/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in developer-tools.

Cc Safety Netcc-safety-netA coding agent CLI hook - block destructive commands and secret file accessVision Toolkit@anionex/dsh-vision-toolkitDeepSeek Harness-native integration for agent-vision-toolkit: image Q&A, OCR, grounding, UI restoration, pixel diff, Artifacts, and Web UI.Remotedsh-remoteRemote-work assistant for DeepSeek Harness: connect SSH (password/key/agent/keyboard-interactive/proxy jump), pick a remote workspace, operate on it with 22 rw_* tools (incl. rw_edit/rw_stat/rw_mkdir/rw_remove/rw_move/rw_forward), conflict-aware mirror syBridge@wenbin_wb/dsh-bridgeDSH remote connection/remote control plugin: scan a QR code with your phone to continue using DeepSeek Harness on mobile or over the public internet, even when you are away from your computer. One-click LAN QR codes, Cloudflare public tunnels, self-hosted tunnels, and WeChat / QQ / Feishu / Telegram

README

dsh-tool-notion

Notion 区块与 Markdown 的双向转换插件,给 DeepSeek Harness 用。

没有 API 客户端,没有外部依赖。 你从 Notion 导出(或从 API 拿到)一份区块数组,它转成 Markdown;你有一份 Markdown,它转成可以直接回写的区块数组。中间不做网络请求 —— 所以它能离线跑、能进测试、也不会因为一个 token 过期就整个失败。

notion_to_md      blocks  →  Markdown
notion_to_blocks  Markdown →  blocks
notion_validate   两边都收,报出结构问题
notion_status     先说清楚哪些块类型它认得

为什么要单独做这个

看起来是「数组 ↔ 字符串」,写起来才知道反了。

Notion 的段落是一组富文本 run,Markdown 的段落是一个字符串。

Notion:  [ {content:"Hello ",annotations:{}}, {content:"world",annotations:{bold:true}} ]
Markdown: "Hello **world**"

一个段落能有任意多个 run,每个 run 带自己的 bold / italic / strikethrough / underline / code,还能各带各的链接。要变成一行文本,就得在每一个注解边界切开插标记;要从一行文本变回去,就得把相邻的、注解相同的 run 合并才能得到 Notion 原本想要的形状。

这两个方向不是互逆操作。 一个是切分,一个是合并。这就是本插件里代码量的主要来源,也是测试里绝大多数断言在盯的地方。


安装

# cordis.patch.yml
plugins:
  dsh-tool-notion:
    workDir: "."
    outputDir: "notion-output"
dsh plugin add dsh-tool-notion

工具

notion_status

在转换之前先问它。它返回:

  • toMarkdown —— 能转成 Markdown 的块类型列表和它们的标记
  • toBlocks —— 能转回区块的 Markdown 构造
  • annotations —— 认识哪五个注解键
  • callouts —— 五种 callout 标签 ↔ emoji 的对应表
  • directories —— workDir / outputDir 的绝对路径

先看这个,就能把「不支持的块类型」变成一条已知边界,而不是转换到一半发现丢了东西。

notion_to_md

收一份区块数组,产出 Notion 风格的 Markdown。

// 参数(三选一)
{ blocks:        [ … ] }        // 区块数组本身
{ blocksJson:    "[…]" }        // 原始 API 响应(字符串),内部 JSON.parse
{ results: { … } }              // 带 results 的 API 包装对象,会自动认出来

为什么要有 blocksJson: defineTool 会在 execute 跑之前就校验参数类型,所以 blocks 这个参数只能收数组。而 Notion API 返回的是一个带 results 的对象。把对象塞进 blocks 会在你还没机会处理之前就被框架拒掉(invalid arguments: "blocks" must be an array)。所以留了一个字符串入口,让原始响应能原样递进来。

输出会在遇到无法表示的结构时显式报告,而不是默默吞掉。

notion_to_blocks

收 Markdown,产出区块数组。

{ markdown: "# Title\n\nSome **bold** text." }
{ path: "notes/export.md" }        // 相对路径,按 workDir 解析

产出的数组可以直接喂给 Notion 的 append 接口。

notion_validate

不转换,只检查。收 blocks / blocksJson,报出:

  • 区块数组的结构错误(缺 type、payload 形状不对)
  • 不认识的块类型
  • 空 run、缺 content 的 run
  • callout 标签无法回读的情况

要判断的是「这份数据能不能安全往返」,不是「这份数据合不合法」。 所以它盯的是会静默丢信息的地方。


五个注解,和有顺序的标记

annotations 有五个键:bold italic strikethrough underline code。

写标记的时候顺序是定死的,因为顺序变了意思就变了:

场景写法为什么
粗体 + 斜体***x***不是 **__x__,粗体在外、斜体在内
行内代码最内层反引号会压制其他所有标记,所以代码必须包在最里面
删除线~~x~~

INLINE_MARKERS 表是按从长到短扫的(*** 先于 *,___ 先于 _),否则 ***x*** 会被解析成三个独立的 *。

反斜杠奇偶性决定标记是不是活的 —— 这是行内扫描里最容易写错的一条:

"a \** b** c"    → 7 个字符:反斜杠转义了 *,标记没生效
"a \\** b** c"   → 4 个字符:反斜杠自己被转义,标记是活的

同一个形状,一个反斜杠之差,结果完全不同。测试里两种情况都钉了。

反引号要加宽围栏:如果内容里本身有反引号,外面的围栏就得比里面长。行内代码和围栏代码块都是这个规则。


Callout 的标签 ↔ emoji 必须是双射

这是开发过程中测试自己抓出来的一个真 bug,值得单独说。

Markdown 写 callout 用的是语义标签:

> [!WARNING]
> 这会删库。

Notion 存 callout 用的是图标 emoji。所以中间要做一次映射。第一版写了单向映射:解析时把 WARNING 存进 icon,回写时又把 emoji 写进 icon,再读回来时期待看到标签 —— 结果每一个 [!WARNING] 都变成了 [!NOTE]。

一个警告被静默降级成了提示。这种 bug 不会报错、不会崩,只会在某天有人因为没看到警告而删了库。

修法是把它做成真正的双射:

const CALLOUT_EMOJI = { NOTE: "📘", TIP: "💡", IMPORTANT: "❗", WARNING: "⚠️", CAUTION: "🛑" };
const EMOJI_CALLOUT = Object.fromEntries(
  Object.entries(CALLOUT_EMOJI).map(([label, emoji]) => [emoji, label])
);

function calloutLabel(payload) {          // 读:emoji → 标签
  const icon = payload?.icon;
  const emoji = typeof icon === "string" ? icon : icon?.emoji;
  if (emoji === undefined) return "NOTE";
  return EMOJI_CALLOUT[emoji] ?? "NOTE";  // 不认识的 emoji 退回 NOTE,不是丢 callout
}

五个标签全部在测试里钉了往返。另外还钉了两种输入形状:icon 是裸字符串、icon 是 { type:"emoji", emoji } 对象 —— Notion 两种都会返回。

通用的教训:凡是「语义值 ↔ 表示值」的映射,都要有反向表和反向断言。单向映射静静吃掉信息的方式是无声的。


parseNotionId 要认带 slug 的 URL

Notion 分享链接把 id 粘在人类可读的 slug 后面:

https://www.notion.so/My-Page-1f2e3d4c5b6a7c8d9e0f1a2b3c4d5e6f
                         ^^^^^^^ 这一段不是 hex

所以不能拿最后一段去匹配 ^[0-9a-f]{32}$ —— 会返回 null。正确做法是先剥掉 query 和 hash,再在整串里找 32 位 hex(或者带连字符的标准 UUID 形式):

const withoutQuery = text.split(/[?#]/u)[0];
const match = /([0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/iu
  .exec(withoutQuery);

一个被测试逼出来的框架规则

defineTool 的 JSON schema 里,每一个嵌套的 { type: "object" } 都必须显式声明 additionalProperties —— 固定形状写 false,自由映射写 true。不写就抛:

JsonSchemaError: … additionalProperties must be explicitly true or false

这个坑在本插件里踩了三次:嵌套的 directories 对象、blocks 数组的 items、以及 byType 这种自由映射。三次都是同一个错误,只是位置不同。数组的 items 也算嵌套对象,也要声明。


测试

node _test/run-all.mjs

三个套件跑在各自独立的子进程里 —— 每个套件都会用 new Function 重建一份插件副本,同进程会互相污染模块缓存。

notion logic:        230 passed, 0 failed
notion integration:  117 passed, 0 failed
notion end to end:    56 passed, 0 failed

共 403 条断言。

三个套件的分工:

  • test-logic.mjs(230) —— 纯函数白盒。行内扫描(含反斜杠奇偶性)、run 合并、注解边界切分、围栏加宽、callout 双射、缩进层级、块校验。
  • test-integration.mjs(117) —— 通过 defineTool 注册后的真实工具调用。参数 schema 形状(required 被提到顶层、parameters.properties 才是子项)、注册开关、错误信息、workDir 解析规则。
  • test-e2e.mjs(56) —— 一份故意难伺候的 "Deploy Runbook" 文档,从 Markdown 一路走到区块再走回来。里面塞了:带 # 注释的 shell 围栏、嵌套围栏、含代码的粗体、粗体链接、嵌套清单、callout、字面星号。

一条钉住的路径规则

path 参数按 workDir 解析 —— 绝对路径会被拼到 workDir 后面,而不是被当成绝对路径使用。这不是 bug,这正是「读不到配置根目录之外」的保证。集成测试里有一条断言专门钉这个行为,免得以后有人「顺手修好」它。

白盒断言的代价与收益

测试通过 new Function 把插件的内部函数(parseInline、mergeRuns、calloutLabel …)取出来直接断言。代价是 harness 要维护一份 INTERNALS 清单,漏一个就是 plugin.X is not a function。收益是不用为了测一个纯函数去套一层 JSON 管道 —— 上面那个 callout bug 就是这么被抓到的。


目录

dsh-tool-notion/
├── lib/index.js               插件本体(4 个工具 + 全部转换逻辑)
├── cordis.patch.yml           插件加载配置
├── _test/
│   ├── harness.mjs            用真实 dsh-tools 重建 apply,并暴露内部函数
│   ├── test-logic.mjs         230 条
│   ├── test-integration.mjs   117 条
│   ├── test-e2e.mjs            56 条
│   └── run-all.mjs            三个套件各自跑在子进程
├── LICENSE                    MIT
└── README.md

License

MIT © yuehancn


本插件属于 DeepSeek Harness 工具插件系列。同一系列还有 dsh-tool-comfyui、dsh-tool-gzh-publisher、dsh-tool-ocr、dsh-tool-media、dsh-tool-subtitle、dsh-tool-invoice、dsh-tool-qrcode、dsh-tool-epub、dsh-tool-podcast、dsh-tool-mining。