bbqisbbq/dsh-tiddlywiki
Project Overview项目介绍
This is a DSH plugin that integrates TiddlyWiki 5 as a private personal knowledge base within DSH. It allows AI agents to read and write content via dedicated tools, and automatically syncs and backs up via Git. It is ideal for users needing a persistent knowledge base across multiple agent sessions. Note that the TiddlyWiki dependency is relatively large.
这是一款DeepSeek Harness(DSH)插件,在DSH内集成TiddlyWiki 5作为私人知识库,支持AI Agent通过专用工具读写内容,自动通过Git同步备份。适合需要搭建跨Agent会话的持久化知识底座的用户使用,注意TiddlyWiki依赖包体积较大。
请帮我了解并安装插件:【dsh-tiddlywiki】【https://github.com/bbqisbbq/dsh-tiddlywiki】
Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。
Or use CLI install (for developers)或使用命令行安装(适合开发者)
CLI Install命令行安装
dsh plugin --profile web add dsh-tiddlywiki
把 bbqisbbq/dsh-tiddlywiki 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-tiddlywiki
把 TiddlyWiki 5 变成你和 Agent 之间的文档中心:一个嵌在 DSH 里、人手一个的私人知识库——Agent 用
tiddlywiki_*工具读写,你在界面里用完整 TW 编辑器记录,一切通过 git 自动同步备份。
🗂 它是什么:你的「文档 × Agent」一站式文档中心
这个插件首先不是一个"AI 记忆工具"(虽然它顺带就是)。它把一件事做顺了——文档和人、文档和 Agent 之间的协作:
- TiddlyWiki 天生适合当文档中心:卡片化组织(标签 / 双向链接 / 一键成文 / 一个文件夹就是整个 wiki)、纯文本 git 仓库天然可迁移可备份。它能是你的私人笔记本、GTD 工具、Agent 的记忆库,甚至让 AI 帮你把电子书导入 TW 来阅读批注——TW + DSH 能做到的唯一限制,只是人类的想象力。
- 人会参与:完整 TW 5 编辑器内嵌在 DSH 里,随时翻、随时改、随时批注。文档不是 Agent 写给你的黑盒,而是方便人类参与的文档中心。
- Agent 也能进:Agent 用 10 个
tiddlywiki_*工具读写;TW 里「发送给 Agent」把笔记一键注入某个会话;每个会话顶部自动汇总它读写过的 wiki 笔记。切换会话、方案终结、多轮合作,成果最终都回到文档里——文档成为跨会话、跨 Agent 的公共底座。 - AI 填平 TiddlyWiki 的门槛:TW 功能强大但上手有门槛,这正是 AI 擅长的——让 Agent 按你的习惯定制首页、标签体系、样式与工作流。曾经要折腾 Obsidian / Logseq 插件体系才能搭出来的个人知识库,现在一句话就能初始化一整套开箱即用的文档中心。
Obsidian、Logseq 也能做到其中一部分,但从没有像这样一站式地顺畅:编辑器、工具、会话、同步、主题全部在同一个界面里闭环。
✨ 特性一览
| 能力 | 说明 |
|---|---|
| 🏠 文档中心起步包 | 首次安装自动 seed:插件说明 + 「示例与文档」(主题汇总模板 / 教程 / 三个示例主题页),首页「📚 插件文档」栏一键查阅;同名 tiddler 已存在一律安全跳过,绝不覆盖你的数据(v0.16.22);插件说明里的工具清单由工具注册表实时生成,不会再写着「10 个工具」却已经 15 个(v0.22.0) |
| 📍 知识库位置可切换 | 设置页「知识库位置」可把插件切换到任意本地文件夹(不用改 cordis 配置、不用重装):就地停/起 TW 子进程,目标目录没有 tiddlywiki.info 时自动 --init server 建一个全新知识库;选择记在 $DSH_HOME/dsh-tiddlywiki/location.json——一个在 wiki 之外的指针文件(所以切到新 wiki 后仍记得「我用的是哪个」),「恢复为配置默认」一键清除;切换失败自动回滚到原知识库并如实告知(v0.22.0) |
| 🔄 seed 更新检测 | seed 标记记录内容哈希:内置内容在本 wiki 预置之后更新过 → 设置页显示「⬆ 有更新」;被你改过 → 显示「✏️ 本地已修改」,且「重新初始化」前二次确认;两者都基于哈希判定,绝不猜(旧格式标记会明确显示「尚未启用更新检测」,不会误报为「你改过」,v0.22.0) |
| 🎨 自定义样式 | 「自定义样式」seed:编辑器美化 / 窄屏侧栏隐藏 / menubar 加高 / 批注弹窗等 5 张通用样式表,新 wiki 也能一键初始化(可选,v0.16.22) |
| 📝 可配置的注入提示词 | 插件注入每个会话的「TiddlyWiki 持久知识库」提示词可在设置页配置:默认精简版(~1.7KB,只保留工具 schema 表达不了的约定——同步纪律 / 标签约定 / 链接格式),可选完整版(额外附一份由工具注册表实时生成的参数索引,不会再过期);extra 追加自定义规范、override 整段接管、可整体停用;保存后无需重启 dsh web(section 即时重注册,当前会话下一步即生效),设置页可按表单当前值预览即将注入的全文(未保存的形态切换也立刻可见,v0.21.0 / v0.22.7) |
| 🤖 Agent 工具 | 15 个 tiddlywiki_* 工具:检索(相关度排序 + 命中处片段 + 字段过滤)、读写、增量追加、批量、重命名、软删除/回收站、反向链接、附件入库、知识库体检、git 同步与冲突解决(v0.19.0;检索/最近仍在服务端排除二进制附件,大 wiki 上从 515MB/17s 降到 ~0.4s) |
| 🛡️ 不会被覆盖的写入 | 所有写入路径(agent 工具 与 快速笔记/编辑器路由)都先读后写:不传 tags 就保留原有标签、自定义字段与内容类型(text/css/wikitext 等不会被重置成 Markdown,v0.20.1);tiddlywiki_put(..., expectedModified/expectedRevision) 与 tiddlywiki_delete(..., expectedModified/expectedRevision) 乐观并发——读取后若有人(在 TW 编辑器里)改过,写入/删除被拒绝(HTTP 409)而不是静默覆盖或丢进回收站;tiddlywiki_attach 的同名标题默认拒绝(要覆盖必须 force: true);tiddlywiki_delete 默认软删除进回收站,tiddlywiki_trash 可恢复(v0.19.0 / v0.19.1 / v0.19.5) |
| 🧼 渲染片段净化 | 回复流卡片与会话汇总注入的 TW 片段先经 host 白名单净化(丢 iframe/script/svg/on*/javascript:/data:text/html 等)——TW 自己的解析器只剥 on*,<iframe src="javascript:…"> 会原样通过并在 DSH 页面里执行(v0.19.1 修复的存储型 XSS) |
| 🔒 写路由方法校验 | 每个写路由只接受自己的 HTTP 方法:跨站 GET /sync、GET /restart、GET /upload 一律 405 且无副作用(v0.19.0 修复了「任意网页一张 <img> 即可触发 pull/commit/push」的 CSRF 面) |
| 🔑 密钥不外泄 | bridge.token / ui.sendToAgent.token / auth.password(v0.20.0)在 /admin/state、/admin/config 的回包里是 ********(设置页原样保存 ≠ 覆盖,清空即删除),git.remote 里的 PAT 打码;/tw、/api 与 POST /render 都拒绝 $:/plugins/dsh-tiddlywiki/ 命名空间——此前 /render 能把配置 tiddler 连 token 与 PAT 一起渲染出来(v0.19.3 / v0.20.0) |
| 🧯 路由不会拖垮进程 | 所有路由经 guardHandler 包装:任何 rejection(含代理里 try 之外的 new URL())都变成 413/500 响应,而不是宿主未处理的 promise rejection(那会直接结束 dsh web 进程并挂死请求);剪藏桥 listen 后保留常驻 error 监听(v0.19.3) |
| 📊 回复流卡片 | 工具结果显示原生 TW 卡片(按笔记自己的内容类型渲染:Markdown 笔记就是 Markdown,v0.18.0),检索/最近列表带命中处摘要(v0.22.8);[标题](https://raw.githubusercontent.com/bbqisbbq/dsh-tiddlywiki/HEAD/dsh-tiddlywiki/tw/#标题) 点击直达 TW 面板 |
| 📤 发送给 Agent | TW 笔记工具栏一键把当前笔记注入所选 dsh 会话(可选工作模式/权限/附加说明);成功/失败会弹出提示(v0.20.0 修复:此前提示把自由文本当 tiddler 标题传给 TW notifier,全部静默) |
| 🧭 内嵌编辑器 | 中央列内嵌完整 TW 5 编辑器(同源代理,Tailscale/内网/域名/HTTPS 均可) |
| 🗂️ 右侧边栏 Tab | DSH 新右侧栏(rightbar):首页「TiddlyWiki 知识库」入口一键打开,与聊天并排;链接点击可直达(v0.16.21) |
| 🧪 审计守门 | 第四轮审计(v0.20.0)把 CI 与 npm run verify:* 合成一份清单,并补上 verify-constants(filter 长度预算)、/render 403、auth 打码、notify 与草稿避让回归 |
| 🧩 Better Sidebar 共存 | 与 dsh-better-sidebar 侧边栏共存(其展开/收起按钮浮在 TW 面板之上);不再向该侧边栏注册 TW tab(v0.17.0 移除了 tab 注册,避免 tab kind 冲突) |
| 📚 会话知识库 Tab | 每个会话顶部汇总本会话读写过的 wiki 笔记,TW 原生渲染(host /render 片段管线 + 白名单净化,v0.16.19 / v0.19.1) |
| 📝 快速笔记 | 输入框上方快捷按钮或右下角「知识库」FAB;原生编辑页或 Markdown 卡片两种模式;首页内置「快速记笔记(完整编辑器)」 |
| 📌 本地剪藏桥 | 可选「剪藏桥 + 书签小工具」:DSH 监听 127.0.0.1 端口接收剪藏请求(Host 校验防 rebinding),点书签弹出浮层——可改标题/编辑选中文字/勾选图片,一键写入知识库;文字成笔记(默认 clip 标签),图片由桥下载存为二进制附件(type: image/* + base64,笔记内 [img[标题]] 内嵌),随 wiki 自动进 git;图片下载有 SSRF 守卫(仅公网 http(s)、逐跳校验重定向,v0.18.0) |
| 🔐 写操作防跨站 | 所有写路由(笔记/上传/同步/后台/代理)拒绝跨站请求(403),仅同源的 GUI 与内嵌 TW 可写;跨站 GET 与浏览器地址栏直达不受影响(v0.18.0) |
| ✅ 待办四象限 | 首页看板:任务打 todo 标签即收录,拖动即可分类/完成(正文附 q 字段),逾期/今日到期自动统计 |
| 🌗 跟随主题 | 内嵌 TW 自适应 DSH 深浅主题(纯内存切换,不进 git) |
| 🔄 一键同步 | FAB「同步」一键 pull→commit→push,状态点实时反映 git 状态 |
| 💾 数据即备份 | wiki 文件夹本身就是 git 仓库,自动 commit(60s 防抖) |
📦 安装
# ① npm 发布包(推荐)
dsh plugin --profile web add dsh-tiddlywiki
# ② 直接从 GitHub 安装
dsh plugin --profile web add github:bbqisbbq/dsh-tiddlywiki
# ③ 本地开发(link 方式,改完 src 后 npm run build 即生效)
dsh plugin --profile web add link:/path/to/dsh-tiddlywiki
装完重启 dsh web 生效。首次启动自动完成:初始化 wiki 目录、git init 并提交基线、写入功能必需的 seed(发送给 Agent 按钮 + 原生渲染路由 + 同源代理基址)与起步文档(插件说明 + 示例与文档);首页/所有文章/自定义样式等为可选项,需要时在设置页「初始化」手动写入。
🚀 快速开始
- 安装并重启 dsh web。
- 侧边栏「TiddlyWiki」→ 中央打开完整 TW 编辑器。
- 随手记:点输入框上方「📝」或右下角「知识库」→「快速笔记」;或在首页直接用「✍️ 快速记笔记」区块,写完保存即成为 tiddler 并自动进 git。
- 看文档:新 wiki 首页(初始化 home-index 后)有「📚 插件文档」栏——插件说明、汇总教程、模板都在里面,可自由删改。
- 收工同步:「知识库」→「🔁 同步」一键 push 备份。
- 让 Agent 参与:直接说「把刚才的会议纪要存进知识库」——Agent 用
tiddlywiki_*工具读写。 - 发笔记给 Agent:TW 里打开笔记 → 工具栏「发送给 Agent」→ 选会话 → 作为消息注入。
📖 使用指南
🤖 Agent 工具(15 个)
| 工具 | 说明 |
|---|---|
tiddlywiki_search |
检索(query + 可选 tags[]/tag/since/type/field/value/limit),按相关度排序(标题命中 > 标签 > 正文命中次数),摘要取自命中处上下文而不是正文开头 |
tiddlywiki_recent |
最近修改的笔记(倒序,支持 limit/since),开工快速了解动态 |
tiddlywiki_list_tags |
现有非系统 tag 及计数(已排除只挂在二进制附件上的 tag);默认列使用最多的 200 个(limit 可调、上限 1000),截断时返回 total/truncated |
tiddlywiki_get |
读单个 tiddler 全文(modified 以 ISO 返回,可直接用作 expectedModified) |
tiddlywiki_put |
写/覆盖;新建未指定类型时默认 text/markdown($:/ 系统条目除外),覆盖既有条目时保留原 type/tags/自定义字段(v0.20.1,改类型要显式 fields.type);expectedModified + force 提供乐观并发保护 |
tiddlywiki_batch_put |
批量写入(overwrite=false 跳过已存在;单条失败不影响其余、逐条报错;4 路并发但结果保持入参顺序) |
tiddlywiki_append |
增量追加:mode=append|prepend、heading=某标题 定位段落,写日志/批注无需读全文;与 put 同一套写策略(保留原 type/tags/自定义字段,新条目才默认 markdown),支持 fields 显式覆盖 |
tiddlywiki_rename |
重命名 + 尽量同步其他条目里的引用;旧标题删除失败时如实回报「两份副本都在」 |
tiddlywiki_delete |
删除(幂等)。默认软删除进 $:/dsh-tiddlywiki/trash/,permanent=true 才真删;支持 expectedModified/expectedRevision/force 乐观并发(读后被改动则拒绝,不把人类的新改动丢进回收站) |
tiddlywiki_trash |
回收站:action=list|restore|empty(索引读不到或损坏时显式报错,绝不把回收站当空的重建) |
tiddlywiki_backlinks |
反向链接:谁用 [[标题]]/{{标题}} 引用了它、谁把它当标签 |
tiddlywiki_attach |
把本机文件或公网 http(s) 地址存成二进制附件(图片/PDF/…),可嵌入某篇笔记;URL 走 SSRF 守卫;同名 tiddler 已存在时默认拒绝(避免静默覆盖笔记),确认覆盖要传 force: true(tags/自定义字段仍保留) |
tiddlywiki_lint |
知识库体检:垃圾标签 / 死链 / 空笔记 / 缺内容类型的类 Markdown 笔记 |
tiddlywiki_git_sync |
action: pull|push|sync |
tiddlywiki_git_resolve |
pull 冲突后按 tiddler 二选一(keep-local|keep-remote) |
知识库同步纪律:
- 开工先
tiddlywiki_git_sync action=pull(rebase + autostash,真冲突会 abort 并报文件)。 - 冲突后用
tiddlywiki_git_resolve二选一解决,再重新 sync(绝不自动覆盖)。 - 收工
tiddlywiki_git_sync action=sync(pull → commit → push)。
🔍 检索/最近跳过二进制附件(v0.16.20):
search/recent在服务端只取文本 tiddler(无type字段或text/*),图片/音频/视频/PDF/zip 等二进制 tiddler(base64 正文)不参与检索、不出现在结果里——大 wiki(如数千张书籍扫描页图)从此从 515MB/17s 降到 ~0.4s,也不会被同名书页图刷屏。get对二进制 tiddler 只返回元数据(binary=true+ 类型/大小 + 链接),不返回 base64 正文。
⚠️
fields.type是 TW 的内容类型保留字段(text/markdown等),业务分类请放tags,别写进fields.type。
🧠 注入的系统提示词(可配置)
插件会往每个会话的系统提示词里注入一段「TiddlyWiki 持久知识库」约定(设置页 → 系统提示词):
| 配置 | 作用 |
|---|---|
prompt.enabled |
关掉后本插件不注入任何文本 |
prompt.mode |
slim(默认):只保留工具 schema 表达不了的约定(写入/并发纪律、同步纪律、标签约定、可点击链接格式);full:额外附一份参数索引,由工具注册表在运行时生成,因此永远不会与真实工具脱节 |
prompt.extra |
追加在末尾的自定义规范(团队 / 个人偏好),始终生效 |
prompt.override |
非空时整段取代内置文本(extra 仍会追加)——想完全自写提示词时用 |
保存后不用重启 dsh web:host 会即时重新注册 prompt section,当前会话从下一步起就使用新文本(DSH 的 system-prompt/change 会更新历史里的系统消息)。设置页的「预览注入文本(按表单当前值)」按钮会把表单里此刻的值(含还没保存的形态切换 / extra / override / 停用开关)发给 host 实时拼成全文——所见即「保存后会注入的内容」,顶部还会标注「含未保存的修改」;预览是只读的,不会替你保存(v0.22.7 之前它只读已保存的配置,所以切换形态后不点保存直接预览会看到逐字节相同的旧文本,容易被读成「两种形态没差别」)。
为什么默认精简:v0.20.1 之前这段提示词里手抄了一份工具参数清单,最后一次同步停在 v0.19.0,而 v0.19.4 / v0.19.5 / v0.20.1 都改过工具参数——模型因此看到 6 处过期签名(
delete缺并发令牌、append缺fields、attach缺覆盖保护、batch_put缺overwrite、trash缺title/limit、list_tags缺limit)。v0.21.0 起:默认形态不再复述参数(工具 description 才是唯一事实),full形态的目录改为运行时生成,并新增scripts/verify-prompt.mjs守门(slim 不得出现参数清单 / full 的每个工具与每个参数都必须在场 / 两种形态都必须保留治理约定块)。
🧑💻 界面操作
- 📤 发送给 Agent:TW 工具栏按钮(首次启动自动写入 wiki,ONE-SHOT)。弹层可选附加说明(位于消息末尾)、工作模式(Agent 预设)、权限(权限预设),按工作区分组选会话或新建。消息自带待办说明。
- 🧭 中央列编辑器:侧边栏「TiddlyWiki」开关(显示名可改
ui.sidebarLabel,保存后即时生效,v0.22.8)。 - 🗂️ 右侧边栏 Tab(v0.16.21):DSH 新右侧栏展开后,首页会出现「TiddlyWiki 知识库」入口盒,点击即在右侧栏以 tab 形式打开完整 TW 编辑器——与聊天并排,适合边聊边查/边记。由
ui.showRightbarTab控制(默认开);老版本 DSH(无右侧栏)自动跳过。 - 🧩 Better Sidebar 共存:装了 dsh-better-sidebar 时,插件只做 UI 共存(中央 TW 面板的 z-index 自动压在其侧边栏展开/收起按钮之下,按钮始终可点)。v0.17.0 起不再向 dsh-better-sidebar 注册「TiddlyWiki 知识库」tab(旧版可用
ui.showBetterSidebarTab关闭)——该 tab 的 kind 会与其它注册方冲突报tab kind "dsh-tiddlywiki" is already registered。右侧边栏入口请用上面的 右侧边栏 Tab(DSH 原生 rightbar)。 - 📝 快速笔记:输入框上方快捷按钮(
ui.showQuickNoteDock)或 FAB;ui.quickNoteMode选打开方式——native(默认,直达 TW 原生编辑页,草稿自动续写)或 card(CodeMirror 6 Markdown 高亮、文件上传、多选 tag、草稿自动保存、「🕘 最近」载入、Ctrl+Enter 保存)。v0.22.6:原生编辑弹窗里用 TW 的「🗑 删除」把笔记删掉后不会再变成打不开的白板——再点一次「快速笔记」就会重新载入编辑器;card 模式底部操作条改成「按钮文字永不折行、放不下时整组换行」,窄卡片里不再把「✏️ 在 TW 中编辑」压成两行。 - 📌 本地剪藏桥(可选,v0.16.24+/v0.16.25 支持图片):DSH 设置 → 常规配置 → 勾选「启用本地剪藏桥」(保存后立即生效)——DSH 即监听
127.0.0.1:8618接收剪藏请求。浏览器书签栏新建书签,把知识库文档里的 JS 代码粘贴为地址,点一下弹出浮层:确认/修改标题与划线文字、勾选页面图片(封面自动标出)→「剪藏」即写入 wiki。文字成笔记(默认clip标签、正文含来源与选中文字、重名自动(2)去重);图片由 DSH 本机下载字节存为二进制附件(clip-url/clip-note溯源字段,笔记内[img[标题]]内嵌展示;某张下载失败自动降级为链接),全部随 wiki 自动 git commit。「📚 插件文档」栏的本地剪藏桥(书签小工具)seed 文档含完整步骤、书签代码、安全说明与 curl 用法。安全:桥只监听 127.0.0.1 + Host 白名单防 DNS rebinding;强烈建议设bridge.token(非空时校验书签的x-clip-token头,防止任意网页往 wiki 里塞内容)。图片附件按设计不参与search/recent(避免刷屏),get只回元数据。 - 🏠 首页(初始化 home-index 后):待办四象限(
todo标签 +q字段拖放分类)+ 快速记笔记(完整编辑器,勾选「同时加入待办」即建任务)+「所有标签 / 所有文章」入口 +「📚 插件文档」栏(自动收录所有带dsh-docs标签的 seed 文档)。 - 📚 会话知识库 Tab:会话顶部 Tab(
ui.tabLabel改名、ui.showSessionTab关闭),自动汇总本会话读写过的 wiki 笔记(写入 volatile$:/temp,不落盘不进 git),TW 原生渲染(v0.16.19 起/tw/render片段管线,与回复流工具卡同链路),链接点击直达中央 TW 面板,不可编辑。 - 🌗 跟随 DSH 主题:内嵌 TW 随 DSH 深浅切换 palette,纯内存不写回 wiki(
ui.followDshTheme/ui.darkPalette)。 - 🔧 知识库 FAB:统一入口(TW 面板开关/重载、快速笔记、同步、TW 服务状态悬停 tip)。同步拉取到新内容会自动重启 TW(同端口)。
- ⚙️ 设置页:DSH 设置 →「TiddlyWiki 知识库」:状态/重启、知识库位置(可切换)、常规配置、插件/主题/语言管理、初始化(seed 状态与重新初始化)。配置写入
$:/plugins/dsh-tiddlywiki/configtiddler,覆盖 cordisconfig:块(tiddler 优先)。
📍 知识库位置(可切换,v0.22.0)
设置页顶部「知识库位置(可切换)」区块显示当前实际服务的文件夹、这个位置是怎么决定的(指针文件 / cordis 配置 / 默认值)、指针文件路径,以及同目录下其它看起来像 wiki 的文件夹(含 tiddlywiki.info)的快捷填入按钮。
- 换一个位置:填根目录(绝对路径,支持
$DSH_HOME/${VAR}/%VAR%)+ 文件夹名 → 「切换到这个位置」。host 会停掉 TW → 释放自动提交与监听 → 指向新目录 → 起 TW → 重载新 wiki 的配置 tiddler → 跑核心 seed(markdown 插件 / 发送给 Agent / 渲染路由 / 同源代理 / 语言)→ 重新武装自动提交;选中即被记住(写进$DSH_HOME/dsh-tiddlywiki/location.json),重启 dsh web 后仍在新知识库。 - 新建一个知识库:目标文件夹若还没有
tiddlywiki.info,插件会照常自动--init server建一个全新的(别填已有的普通笔记目录——它会被初始化)。 - 恢复为配置默认:删除指针文件并(必要时)切回
config.wikiRoot/config.wiki。 - 安全语义:指针文件在任何 wiki 之外(若存在 wiki 自己的配置 tiddler 里,切到新 wiki 就会把这个选择一起丢掉——鸡生蛋);指针文件损坏/非法时明确报告并回退到配置默认,不会静默乱跑;切换失败会回滚到原来的知识库,并告诉你是「已回滚」还是「回滚也失败了」;同刻只允许一个切换(并发请求直接拒绝)。
- 注意:切换期间正在跑的 Agent 工具调用会失败(TW 在重启),界面上按钮会禁用并显示「切换中…(重启 TW)」。
wikiRoot / wiki 现在只是默认值——运行中的实际位置以指针文件优先。这也是为什么它能不改 cordis、不重装就切。
🧩 初始化(一次性预置 seed):哪些「必备」,哪些「可有可无」
seed 是把「wiki 里预置内容」随插件分发的机制:ONE-SHOT(只写缺失)+ 安全跳过(同名 tiddler 已存在绝不覆盖你的数据),需要时可「重新初始化」恢复、可「反初始化」移除。详细见 docs/seed-initialization.md。
| 层级 | seed | 说明 | 首次安装 |
|---|---|---|---|
| 🔒 核心(功能必需,不可移除) | send-to-agent |
TW 工具栏「发送给 Agent」按钮插件 | 自动写 |
render-route |
原生渲染路由(回复流卡片 / 链接直达依赖) | 自动写 | |
tw-web-host |
TW 前端 API 基址 → 同源代理(内嵌编辑器前提) | 自动写 | |
| 📖 起步(默认写、可移除,想要完整体验建档案) | doc-note |
「dsh-tiddlywiki 插件说明」笔记 | 自动写 |
starter-docs |
「示例与文档」:主题汇总页·模板 + 教程 + 三个示例主题页(日志/决策记录/排障) | 自动写 | |
| 🎀 可选(默认不写、设置页手动、可移除,可有可无) | home-index |
首页(四象限待办 + 快速记笔记 + 所有标签/所有文章 + 📚 文档栏)——文档中心的「门面」 | 手动 |
all-articles |
「所有文章」两列分页总览(🤖 Agent / 👤 人工) | 手动 | |
ui-styles |
自定义样式 5 张(编辑器美化 / 窄屏侧栏 / menubar 加高 / 批注弹窗等) | 手动 | |
menubar-theme |
menubar 顶栏跟随 DSH 主题换色 | 手动 | |
clip-bridge |
「本地剪藏桥(书签小工具)」使用说明——含书签代码 / 启用步骤 / 安全说明(真功能在插件运行时代码里,此 seed 只预置文档) | 手动 |
- 想获得完整插件体验:核心 3 项首次安装就有;再补
home-index(首页)+starter-docs(示例文档)即是一个开箱即用的文档中心。 - 一个可选项都不想要:完全不影响功能——设置页「反初始化」即可,核心项受保护不可移除。
- 文档怎么扩散到更多:以后插件新增的任何说明 / 教程 / 模板类内容都走 seed 并带
dsh-docs标签——首页「📚 插件文档」栏自动收录,你无需任何配置。 - 内置内容更新了怎么办(v0.22.0):seed 标记里记着内容哈希,设置页据此显示两个提示 chip——「⬆ 有更新」(内置内容比你 wiki 里预置的更新,可点「更新到内置版本」取用)与「✏️ 本地已修改」(这篇是你的内容,重新初始化会覆盖它,会先二次确认)。升级插件后旧 wiki 的标记没有哈希,会显示「更新检测尚未启用(重新初始化一次即可)」,不会把老标记误判成「你改过」;重新初始化一次即升级标记。绝不自动改写你的 wiki——更新只在你点的时候发生。
🛠 配置
插件行默认配置(缺省即默认,无需手动配置):
- id: dsh-tiddlywiki
config:
wikiRoot: "$DSH_HOME/tiddlywiki" # 默认位置;运行中可被设置页「知识库位置」覆盖(指针文件优先,v0.22.0)
wiki: "main" # 文件夹名("." = 直接用 wikiRoot 这个目录)
port: 0 # 0 = 自动探测空闲端口
git:
autoCommit: true
debounceMs: 60000
remote: "" # 空 = 仅本地 commit;填了才 push
branch: "main"
note:
tag: "inbox" # 快速笔记默认 tag
startup:
readyTimeoutMs: 60000 # TW 启动就绪窗口(v0.22.5,5s–600s;超出只警告并继续等,硬上限 = 3×,仍未就绪才判失败)
prompt:
enabled: true # false = 本插件不注入任何提示词
mode: "slim" # slim(默认:只留约定)/ full(+ 由工具注册表实时生成的参数索引)
extra: "" # 追加在提示词末尾的自定义规范(团队/个人偏好)
override: "" # 非空时整段取代内置文本(extra 仍会追加)
bridge:
enabled: false # 本地剪藏桥(书签小工具);保存后立即生效
port: 8618 # 监听端口(127.0.0.1;改后需重启 dsh web 才绑定新端口)
token: "" # 共享口令;非空时校验书签的 x-clip-token 头(强烈建议设置)
tag: "clip" # 剪藏笔记默认 tag
ui:
showQuickNote: true # FAB 里显示快速笔记入口
showQuickNoteDock: true # 输入框上方快捷按钮
quickNoteMode: "native" # native=TW 原生编辑页 / card=Markdown 卡片
sidebarLabel: "TiddlyWiki" # 侧边栏入口显示名
showPanelStatus: true
showSyncButton: true
followDshTheme: true # 跟随 DSH 深浅主题
darkPalette: "$:/palettes/CupertinoDark"
tabLabel: "知识库" # 会话 Tab 名
showSessionTab: true
showRightbarTab: true # DSH 右侧边栏提供 TiddlyWiki 入口/Tab
sendToAgent: { enabled: true }
uiLanguage: "" # 留空不干预;"zh-Hans" 自动启用简体
auth:
username: "" # 默认 loopback 匿名;暴露到非回环才需要
password: "" # 非空时插件内置客户端/就绪探测/浏览器代理都带 Basic 认证(v0.18.0 起真正可用)
运行时配置:设置页写入的
$:/plugins/dsh-tiddlywiki/configtiddler 是config:块之上的覆盖层(tiddler 优先、随 wiki git 同步),改 note tag / git / ui 开关 / 注入提示词(prompt.*) 都无需动 cordis;提示词改动保存后立即生效(section 即时重注册,当前会话下一步生效),剪藏桥端口改动仍需重启 dsh web 重新绑定监听;startup.readyTimeoutMs对下一次 TW 启动/重启生效(v0.22.5)。知识库位置是三层(v0.22.0):指针文件
$DSH_HOME/dsh-tiddlywiki/location.json>config:块的wikiRoot/wiki> 内置默认($DSH_HOME/tiddlywiki+main)。wikiRoot/wiki因此是「默认位置」而不是「唯一位置」——设置页切过的位置存在指针文件里(一个在 wiki 之外的文件),所以要换回配置值就点「恢复为配置默认」。
🌐 远程访问
TW 子进程只监听 127.0.0.1 回环;Agent 工具/快速笔记/同步都走 DSH 宿主进程→回环 TW,不受访问入口影响。浏览器里的 TW 编辑器 iframe 经同源代理 <DSH origin>/dsh-tiddlywiki/tw/ 访问(v0.6.0 起),所以通过 Tailscale / 内网 / 域名 / HTTPS 访问 DSH 时编辑器照常工作,且 TW 重启不打断编辑中的内容。
👨💻 开发
需要 Node.js ≥ 22。
npm install
npm run typecheck # tsc --noEmit
npm run build # clean + host tsdown + client tsdown + wrap(wrap 会校验 id 与体积 <900KB)
npm run selftest # headless:spawn TW → REST 读写 → git → 退出回收
npm run smoke:client # client bundle 的 module-loader 形状冒烟
npm run verify # = verify:static + verify:unit + verify:e2e(本地一键;CI 同款分档)
npm run verify:large # 3000+ 条目大 wiki:检索耗时 / 二进制零出现 / 真跑 commit(约 1 分钟)
node scripts/verify-send-to-agent-bundle.mjs # bundle 字段 + 源件逐字一致
node scripts/verify-seed-send-to-agent.mjs # 全新 wiki 上的 seed E2E
node scripts/verify-clip-bridge.mjs # 剪藏桥 headless 验收(含 SSRF 守卫)
node scripts/verify-seeds-admin.mjs # /admin/seeds 状态与 run 的 E2E
node scripts/verify-prompt.mjs # 注入提示词守门(slim 无参数清单 / full 与工具注册表逐项一致 / 治理约定不丢)
node scripts/verify-wiki-switch.mjs # 运行时切换知识库 E2E(真起 TW:切换 / 回滚 / 指针文件 / 非法输入,v0.22.0)
📦 从 npm 包安装的用户只有
lib/+src/+docs/(scripts/不在发布包里,避免把构建脚本塞进依赖树)——想跑上面的验收脚本请用 git 仓库:git clone https://github.com/bbqisbbq/dsh-tiddlywiki && npm install。
改 bundle/seed 的再生成流水线(不要手改 seed-*.ts 里的生成常量;bundle 版本号只在 scripts/bundle/versions.mjs 定义一处):
# 发送给 Agent 按钮(改 scripts/bundle/send-to-agent/ 后)
node scripts/build-send-to-agent-bundle.mjs
node scripts/gen-seed-send-to-agent.mjs scripts/bundle/send-to-agent.bundle.json src/host/seed-send-to-agent.ts
node scripts/verify-send-to-agent-bundle.mjs
# 渲染路由(改 scripts/bundle/render/server-routes/render.js 后;版本在 versions.mjs)
node scripts/build-render-bundle.mjs
node scripts/gen-seed-render.mjs scripts/bundle/render.bundle.json src/host/seed-render.ts
# 首页(改 wiki 的 🏠 主页/所有标签/标签笔记 .tid 后;默认就剥离作者私有人口 +
# 注入「📚 插件文档」栏,确要保留私有内容才加 --keep-private)
node scripts/gen-seed-home.mjs '<wiki>/tiddlers/🏠 主页.tid' '<wiki>/tiddlers/所有标签.tid' '<wiki>/tiddlers/标签笔记.tid' src/host/seed-home.ts
# 自定义样式(改 wiki 的样式 .css + .meta 后;tag 自动收窄为 $:/tags/Stylesheet)
node scripts/gen-seed-ui-styles.mjs '<wiki>/tiddlers/<https://github.com/bbqisbbq/dsh-tiddlywiki/blob/HEAD/样式.css>' … src/host/seed-ui-styles.ts
# 示例与文档(starter-docs)/ menubar 主题:直接维护 src/host/seed-starter-docs.ts / seed-menubar-theme.ts
# 随后 npm run build
产物约定:lib/ 内零 @deepseek-ai 运行时 import;client 必须 minify(否则 >1MB 被注册表校验拒绝);react/tiddlywiki 不打包(运行时解析)。
路由参考(开发者)
| 路由 | 方法 | 用途 |
|---|---|---|
/dsh-tiddlywiki/status |
GET | 面板健康(service/url/git/tag/ui) |
/dsh-tiddlywiki/note /edit /tags /recent /get /search |
POST/GET | 快速笔记、打开编辑器、tag/最近/单个/搜索(列表路由都支持 limit;/tags 另支持 sort=alpha|count 与 total/truncated,v0.19.4) |
/dsh-tiddlywiki/render |
POST | TW 片段渲染(host 净化后返回,回复流卡片/会话汇总用,v0.19.1) |
/dsh-tiddlywiki/sync /upload /restart |
POST | 一键同步、文件上传、重启 TW |
/dsh-tiddlywiki/session/summary |
POST | 会话「知识库」Tab 汇总 |
/dsh-tiddlywiki/agent/sessions /modes /send /create |
GET/POST | TW「发送给 Agent」:会话/模式/发送/新建 |
/dsh-tiddlywiki/api/* |
any | 透传 TW 服务(JSON) |
/dsh-tiddlywiki/tw/* |
any | 同源 TW 代理(远程访问核心) |
/dsh-tiddlywiki/admin/seeds /run /remove |
GET/POST | seed 状态(v0.22.0 起含内容哈希的「有更新 / 本地已修改」)/ 运行 / 反初始化 |
/dsh-tiddlywiki/admin/prompt |
GET/POST | 当前注入提示词全文(GET = 已保存的有效配置,v0.21.0);POST 带 {enabled,mode,extra,override} 则按草稿渲染、写入零副作用,供设置页预览未保存的表单值(v0.22.7) |
/dsh-tiddlywiki/admin/wiki/location |
GET | 当前知识库位置 + 来源(指针/配置/默认)+ 指针文件路径 + 同目录候选 wiki(v0.22.0) |
/dsh-tiddlywiki/admin/wiki/switch /reset |
POST | 运行时切换知识库 / 恢复为配置默认(失败自动回滚并报告,v0.22.0) |
项目结构
src/
├── index.ts # host 入口:装配 WikiServer/路由/工具/提示词/自动 commit
├── sdk.ts # 自包含 defineTool + dshHomePath(零 @deepseek-ai 运行时依赖)
├── host/
│ ├── wiki.ts # WikiServer:spawn/kill/自愈/端口探测/就绪轮询(策略见 ready-policy.ts)+ 迟到就绪复探;TW_PROXY_PATH 同源代理
│ ├── ready-policy.ts # TW 启动就绪策略(v0.22.5):软窗口 60s(可配)/ 硬上限 3× / awaitReady 纯策略(注入时钟,可单测)
│ ├── tw-api.ts # TiddlyWeb REST 客户端
│ ├── git.ts # git init/commit/pull/push/sync/status + AutoCommitter
│ ├── routes.ts # 全部 DSH 路由 + agent-send/create/modes + session/summary
│ ├── http.ts # 共用 HTTP 助手(readBody/json)
│ ├── clip-bridge.ts # 本地剪藏桥(v0.16.24):127.0.0.1 监听 + POST /clip 写 wiki(Host 校验/token/CORS preflight)
│ ├── session-summary.ts # 会话「知识库」Tab 后端
│ ├── admin.ts # 设置页后台:tiddlywiki.info 读写 + /admin/*
│ ├── config.ts # ConfigStore:cordis config 基底 + 配置 tiddler 覆盖层
│ ├── seeds.ts # 统一 seed 注册表(10 项,三层:核心/起步/可选)
│ ├── prompt.ts # 系统提示词(v0.21.0):slim/full 两种形态 + extra/override,full 的目录由工具注册表实时生成;v0.22.7 起草稿预览(normalizePromptPreview/describePrompt,与保存路径同一份拼装)
│ ├── seed-*.ts # 各 seed 实现(bundle/首页/ui-styles 常量脚本生成;starter-docs/menubar/clip-bridge 手工维护)
│ └── tools.ts # 15 个 tiddlywiki_* 工具(列表式注册)
└── client/ # 浏览器半部
├── index.ts # client 入口(inject ['slots'],纯 DOM,永不 throw)
├── endpoints.ts # 客户端同源端点常量 + describeSyncResult(同步回执唯一实现,v0.22.8)
├── status-cache.ts # 共享 /status 读取器(2s TTL + 在途合并)
├── ui-config.ts # 共享 ui.* 投影 + invalidate/subscribeUiConfig(v0.22.8 扩到全部 FAB 开关)
├── render-fetch.ts # **唯一**的 POST /render 调用(v0.22.8)
├── knowledge-fab.ts / quick-note-dock.ts / note-widget.ts / editor-popup.ts
│ # 知识库 FAB / 快捷按钮 / 快速笔记 / 原生编辑弹窗
├── markdown-editor.ts # CodeMirror 6 Markdown 编辑器
├── session-summary.ts # 会话「知识库」Tab(conversation.view 槽位)
├── tool-views.ts # 回复流工具卡片(tool.call.toolview)
├── theme-sync.ts / sidebar-entry.ts / sync-button.ts
│ # 主题同步 / 侧边栏入口 / 同步按钮
├── tw-frame.ts # **TW frame 内核(v0.22.4 起唯一实现)**:createTwFrameSurface(skin) 管 lazy-load / status 轮询 /
│ # 错误与启动态 / 主题同步 / FAB 重载 / hash 导航 / dispose;中央面板与右侧栏共用同一份
└── panel.ts / rightbar-tab.ts / settings-page.ts / state.ts / styles.ts / toast.ts
> ⚠️ v0.22.8 起 `endpoints.ts` 的 `describeSyncResult()`、`render-fetch.ts`、`ui-config.ts` 各是**唯一实现**:
> 同步回执、渲染调用、`ui.*` 投影都不要再在客户端面里各写一份(此前已因此漂移)。
scripts/ # 构建/校验/再生成脚本
docs/seed-initialization.md # seed 机制详解(权威)
lib/ # 预构建产物(发布含 lib/**,提交入库;零 @deepseek-ai 运行时 import)
🕘 版本记录
最近几个主要版本的一句话记录(完整变更见 Releases / git log)。
v0.22.8(2026-09-15):第六轮代码审计修复——host 与 client 各做一份只读审计,逐条核实后修 10 处真缺陷,并清掉一轮重复实现与死代码。① 数据丢失(P0):
/edit仍会把「调用方文本或笔记已保存正文」PUT 进刚复用的那个草稿,而那个草稿里装的是用户在 TW 原生编辑器里敲的未保存内容——触发路径极常见:打开快速笔记(标题精确到分钟)→ 写 → 关掉 → 同一分钟内再打开 → 草稿被覆盖。现在只有我们创建的草稿才由我们填充,复用的仅在调用方显式给了文本时才写。② 设置页超时(P0):fetchJson展开init后又硬编码signal,于是「知识库切换 / 恢复默认 / 重启 TW」的 120s 预算被 15s 掐断——宿主其实切成功了,用户却看到「切换失败」(大 wiki 冷启动实测 44s+),且重试会再走一遍停/启。③ 净化器崩服务:�这类越界数字实体会让String.fromCodePoint()抛RangeError,而净化器没有 try——一条笔记正文就能让POST /render502,打坏回复流工具卡与会话「知识库」Tab。④ 「幽灵草稿」:保存/「丢弃」后重置编辑器会触发防抖,把「空正文 + 新时间戳标题」又写成草稿,下次打开误报「已恢复未保存草稿」并跳过默认 tag。⑤/recent一直丢掉since(工具与卡片都发它),于是模型看到过滤结果、人看到未过滤列表——与 v0.20.0 修过的/search同类漂移。⑥ 隐藏的 TW 面板会因为一个在途/status响应重新起一轮 30×1.5s 轮询。⑦/tw代理补齐显式方法白名单。⑧/render的 404 改为结构化异常(原先按错误消息文本正则,改词即把「不存在」变 502)。⑨/get改用共享的isBlockedProxyTitle()(原为硬编码字面量副本)。⑩ 侧边栏显示名改完设置即时生效(原只挂载时读一次)。去重/死代码:新增render-fetch.ts(唯一渲染调用)、describeSyncResult()(同步回执)、formatLocalMinute(),ui-config.ts承担全部ui.*投影;删除生产零调用的ensureTwWebHost()(与tw-web-hostseed 重复)与listTags(),多个仅供模块内部使用的export与「算了却从不显示」的字段一并清除。守门:verify-render-sanitizer.mjs+1、verify-frame-guards.mjs+3、verify-audit-fixes.mjs+3(草稿覆盖那条已反向验证:还原修复即红)。v0.22.7(2026-09-14):设置页「预览注入文本」改为按表单当前值渲染(用户实测提问「两种内置文本形态差别是什么?为什么选了不同形态后查看当前注入文本显示的东西一样?」)。两种形态的差别其实只在 intro 一段:
slim(默认)是一句能力概览(实测 1735 字符),full换成由工具注册表实时生成的 15 行参数索引(2504 字符),三块治理约定(写入与并发 / 同步纪律 / 笔记约定)完全相同。但预览按钮此前只发GET /admin/prompt,读的是 host 已保存的有效配置,而下拉框的值只活在浏览器 DOM 里——于是「切换形态 → 不点保存 → 点预览」看到的是逐字节相同的旧文本,用户自然以为两种形态没差别。现在:①prompt.ts新增normalizePromptPreview()(把不可信的 body 白名单化成 4 个字段,未知键/错类型丢弃并回落内置默认)+describePrompt()(applyPrompt()与预览共用同一份拼装,预览不可能与保存后的注入不一致);②POST /admin/prompt接收{enabled,mode,extra,override}草稿并渲染全文,写入零副作用(不落盘、不触发onConfigChanged),同源守卫 + 畸形 JSON 400;GET 保留为「已保存/正在注入」的读取;③ 设置页按钮改名「预览注入文本(按表单当前值)」并 POST 草稿,标题栏在表单有未保存改动时标注「含未保存的修改,保存后才真正注入」。守门:verify-prompt.mjs新增 3 条纯函数断言(白名单、describePrompt与buildPromptText逐字节一致、两种形态在草稿里必须不同),verify-seeds-admin.mjs第 8 段把「POST 必须 405」换成 7 条草稿断言(slim/full 草稿不同、extra 追加、enabled:false为空、GET 仍是旧的已保存状态且onConfigChanged未触发、垃圾字段回落、畸形 JSON 400、跨站 403)。v0.22.6(2026-09-14):修「快速笔记」两处用户实测报障。① 原生编辑弹窗里删掉笔记后,弹窗变永久白板、再点「快速笔记」也回不来。
ui.quickNoteMode=native的编辑器是同一个 iframe 复用的,而openEditorPopup()只在 URL 变了才给 iframe 赋src(刻意如此:赋src即整页重载,会丢掉 TW 里未保存的草稿 / 滚动位置 / 撤销栈)。可 TW 编辑器的「删除」是tm-delete-tiddler:它把原 tiddler 与草稿一起删掉、并用removeTitleFromStory把 story 清空——于是弹窗里剩一块白板;而此时主机重建的草稿标题往往与删除前完全相同(默认标题是分钟级时间戳 + canonicalDraft of "…"复用),URL 不变 → 不重载 → 白板永远摆在那儿,再点按钮也只是「收起/重新打开」同一个空 iframe。现在三处一起兜住:新增isEditorPopupBlank()(同源读 iframe 文档里的.tc-story-river,一条.tc-tiddler-frame都没有即判空;跨源 = TW 里点了外链、文档仍在 loading、读不到文档时一律不判空,绝不擅自重载一个可能正在编辑的编辑器),空掉的弹窗在openEditorPopup()里强制重载;closeEditorPopup()同时清掉frame.dataset.loaded,所以「关闭再打开」也一定是新的编辑器载入(关闭意味着丢掉上一次的 view 状态);输入框上方的按钮与openNative()的「已打开」幂等守卫都改成isEditorPopupOpen() && !isEditorPopupBlank(),用户再点一次就能拿回编辑器。② card 模式底部操作条把按钮文字压成两行(用户截图反馈的美化问题)。340px 的卡片里 5 个控件本就放不下,旧 CSS 让 flex 默认收缩,于是「📎 上传」「🕘 最近」「✏️ 在 TW 中编辑」「保存」每个按钮里的文字都折成了两行(无头 Chrome 实测:每个按钮textRects=2、高 46px)。现在按钮一律white-space: nowrap+flex: 0 0 auto(文字永不折行、永不被压扁),装不下时整个右组换行并用margin-left: auto继续贴右缘,「Ctrl+Enter」提示允许收缩让位——实测全部按钮恢复单行(高 30px),左下是「上传 / 最近 / Ctrl+Enter」、右下是「在 TW 中编辑 / 保存」两行布局。守门:新增scripts/verify-editor-popup.mjs(进verify:unit,tsx 直跑源码 + 最小 DOM 打桩,11 条行为断言——同 URL 有内容不重载 / story 被删空必须重载 / 关闭清dataset.loaded/ 关闭后重开必重载 / 空白判据的四种保守边界;反向验证过:把两处修复改回去会红 3 条),verify-frame-guards.mjs另加 2 条接线断言(空弹窗不得被当成「已打开」)。真机复核:无头 Chrome 里确认「同一个 URL 再赋一次src确实会重新加载」「清空 story 后重载能恢复内容」,并用真实 CSS + 真实卡片结构对比修复前后的按钮排版。v0.22.5(2026-09-14):修「大知识库冷启动被误判为启动失败」(用户实测报障:dsh 启动时
[dsh-tiddlywiki] startup issue (self-healing is armed): Error: wiki server did not become ready in time)。根因不是 TW 没起来,而是就绪判定太急 + 判失败后再也没人复探。证据来自/status的环形日志:01:43:51 spawn … tiddlywiki.js … --listen→01:44:11 wiki server did not become ready in time→01:44:35 [out] Processing background action …+[out] Serving on http://127.0.0.1:52323。也就是说这个 5099 个 tiddler / 26MB 的知识库在冷文件缓存下真的需要约 44 秒才打印Serving on,而旧代码只有一个 20 秒硬超时,于是:① 抛错中断整条启动管线——配置 tiddler 没加载、核心 seed(发送给 Agent / 渲染路由 / 同源代理 / markdown 插件)没写、剪藏桥没起,全都会拖到下一次重启;② 写死health='failed'+ 一条粘性 error,而超时后没有任何东西会再探测,所以 TW 明明在正常服务,/status(面板 / FAB / 悬浮提示)却一直报故障。现在把「就绪」变成一条明确的三段策略(新的src/host/ready-policy.ts,纯函数 + 注入时钟,可单测):软窗口(默认 60s,可用startup.readyTimeoutMs在设置页调,夹在 5s–600s)之内安静等待;超过它只写一条slow start: /status not ready after Ns — still loading并继续等(状态保持starting,不再粘住 error);硬上限 = 3× 软窗口仍无响应才判失败——并且失败时不杀子进程,而是挂一个有界(10 分钟)、unref的「迟到就绪」后台探测,TW 真起来的那一刻立刻把状态改回running并清掉那条旧错误(ready (late): /status 200),stop()与新一次start()都会取消它。startup.readyTimeoutMs走「cordis 配置 < 配置 tiddler」双层,设置页保存后对下一次启动/重启生效,无需重启 dsh web。守门:新增scripts/verify-ready-policy.mjs(进verify:unit,tsx 直跑源码 + 虚拟时钟)——归一化/夹取、44s 冷启动必须判成功(本次事故形状的回归断言)、慢启动只警告一次、子进程退出 → 立即exited、始终不就绪 → 到硬上限才timeout、轮询节奏有界(慢窗口降到 2s,不空转),外加源码级接线断言(wiki.ts不得再出现 20s 硬编码、必须有awaitReady/armLateReadyWatch/clearLateReadyWatch,config/index/client 三处链路都在);verify-resilience.mjs增加一条真实 TW 的重启断言(窗口热改 + 夹取 + 仍判就绪)。v0.22.4(2026-09-13):重构:把 TW frame 的生命周期收敛成唯一一份实现(无功能变更,纯去重)。v0.22.3 那个「空
src把 DSH 载进 iframe」的 P0 之所以发生,根因不是谁写错了某个判断,而是panel.ts(中央列面板)与tw-frame.ts(右侧栏 tab)各自抄了一份showError/showStarting/showFrame/applyPendingHash/fallbackLoad/doRefresh——修 bug 时守卫只补到 panel,tw-frame 那份照旧,同一个坑于是踩了两次(panel.ts靠「!hidden⇒ 已载入真实 twProxy」这个不成文不变量侥幸安全,tw-frame 连这个都没有)。现在这六个函数只在tw-frame.ts新增的createTwFrameSurface(skin)里各有一份,createTwFrameController()退化成它的 rightbar 薄包装;一个 surface 只提供三样东西:皮肤(类名 + 可选内联样式)、惰性构建点(build()返回 view,由调用方决定挂到哪里)、可见性(setVisible())。panel.ts因此从 469 行降到 280 行,只剩 rect 钉住 / 惰性构建 / 共存 chrome / 面板互斥。顺带三处行为改进(都是去重后的自然结果):① 面板打开链接改为先state.openPanel()再surface.openTiddler()(内核以visible=false拒绝隐藏 surface,顺序反了链接会静默丢失,脚本里有守门断言);②setVisible(false)现在会隐藏 frame 并停掉有界轮询(下次显示重新给满预算);FAB「重载面板」刻意不受可见性限制(唯一判据是dataset.loaded)——显式重载请求要能覆盖关掉的面板,否则「关掉面板 → 点重载 → 再打开」会看到旧资源,而展示陈旧内容比多一次重载更糟;③ 内核的build()会记住「DOM 还没建就被要求显示」的情况并在建好后补一次/status—— 此前中心列若在面板挂载之后才出现,面板会停在空壳上直到用户再切一次。守门:verify-frame-guards.mjs加了计数去重断言(panel 里出现任何一个生命周期函数就直接判红,反向验证过:植入回来必失败),并新增scripts/verify-frame-surface.mjs—— 用 tsx 直跑源码 + 最小 DOM 打桩,真正执行createTwFrameSurface()跑 16 条行为断言(空src的两条重载路径、只显示真的载入过 TW 的 frame、同一 URL 不重复赋src、启动/错误/重试恢复、同源 hash 导航与跨源兜底、共享 chip 标签、dispose 摘监听且幂等),已进verify:unit。测试环境提示:本机沙箱里 node 再 spawn 孙进程会崩,npm run偶发段错误,verify-package-contents与verify-git-resolve的失败属环境问题(手动复核过断言全过),与本版无关。v0.22.3(2026-09-12):第五轮代码审计的客户端修复版(host 侧零缺陷:CSRF 门禁 / 片段净化 / SSRF 守卫 / 密钥打码 / 写策略 type 保留 / 乐观并发 / git 互斥 / seed 内容哈希 / 切换回滚逐条对照都成立;
tsc与 8 个verify-*全绿)。① P0:iframe 空src被当成合法地址使用。tw-frame.ts的 FAB「重载面板」处理是frame.src = frame.src、hash 兜底加载是frame.src.split('#')[0]拼 hash——而iframe从未赋过src时,读iframe.src得到的是宿主 DSH 页面自己的 URL。setVisible(true)会在首个/status回来之前就取消hidden(切走再切回即可命中),于是这两种写法会把 DSH 页面载进 iframe:iframe 里再起一份 DSH(重复 FAB、重复全局监听、白屏)。现在两处「整页重载」路径都只认dataset.loaded(只有showFrame写它)并抽出共享的loadableFrameUrl(),panel.ts原本靠「!hidden⇒ 已载入真实 twProxy」这个不成文不变量侥幸安全,现也改成显式判据。② P1:主题「活动」单选预选错误,且会影响写入。/admin/state只回info.themes(已加载集合),设置页就拿它的最后一项冒充「活动主题」;用户显式激活过非末位主题时,打开设置页显示错误选中项、不动任何单选直接点「应用主题」也会静默把活动主题改回末位那个。现在 host 读$:/theme并在/admin/state回info.themeActive(去掉$:/themes/前缀归一),设置页优先用它、猜末位只作兜底,并且只在 catalog 里存在时才认。③ P1:applyToFrame缺 try/catch。setThemeSyncConfig()是同步遍历调用各 frame 的 applier 的(doRefresh/load都在 await 链里),而frame.contentWindow.$tw这次属性访问在 iframe 导航到跨源页面(TW 里点外链)时自身就抛SecurityError(内层各助手的 try/catch 还没轮到),异常直接变成未处理 rejection 并中断那次刷新;现在整段包住。④ P2 清理:会话汇总的挂载 effect 补mountedRef卸载守卫(genRef只认「被更新取代」、覆盖不到卸载,在途请求 resolve 后仍会 setState 并递归再发一轮)、快速笔记按钮的fetchUiConfig().then(setMode)补 alive 守卫、note-widget卸载不再删除设置页也在用的页面级 toast 单例(原来会掐掉别人正在显示的提示);删掉三处无人消费的死标记/死字段(view.dataset.visible、data-dsh-tw-rightbar、BuiltUi.recentBtn、ConfigField.input),工具卡标签 key 补下标(同标签重复会撞 key),并把panel.ts里重复的requestRestart收敛为复用tw-frame.ts的那一份。守门:新增scripts/verify-frame-guards.mjs(已进verify:unit)——空 src 陷阱、活动主题优先级、跨源 try/catch、共享 toast、死标记共 13 条断言,其中readActiveThemeName()走真实函数(前缀 / 裸名 / 缺失 / 读失败),静态断言会剥掉注释行以免匹配到自己的说明文字。v0.22.2(2026-09-12):修「主题汇总页·模板」seed 内容被渲染成几千遍重复(用户实测报障)。模板里留了两个「可选」大段落,其中一个标题里有一个裸
<$list>(没有filter属性)——TW 渲染时把它当成「列出全部 tiddler 的列表」,于是整段「可选:把本页收进『一页多主题』tabs」说明被跟着重复渲染几千次(实测渲染出 1.1MB、约 2941 遍重复)。现在模板精简为一个列表 + 一行指向教程的说明:删掉两个「可选」段落(自定义<$list>样式版 / tabs 收录法),自定义需求统一见 [[教程:按主题/标签做汇总页]];模板正文的提示也改为「把正文里的主题A全部替换」(原来写「两处」,实际有 3 处)。已有 wiki 的模板不会自动更新(seed 是 ONE-SHOT):本机线上 wiki 已手工覆盖为新模板并同步 seed 标记哈希;其余 wiki 可在设置页「初始化」里对starter-docs点「重新初始化」(会覆盖你对模板的改动,改过请先备份)。顺带修好一个校验脚本的兼容问题:scripts/verify-package-contents.mjs假定npm pack --json返回数组,但 npm 12 返回{name:{...}}对象,导致「发布包内容」检查假失败(与本次改动无关,但会卡住发布流程)。v0.22.1(2026-09-11):修首页「快速记笔记」创建出的条目日期时间错误(用户实测报障)。首页快速笔记在标题留空时用
<now "YYYY-MM-DD-HHmm">生成标题,而 TW 的日期格式 token 只有小写YYYY/0MM/0DD/0hh/0mm—HH根本不是 token,未知字符被原样输出,于是生成的是2026-9-11-HH20这种标题(还伴随月份/日不补零)。现在改为YYYY-0MM-0DD-0hh0mm,并新增verify-constants.mjs守门(首页 seed 不得含HHmm)。同一处还把一个反模式改成 TW 的正确命名空间:$savetitle原本写$:/state/home-note/last-created——$:/state/*会被 syncer 落盘进 git(设置页覆盖层之外的有一份状态污染),改用$:/temp/*(tiddlyweb adaptor 显式排除,浏览器端临时状态不进 wiki)。顺带修好一个一直跑不起来的构建脚本:scripts/gen-seed-home.mjs的生成模板里有两处反引号没转义(第 148/181 行的`ok:false`),整个脚本语法错误——也就是说「改首页 → 重新生成 seed」这条路早就断了,本次同时修复。已有 wiki 的首页不会自动更新(seed 是 ONE-SHOT):设置页「初始化」里对home-index点一次「重新初始化」即可拿到修好的首页(会覆盖你对首页的改动,若你改过请先备份;本次作者的线上 wiki 已手工打上同样的两处修改)。v0.22.0(2026-09-11):知识库位置可在设置页运行时切换 + seed 文档「过期」检测 + 一个隐藏很久的数据丢失竞态。① 知识库位置可切换:
wikiRoot/wiki之前只能写死在 cordis 配置里(改一次要动配置文件 + 重启),现在设置页顶部「知识库位置」显示当前实际目录、这个位置怎么决定的(指针文件 / cordis 配置 / 默认值)、指针文件路径与同目录的候选 wiki;填一个绝对路径即可运行中切换——停 TW → 释放自动提交与监听 → 改指 → 起 TW → 重载新 wiki 的配置 tiddler → 跑核心 seed(markdown 插件 / 发送给 Agent / 渲染路由 / 同源代理 / 语言)→ 重建 git → 最后才写指针;目标目录没有tiddlywiki.info会自动--init server建一个全新知识库;失败自动回滚到原知识库并如实回报rolledBack。选择存在$DSH_HOME/dsh-tiddlywiki/location.json——一个在 wiki 之外的指针文件:设置页的覆盖层就存在 wiki 自己的配置 tiddler 里,若「用哪个 wiki」也存那里,切过去就会把这个选择一起丢掉(鸡生蛋);指针损坏只会报告并回退配置默认,绝不乱跑。② seed 更新检测:seed 标记从一行seeded-once升级为{version,hashes,at}——记下我们写下的内置正文的哈希,于是设置页能区分「⬆ 内置内容有更新」(可一键「更新到内置版本」)与「✏️ 本地已修改」(覆盖前二次确认);旧标记(无哈希)会显示「更新检测尚未启用」并按文本比对判定归属,不会被误判成「用户改过」;updateAvailable只是提示,绝不自动改写你的 wiki。③ 文档不再手抄易变事实:插件说明笔记里的工具清单由工具注册表生成(docNoteText(tools))——它此前写死「10 个 agent 工具」而实际已有 15 个。④ 修掉一个潜伏的数据丢失竞态(本次最重要的修复):flushPendingWrites()(「重启 TW 前把 syncer 队列排干」的哨兵)假设「哨兵落盘 ⇒ 队列已空」,但 TW 的 syncer 会跳过最近 1 秒内保存过的标题(syncer.js的throttleInterval/chooseNextTask)——哨兵是另一个标题、随时可写,于是它会插队先落盘,被 throttle 的写入仍留在队列里、随即被重启吞掉。这个竞态一直存在(AGENTS.md 记录过 v0.19.0「force-all 随机丢tw-web-host」),v0.22.0 新增的 seed 标记写入改变了时序,使它变成必现(verify-seeds-admin稳定复现)。现在改为两段式:写哨兵 A 等落盘 → 睡一个 throttle 窗口(从$:/config/SyncThrottleInterval读,默认 1s)→ 再写哨兵 B 等落盘;这期间所有被 throttle 的标题都会变可用并被写出,第二枚哨兵才是真正的队尾。守门:新增scripts/verify-wiki-switch.mjs(真起两个 wiki:切换 / 回滚 / 指针文件 / 非法输入,已进verify:e2e),verify-seeds-admin.mjs增加 5 组内容哈希断言(新鲜 / 用户改过 / 内置更新 / 旧标记两种 / 重新初始化后刷新)。v0.21.0(2026-09-11):注入提示词改为「默认精简 + 可配置 + 不再过期」。旧提示词手抄了一份工具参数清单,最后一次同步停在 v0.19.0,此后 v0.19.4(
list_tags limit)、v0.19.5(delete/attach/batch_put并发令牌与attach默认拒绝同名覆盖)、v0.20.1(append的fields)都改过工具层——模型实际看到 6 处过期签名。现在:① 新增prompt.{enabled,mode,extra,override}配置(设置页「系统提示词」区块):默认slim(~1.7KB,只保留工具 schema 表达不了的约定:写入/并发纪律、同步纪律、标签约定、可点击链接格式),full形态额外附参数索引但由tiddlywikiToolSummary()从注册表实时生成,不可能再脱节;② 保存后无需重启 dsh web——section 即时重新注册,当前会话从下一步起生效(DSHsystem-prompt/change会更新历史里的系统消息),设置页还能一键预览即将注入的全文(GET /admin/prompt);③ 用户文本里的{{…}}会被转义(DSH 对未知变量直接抛错,会炸掉整个系统提示词装配);④ 守门:新增scripts/verify-prompt.mjs(slim 不得出现参数清单 / full 的每个工具与每个参数都必须在场 / 两种形态都必须保留治理约定块 / 转义与 extra-override 语义),已进verify:unit。v0.20.1(2026-09-11):修复「覆盖已有条目时内容类型被静默重置」(数据正确性)。
tiddlywiki_put/tiddlywiki_append/tiddlywiki_batch_put覆盖既有条目时会丢掉它的type:cleanTiddler()把type当成「构造 PUT body 时跳过的字段」,于是finalTypeForWrite()再补默认值——put把text/css的样式条目改成text/markdown(整篇 CSS 被当 Markdown 渲染、样式静默失效)、把 wikitext 笔记改成 Markdown;append更彻底:它自己手写 PUT body,连type都不写,TW 于是回落text/vnd.tiddlywiki(磁盘上.md+.meta变成.tid,##/**粗体**/表格全按 wikitext 解析)。现在:覆盖路径一律保留原type,Markdown 默认值只给新建条目($:/系统条目除外);tiddlywiki_append与put共用同一套写策略(buildWriteTiddler),并补上了此前缺失的fields参数;rename与回收站恢复同样不再丢类型。回执也补了诚实提示:新建默认时写「新建且未指定,已默认 markdown」,覆盖时若类型真的变了会写「⚠️ 内容类型已从 X 改为 Y」。守门:新增scripts/verify-write-policy.mjs(7 条纯函数单测,已进verify:unit)与verify-audit-fixes.mjs的 6 条 E2E(css 保持 css / wikitext 保持 wikitext / markdown 追加不变 / 新建仍默认 markdown /fields.type是唯一改类型入口 / rename+回收站恢复保类型)。v0.20.0(2026-09-11):第四轮代码审计的修复版(安全 / 用户可见缺陷 / 工程守门 / 死代码清理)。安全:①
POST /dsh-tiddlywiki/render没有像/get、/tw、/api那样拦插件命名空间——TW 的/render对任意标题都渲染,于是{"title":"$:/plugins/dsh-tiddlywiki/config"}能把配置 tiddler 连bridge.token与带 PAT 的git.remote一起渲染出来(本机临时 wiki 实测复现;片段净化器只管标签、管不住正文)。现在抽出一份isBlockedProxyTitle()并覆盖/render(selftest 断言 403)。②maskConfigSecrets()此前只遮 token 与 git remote,而文档一直声称auth.password也被遮——实测原样返回;现在auth.password一并打码并附passwordSet展示位,回填掩码同样被stripMaskedSecrets()丢弃。用户可见缺陷:③ TW 的$tw.notifier.display()只认已存在的 tiddler 标题、不存在时什么都不做,而「发送给 Agent」的notify()传的是自由文本——所有成功/失败提示都是空操作(用户点完按钮毫无反馈);现在先写$:/temp/dsh/send-to-agent/notice再 display(bundle 0.3.4 → 0.3.5)。④ 快速笔记卡片丢掉了404 + {notFound:true}的响应体,notFound分支永不成立,于是「条目不存在」被显示成「wiki 服务不可用」;fetchJson现在保留 404 正文。⑤/edit的草稿查找在 v0.19.5 重构时把分支写反:规范草稿已存在时反而直接覆盖(丢用户未保存的编辑),扫描到的异构草稿被改名为新条目(留孤儿);恢复free ? canonical : 复用既有草稿 ?? 时间戳的避让语义,并补 E2E 断言。⑥ 会话「知识库」Tab 的「修改」时间用Date.parse()解析 TW 紧凑格式(20260101000000000→ NaN)后原样回显成 17 位数字;改用parseTiddlerDate()。⑦ 设置页点「同步 / 重启 TW」会refresh()重建整块配置表单,静默丢弃未保存的输入;现在只有服务端配置真的变了才重建。⑧tiddlywiki_search的field/value只在工具层生效,客户端卡片不发送、host 路由也不读——卡片列出的是未过滤结果;两侧已打通。⑨ 草稿自动保存调用了带副作用的getTags(),会把 tag 框里没回车的半截词提交成标签;新增纯读的peekTags()。工程守门:⑩ CI 之前各自维护一份脚本清单,与package.json双向漂移——verify-status-cache与verify-audit-fixes(v0.19.5 全部数据安全修复的唯一回归)从未在 CI 跑过;现在 CI 只调npm run verify:static|verify:unit|verify:e2e|verify:large。⑪verify-render-bundle的module-type断言查的是源码注释而不是 tiddler 字段(假断言,字段丢了照样绿);verify-package-contents不守src/docs也不禁scripts/;均已修正。⑫ 三个浏览器脚本硬编码D:/npm-global/...puppeteer-core且 Chrome 候选表漂移(Linux 上恒 SKIP),抽出scripts/lib/browser-env.mjs;waitFor与迷你路由分发器各抽成scripts/lib/tw-harness.mjs;TEXT_LIST_FILTER长度预算移进新的verify-constants.mjs(static 档,不再只在两个最重的 TW 套件里断言)。死代码 / 重复:⑬ 开启tsconfig.noUnusedLocals并清掉 16 处死 import/死类型;删FLUSH_PROBE_FILE、fetchUiConfig({force})、sidebar-entry的initialLabel、ToolCallOwnerProps未用字段、四个卡片的死textprop、headerTitle的 7 个空 case、__twDebug、panel.ts的兼容 re-export、一行包装setSessionSummaryTabLabel;invalidateStatus()由invalidateUiConfig()一并调用(设置页保存后 FAB/侧栏立即读新值);GitStatusView三份合成一份,snippetOf/safeEqual/assertPublicImageUrl各合成一份;客户端端点字面量统一收进endpoints.ts;defineTool从不被读取的output.schema参数移除。文档:修掉过期注释与文档(客户端仍写/tw/render、tool-views头部仍称「HTML 来自本地 wiki 所以安全」、host/routes.ts文件头只列 6 条路由、生成的 seed docstring 仍写Never throws.)。守门:verify-send-to-agent-bundle补外层 version 断言与 notify 回归,verify-secret-masking补 auth 用例,verify-status-cache补 invalidate 联动,selftest 补/render403。v0.19.5(2026-09-11):第三轮代码审计的修复版(数据安全 / 正确性 / 客户端网络卫生 / 工具性能)。数据安全:①
tiddlywiki_attach此前完全不读旧条目就PUT——附件标题一旦撞上既有笔记(会议纪要.png之类)会把那篇笔记连 tags/自定义字段/正文一起静默替换成 base64,是本轮最危险的一条。现在先读后写(004 = 新建,其余错误照常抛出),撞名时默认拒绝并要求force: true(并发令牌只证明「读过」、不等于「同意覆盖」),覆盖时仍保留原 tags 与自定义字段,新建附件也会补agent-written;嵌入笔记(noteTitle)同样走写策略。②/edit(快速笔记直达 TW 原生编辑器)此前把草稿写死text/markdown,而 TW 保存草稿会把字段抄回原条目——任何 wikitext 笔记被这样编辑一次就降级成 Markdown,!标题 /<$list>/[[链接]]下次全渲染成源码。现在草稿类型跟随原条目,只有新笔记才回落 Markdown。③ 回收站索引读失败/JSON 损坏时,delete此前把它当「空索引」再全量覆盖 → 之前所有回收站记录变成既查不到、也清不掉的孤儿(体积还留在 git 里)。现在读失败即中止(新增TrashIndexUnavailableError),损坏也不静默重建,trash list/restore/empty一律显式报错。④rename先写新标题、再删旧标题,此前若删除失败会抛裸错让调用方以为整个重命名没发生;现在如实回报「两份副本都在,请手动删除旧标题」。⑤tiddlywiki_delete支持expectedModified/expectedRevision/force——删除比覆盖更具破坏性,此前却没有任何乐观并发保护(get→ 人类在 TW 里改动 →delete会把新改动一起丢进回收站)。正确性:⑥ 会话汇总只探测前 300 篇,却把所有条目按探测结果渲染,超出上限的会被谎报成「⚠️ 已删除/不存在」;现在未探测的条目标「(未探测,超出单次查询上限)」。⑦/api透传补上方法白名单(宿主按 pathname 分发,此前 TRACE 之类的任意方法都会被转发给 TW)。⑧/tw代理遇到带 body 的 DELETE 不再把请求体留在 socket 上(此前会挂到 30s 超时)。⑨/admin/config不再把所有失败都当 400(服务不可用/超限走 413/500);/upload的「超限」判定与errorStatus统一。⑩WikiServer成功启动时清掉上一次失败的error(自愈成功后/status与面板提示不再长期显示过期故障)。工具性能:⑪batch_put从「顺序 2N 次 REST」改为 4 路有界并发(结果按入参下标回填,顺序与逐条容错完全不变),autoCommit移出循环。⑫ 快速笔记找草稿从「拉整份 listing」改为先单条 GET 规范草稿名,listing 只作兜底。客户端网络卫生:⑬ 新增共享的/status读取器(2s TTL + 在途合并)——此前中央面板、侧栏框架、同步按钮、快速笔记配置四处各有一份fetchStatus,页面加载时会同时发多次请求,而 host 每处理一次/status要起最多 5 个 git 进程;⑭ui-config的缓存同样改为 promise(并发调用共享一次请求),失败不缓存。其它:ToolsDeps.noteTag死代码删除;put/batch_put描述改为「防抖自动 commit(默认 60s)」以免模型误以为写完即提交。守门:新增scripts/verify-audit-fixes.mjs(10 条 E2E,真实 TW + 真实路由,每条都能复现旧缺陷)与scripts/verify-status-cache.mjs(5 条单测,tsx直跑源码),均已并入verify:unit/verify:e2e。v0.19.4(2026-09-11):标签列表全面「有界」——最后一个没有上限的列表接口。
GET /dsh-tiddlywiki/tags此前会把每一个去重标签(大 wiki 上千个)连同计数全量回给浏览器,而回复流工具卡只是展示前 60 个;tiddlywiki_list_tags更严重——同样全量灌进模型上下文。现在:①/tags支持limit(1–500,缺省仍是全量,快速笔记的标签自动补全保留完整词表)与sort=alpha|count(默认alpha,count按使用次数降序),回包新增total(去重后的真实总数)与truncated;② 工具tiddlywiki_list_tags新增可选limit(默认 200、上限 1000),截断时 render 明说「共 N 个,仅列出最多的 M 个」,不再让模型以为那就是全部;③ 客户端TagsCard改为直接请求?limit=60&sort=count(不再下载上千条再丢掉),并用total显示「共 N 个 · …另有 M 个」;④ 顺手消掉重复实现:路由与工具现在共用TiddlyWebClient.tagStats()一份计数逻辑(此前路由自己遍历一遍,且不跳过$:/系统标题,两侧口径可能不一致),/recent、/search、/tags的 limit 解析收进readLimit()/readOptionalLimit()两个助手。守门:selftest 增 6 条断言(截断/total不丢分母/tags与items同集同序/上限 500/sort=count单调递减/无 limit 时truncated=false),verify-tools增list_tags的 limit 用例。v0.19.3(2026-09-11):清掉审计清单里剩下的中优先级项(安全面 / 健壮性 / 正确性)。密钥不再外泄:
bridge.token/ui.sendToAgent.token会被GET /admin/state与POST /admin/config的回包替换成********(并给tokenSet标记),设置页原样保存不会把真 token 覆盖成掩码、清空即删除;git.remote里的 PAT 同时打码,回填同值也被丢弃。更要紧的是代理旁路:/get早先禁止读插件配置 tiddler,但/tw与/api会把任意路径转发给 TW 子进程,而它的 TiddlyWeb REST 对$:/…标题照答不误——GET /dsh-tiddlywiki/tw/recipes/default/tiddlers/%24%3A%2Fplugins%2Fdsh-tiddlywiki%2Fconfig实测能拿到配置正文。现在两个代理都拦截$:/plugins/dsh-tiddlywiki/命名空间(selftest 有回归断言)。健壮性:所有路由统一经guardHandler包装——此前每个注册都是void handleX(req,res),而宿主没有unhandledRejection处理器,任何一次 rejection(含代理里 try 之外的new URL())都会直接结束 dsh web 进程、请求挂死;剪藏桥 listen 之后补上常驻error监听(此前移除唯一监听后,运行期 server error 就是未处理事件 → 崩进程),stop()用closeAllConnections()+ 1s 上限,keep-alive 不再是卸载时的死等;/tw代理在客户端断连时中止上游 fetch 并销毁流(此前会一直拉到 30s 超时)。正确性:会话汇总不再把查询失败(超时/5xx)报成「已删除/不存在」(只有 404 才算不存在),来自请求体/会话日志的 sessionId、rename 旧标题、检索词一律 HTML 转义(TW 会原样透传 HTML,汇总片段又会被注入 DSH 页面),sessionId 还加了字符集白名单;/upload改原子写(wx+ 仅对 EEXIST 走后缀链,修掉 TOCTOU 与「任何 access 错误都当名字可用」)、文件名末尾点/空格先规范化(evil.html.此前能绕过可执行扩展名黑名单);SSRF 白名单补上多播224/4、保留240/4(含255.255.255.255)、192.0.2.0/24、198.51.100.0/24、203.0.113.0/24、192.88.99.0/24;readWikiInfo对顶层null/数组给出可读错误而不是TypeError;/admin/info空操作不再重写tiddlywiki.info+ 重启 TW,校验失败 400 / 内部失败 500 分开;/agent/create先校验工作模式再建目录(此前未知模式会留下孤儿目录);body 超限统一 413。v0.19.2(2026-09-11):v0.19.1 的内容 + 让 flush 哨兵真正生效。v0.19.1 在 npm 上只是被 staged(未确认),而那份 tarball 少了下面这个修复,所以补一个版本号(请以 0.19.2 为准,0.19.1 可以取消掉)。修复内容:
flushPendingWrites(「重启 TW 前把 syncer 队列排干」的哨兵)从来没成功过——① 它写type: 'text/plain'却去等.tid文件,而 TW 的文件系统适配器按内容类型决定扩展名(text/plain实际落.txt+.txt.meta);② 它用mtime >= startedAt判定,而哨兵是紧接在等待之前写的,Windows 上新文件的 mtime 可能落在同一/前一个时钟刻,条件永不成立。两者叠加 → 每次调用都超时返回 false,而所有调用方只把它当 warning:/sync、工具git_sync、seed 重启与启动路径的「排干 syncer」全部静默失效(启动路径还白等 8 秒)。现在按「文件名含dsh-tiddlywiki_flush-probe+ 文件内容含本次随机戳」判定(与扩展名/时钟无关),实测 <1.2s 返回;selftest 加了断言,另修掉一处「轮询结果被忽略就重启」的测试竞态(首轮 GitHub CI selftest 抓到的 404)。其余同 v0.19.1:CI 复活(.gitattributesLF + sourcemap 可复现)、渲染片段净化(存储型 XSS)、/note/edit共享写策略(不再清掉人类笔记的标签/自定义字段)、重启单飞与启动/teardown 握手、tiddlywiki_get字段摊平、lint两个坏检查、客户端泄漏与草稿回写等。v0.19.1(2026-09-11):第二轮代码审计的修复版 + 让 CI 重新变绿。顺带抓出一个"静默失效"的哨兵:
flushPendingWrites一直用type: 'text/plain'写哨兵、却去等.tid文件(TW 的文件系统适配器按内容类型决定扩展名,text/plain实际落.txt+.txt.meta),叠加mtime >= startedAt的判定在新写入的同一时钟刻可能永不成立 → 每次调用都超时返回 false,而所有调用方只把它当 warning。也就是说 v0.19.0 声称的「重启前排干 syncer」其实一直没生效(/sync、工具git_sync、seed 重启与启动路径全都受影响,启动路径还会白等 8 秒)。现在改成按内容随机戳匹配(不依赖扩展名、不依赖文件时间),实测 <1.2s 返回,并有 selftest 断言守门。CI 其实是红的:lib/index.js.map内嵌源文件原文(sourcemap 的sourcesContent),Windows 工作区是 CRLF、GitHub runner 检出是 LF,Linux 上重建出的 map 与提交版必然不同 →static作业的git diff --exit-code -- lib/每次失败,而它一挂,另外三个 job(needs: static)根本不会跑(v0.19.0 声称的四档守门实际停摆)。修法:新增.gitattributes(* text=auto eol=lf) 把工作区钉成 LF 并重建提交 lib/;顺带补上 send-to-agent 的「bundle ↔ seed 逐字节」守门(render 早就有,缺这条时「跑了 build 忘跑 gen」会 CI 全绿却发旧按钮)、prepublishOnly预检、CI 失败时能看懂的错误提示。安全(存储型 XSS):回复流卡片与会话汇总把 TW 片段dangerouslySetInnerHTML进 DSH 页面,而 TW 的解析器只剥on*——实测<iframe src="javascript:…">、<a href="javascript:…">、<form action="javascript:…">全部原样通过(任何写进 wiki 的正文——agent 笔记、剪藏、导入——都能在 DSH 同源页面执行脚本并调用未鉴权的/dsh-tiddlywiki/*路由)。新增 host 侧片段净化器(src/host/sanitize.ts:丢 script/style/iframe/object/embed/form/svg/math…、丢on*/srcdoc/srcset、URL 属性只放行 http(s)/mailto/tel/相对路径/栅格data:image/*,并先做实体解码挡javascript:这类混淆),新增POST /dsh-tiddlywiki/render作为客户端唯一渲染入口(客户端不再直连 TW 的未净化/tw/render,因此老 wiki 也立刻受保护);配套 payload 回归scripts/verify-render-sanitizer.mjs(已进 CI)。数据安全:/note与/edit此前不读旧条目就整体 PUT,用同名标题保存会清掉人类笔记的标签与自定义字段——现在两条人类路径与 agent 工具共用新的src/host/write-policy.ts(先读后写、保留字段、agent-written只给 agent 新建的条目);快速笔记卡片对「🕘 最近」载入的笔记回传expectedRevision,人类在 TW 里的并发修改会让保存得到 409 而不是被覆盖;重启 TW 前先排干 syncer(/sync与工具git_sync此前漏了 flush 哨兵——刚保存的笔记可能被重启吞掉);WikiServer.restart()改为内部单飞(admin 路由不受 routes 层互斥保护,并发重启会留下孤儿 TW 进程);启动任务是 fire-and-forget,teardown 现在先置disposed并等它收尾(插件热更新/禁用时不再「disposer 先跑完、startup 后 spawn」留下孤儿进程与泄漏监听)。工具层:tiddlywiki_get的自定义字段此前渲染成fields=[object Object](单条 GET 的fields嵌套没摊平)——q/due/clip-url对模型完全不可见,已修;tiddlywiki_lint的死链检查把每一条指向图片/附件的链接都误报成死链(标题集合取自排除二进制的列表),missing-type则永远不触发(TW 服务端会给无 type 的条目补text/vnd.tiddlywiki,改用[!has[type]]过滤器判定),描述与checks里的large-binary从未实现,已删除;tw-api的瘦列表(/tags、lint 用)加短 TTL 缓存。客户端:TW 就绪重试的 40×150ms 定时器、sync-button卸载后的迟到回调、injectStyles的共享<style>被旧 disposer 删掉、渲染阶段改模块级缓存(改到 effect 阶段)、tiddlywiki_list_tags卡片不截断(现最多 60 个 + 提示余量);快速笔记「在 TW 中编辑」成功后不再把同一份内容重新写成「未保存草稿」。工程:工具层 E2E 从 10 个工具补齐到 15 个(并断言一个都不能少)、selftest 新增「人类写路径保留字段 / 409 冲突」与「host /render 净化」端到端断言、package-lock.json版本与 npm 描述同步。v0.19.0(2026-09-11):按代码审计结论做的全量修复 + 一批新能力(安全 / 数据安全 / 工具层 / 客户端 / 工程)。安全:① 每个路由现在校验 HTTP 方法(此前
http.ts主动放行 GET、宿主按 pathname 分发,于是GET /dsh-tiddlywiki/sync会 pull+commit+push、GET /restart重启 TW、GET /upload落文件——任意网页一张<img>即可触发;实测复现,现已一律 405 且无副作用);② 剪藏桥 SSRF 守卫的 IPv6 判定改为按字节解析(此前::ffff:7f00:1、0:0:0:0:0:0:0:1、::0:1等回环写法全部放行——实测复现);图片下载改为逐跳 pin 住已校验的 IP(堵 DNS rebinding TOCTOU)、流式限长(不再先全量缓冲再判 15MB)、禁用透明解压;③ TW 子进程的 spawn 日志不再写明文口令(该日志经无需认证的GET /status返回),/status还会脱敏 git remote 里的 token、剪藏桥健康接口不再回显 port/tag/tokenSet、/get不再暴露插件配置 tiddler、/agent/sessions补上 token 守卫、token 比较改常数时间、/tw代理改为流式转发(大附件不再整包进内存)、上传拒绝 html/svg 等可在同源执行的文件、/note//edit拒绝$:/标题。数据安全:④ 新增tiddlywiki/markdown插件自举——全新 wiki 是用--init server建的,不含 markdown 插件,而插件默认把每篇笔记写成text/markdown,此前新用户开箱即见 Markdown 源码;⑤tiddlywiki_put覆盖已有笔记时不再丢掉原有的标签与自定义字段(PUT 是整体替换,旧实现只发 title+text;单条 GET 的自定义字段还嵌套在fields里,一并修掉);⑥ 新增乐观并发:expectedRevision/expectedModified+force,人类在 TW 编辑器里的改动不再被静默覆盖;⑦tiddlywiki_delete默认软删除进回收站(tiddlywiki_trash可 list/restore/empty);⑧readWikiInfo只把 ENOENT 当「没有配置」(此前读失败=空配置,设置页保存会整文件覆盖tiddlywiki.info),写入改为备份 + 原子替换;seed 的tw-web-hostcheck 不再吞错;重启 TW 前用flush 哨兵排出 syncer 队列(force 重新初始化曾随机丢掉tw-web-host)。工具层(10 → 15 个):新增tiddlywiki_append(增量追加 / 段落定位)、tiddlywiki_backlinks、tiddlywiki_attach(本机文件或公网 URL → 二进制附件)、tiddlywiki_lint(垃圾标签 / 死链 / 空笔记 / 缺内容类型)、tiddlywiki_trash;search改为相关度排序 + 命中处上下文片段 + 字段过滤 + limit 上限 + TW 紧凑日期解析(此前since过滤恒为空)、list_tags不再统计只挂在二进制附件上的标签、batch_put的单条失败不再被参数预校验整批打断、列表加短 TTL 缓存。客户端:草稿卸载/刷新前落盘、草稿按窗口分键(不再跨标签页互相覆盖)、session-summary自愈循环与卸载后 setState 修复、中央面板hidden状态修正、三个常驻定时器加上停止条件、wiki 链接不再吞掉 Ctrl/中键、编辑器弹窗补role=dialog与焦点、列表项键盘可达、21 处:focus-visible、移动端touch-action、numField的0不再被吞。工程:新增 GitHub Actions CI(静态检查 + 自测 + 单元 + E2E 四档,含git diff --exit-code -- lib/抓「改了 src 忘了 build」)、9 个新验收脚本(auth 模式此前零覆盖、工具层、seed 读失败反例、git 冲突、崩溃自愈、大 wiki、render bundle 逐字节、发布包内容、版本一致性)、npm run verify:*方便本地一键跑、lib/client.bundle.js不再入库、AGENTS 的grep @deepseek-ai检查修正为「真实 import」。升级提示:重启 dsh web 后新会话生效;客户端改动需刷新页面。v0.18.0(2026-09-10):一轮全量代码审计后的修复版(数据安全 / 安全面 / 前端稳定性 / 工程卫生,共 40+ 项)。数据不再静默丢失:① seed 只在真的 404 时才认为条目缺失(此前任何读取错误都被当「不存在」,瞬时故障会让非 force 的启动 seed 覆盖你改过的同名笔记、
$:/DefaultTiddlers、send-to-agent / render bundle);②wiki/.gitignore不再每次启动被整份重写(用户自定规则改前会被冲掉);③ 配置 tiddler 读失败不再清空内存覆盖层(随后在设置页保存一项配置会丢掉其余全部覆盖);④ 只有 render-route 真的重写后才重启 TW,且要等它落盘(否则重启会丢掉未 flush 的写入——这条是本版新引入又被测试抓出的回归)。正确性:/render现在按 tiddler 自己的type渲染——Markdown 笔记在回复流卡片/汇总里终于按 Markdown 渲染(此前硬编码 wikitext,## 现象会被当成 wikitext 列表,实测复现)。安全:所有写路由(/admin/*、/note、/edit、/upload、/sync、/restart、/api、/tw的写方法)加同源/CSRF 守卫(跨站写请求 403,跨站 GET 不受影响);剪藏桥图片下载加 SSRF 守卫(仅公网 http(s),逐跳校验重定向,拒绝回环/内网/云元数据地址);bridge.port设置页改动现在真的生效(此前只读 cordis 基座);auth.username/password从此可用(内置 REST 客户端与就绪探测带 Basic 认证,代理转发WWW-Authenticate让浏览器弹登录框,此前配置了用户名会让插件 20s 后启动失败)。前端:编辑器弹窗不再因同草稿重开而整机重载、并纳入面板互斥;中央面板自愈列元素重建;右栏 Tab 重新可见会重新探测状态;侧边栏入口插入不再抛NotFoundError连带拖垮 FAB/面板;同步中不再被 30s 轮询覆盖状态;injectStyles可卸载(热重载拿到新样式);每处 mount 独立 try/catch;面板的 DOM 观察/滚动测量合并到 requestAnimationFrame(流式输出时不再每帧强制样式重算)。工具与仓库:put/batch_put不再把读取失败当新条目而误打agent-written,fields不能覆盖title/text/tags,batch_put逐条报告失败;git 的 commit 与 pull 串行化(不再争.git/index.lock);/status的 git 摘要加 2s 缓存(每次调用少跑 5 个 git 进程);请求中途断开不再挂住路由;自动端口被占时会重新探测;tiddlywiki.info损坏不再让后台 500;会话汇总对后代会话/条目数设上限。工程卫生:bundle 版本单一来源(scripts/bundle/versions.mjs,渲染路由 0.2.0)、生成器从 bundle 读版本(外层 0.3.2 漂移修正为 0.3.4)、发布包不再带client.bundle.js中间产物、verify-*假阳性修复(未 await 的用例、被当成断言的 console.log)、selftest 失败也会回收 TW 子进程、gen-seed-home默认剥离私有人口、verify-menubar-theme不再默认打作者本机端口。v0.17.0(2026-09-10):移除:DSH Better Sidebar(dsh-better-sidebar)Tab 集成。旧版通过
ctx.betterSidebar.registerTab({id:'dsh-tiddlywiki'})注册的 tab kind 会与其它注册方冲突,浏览器控制台报sidebarRight: tab kind "dsh-tiddlywiki" is already registered (extension);本版整体删除该注册路径(删除better-sidebar-tab.ts、client 入口的挂载块,以及ui.showBetterSidebarTab配置项/设置页开关),插件不再引用ctx.betterSidebar服务。与 dsh-better-sidebar 的界面共存(中央面板 z-index 让位于其侧边栏按钮)保留;右侧边栏入口请用 DSH 原生 rightbar(ui.showRightbarTab)。更新后刷新页面生效;旧版可临时用ui.showBetterSidebarTab=false规避冲突。v0.16.28(2026-09-10):修:拖拽版剪藏书签在知乎等真实页面报
SyntaxError: Unexpected token ';'。根因(真实 Chrome 实验证实):0.16.27 把书签 href 做 HTML 实体转义("/&/<),但浏览器的a.href不做实体还原——拖拽成书签后存的就是实体文本,执行时即解析失败。修复:href 改为 percent-encoding(CLIP_BRIDGE_DRAG_HREF,属性里只剩%XX,天然无需任何属性转义);Chrome 执行javascript:URL 前会 percent 解码(实测通过)。浏览器 E2E 升级为直接以编码 href 走location.href执行(完全等价拖拽书签的执行路径)并断言浮层弹出;静态验收改为decodeURIComponent(href) === 代码常量一致性校验。行为不变——已拖过旧版书签的用户需重新初始化 seed 后重新拖一次(旧书签仍然坏的,因为里面的代码是实体文本)。v0.16.27(2026-09-10):剪藏书签支持「拖拽安装」。seed 文档新增一个可拖拽按钮(markdown 内嵌原始 HTML 锚点,href 即书签代码)——按住拖到浏览器书签栏/地址栏松手即装好,免去复制粘贴;代码 fence 保留作兜底。书签代码抽成单一常量
CLIP_BRIDGE_BOOKMARKLET(锚点 href 做 HTML 实体转义),并新增同步一致性校验(verify-clip-bridge.mjs:href 解码后与代码逐字相等)与浏览器 E2E(verify-clip-bridge-browser.mjs:真实 TW + 无头 Chrome 渲染真实 seed 文档,断言 javascript: href 原样保留 / draggable / 解码一致 / 真浏览器里执行书签弹出浮层 / 无 JS 异常)。v0.16.26(2026-09-10):修:剪藏书签在真实页面上崩溃(
Cannot set properties of null (setting 'value'))。根因:浮层字段在p尚未挂到 document 前就用document.getElementById取值(脱离文档树查不到 → null);同时cb_*id 可能与页面自身元素冲突。修复:所有浮层字段改为p.querySelector作用域内查找 + 字段赋值挪到appendChild之后;并把书签放进 jsdom 真实 DOM 端到端跑通(浮层/填充/选图/提交载荷/结果态 12 项全过)作为验证,verify-clip-bridge.mjs新增静态回归断言(禁未限定 getElementById + 挂载时序)。行为无变化,仅书签代码(seed 文档)修复。v0.16.25(2026-09-10):剪藏桥支持图片剪藏(浮层选图)。书签升级为选择式浮层:可改标题/编辑选中文字,浮层列出页面图片缩略图(自动跳过 <80px 小图标与 data:/blob: 占位、去重,
og:image标「封面」并默认勾选)勾选图片后一键剪藏。图片由桥(DSH 进程侧)下载字节存为二进制附件 tiddler(type: image/*+ base64 正文,即 TW 原生附件形态;clip-url/clip-note溯源),笔记改用 wikitext 用[img[标题]]内嵌展示;某张下载失败自动降级为链接、不阻塞整次剪藏;纯文字剪藏保持原 markdown 路径不变。安全不变(127.0.0.1 + Host 校验 + 可选 token;下载带 referer/UA 应对常见防盗链)。验收新增 image-flow 测试 + 书签语法检查(verify-clip-bridge.mjs24 项全过)。v0.16.24(2026-09-09):新:本地剪藏桥 + 书签小工具。DSH 进程内新增只监听 127.0.0.1 的 HTTP 桥(配置组
bridge.*:enabled默认关、port默认 8618、token可选共享口令、tag默认clip)——浏览器书签(JS 小工具)把当前页标题/URL/选中文字 POST 给它,经唯一写入通道落进 wiki(markdown、重名自动(2)去重、默认clip标签、随 wiki 自动 git commit)。安全:Host 头白名单防 DNS rebinding、CORS/PNA 预检放行(https 页面书签可用)、bridge.token强烈建议设置。附可选 seedclip-bridge:「本地剪藏桥(书签小工具)」说明文档(含书签代码/启用步骤/安全说明/curl 用法,打dsh-docs标签进「📚 插件文档」栏,可反初始化);设置页新增 4 个配置字段。enabled/token/tag设置页保存即生效,改端口需重启 dsh web。v0.16.23(2026-09-09):新:DSH Better Sidebar(dsh-better-sidebar)集成。插件通过
ctx.betterSidebar服务注册 TiddlyWiki 为 Better Sidebar 侧边栏的 tab 类型——+ 菜单点击即以 tab 打开完整 TW 编辑器(同源代理 iframe,与聊天并排);TW iframe 机制抽成共享模块(rightbar/better-sidebar 复用:lazy-load / status 轮询 / 主题同步 / hash 导航 / 互斥协议),回复流 wiki 链接在同一处统一路由到任一可见的侧边 TW tab。配置ui.showBetterSidebarTab(默认 true)可开关;未安装 Better Sidebar 自动跳过。更新后刷新页面即可看到入口。v0.16.22(2026-09-09):seed 体系三层化 + 文档中心起步包。① 分层:核心(自动、不可移除:发送按钮/渲染路由/代理基址)+ 起步(首次安装默认写、可移除:插件说明 + 新增「示例与文档」seed——主题汇总模板/教程/三个示例主题页)+ 可选(手动:首页/所有文章/新增「自定义样式」seed/顶栏主题);所有种子安全跳过(同名 tiddler 已存在绝不覆盖)。② 新增
dsh-docs文档合集约定:所有 seed 文档打该标签,首页「📚 插件文档」tabs 栏自动收录。③ seed 版首页改为通用版(gen-seed-home --strip-private:剥离作者私有人口,注入文档栏)。④ 修:首页快速记笔记的 tags 筛选器 bug(then[[todo]]操作数双括号导致「筛选器错误」被拆成 6 个 tag → 改为then[todo])。v0.16.21(2026-09-09):新:DSH 右侧边栏(rightbar)集成。注册 TiddlyWiki 为右侧栏 tab 类型——rightbar 首页出现「TiddlyWiki 知识库」入口盒,点击即在右侧栏以 tab 形式打开完整 TW 编辑器(同源代理 iframe,跟随 DSH 主题),与聊天并排;配置
ui.showRightbarTab(默认 true)可开关。更新后刷新页面即可看到入口。v0.16.20(2026-09-09):修:
search/recent在大 wiki 上超时。根因:列表请求把全部 tiddler(含图片等二进制附件)的 base64 正文拉回来(2418 个 tiddler ≈ 515MB/17s)。修复:search/recent/get在服务端只取文本 tiddler(无type或text/*);二进制 tiddler 完全排除,get对二进制只回元数据。实测 515MB/17s → 6.24MB/0.3s。v0.16.19(2026-09-07):修:会话「知识库」Tab 把汇总当源码显示——TW 5.4.1 把
$:/temp/条目一律按代码块渲染;改为/tw/render原生片段管线(与回复流工具卡同链路),不再用 iframe/story view。v0.16.18(2026-09-07):README 全面精简重写;seed 优化——首页 seed 跟随 wiki 现状、修「所有文章」回主页死链、doc-note 文案修正。
v0.16.17(2026-09-07):点击快速笔记可选直达 TW 原生编辑页(
ui.quickNoteMode)+ 修「在 TW 中编辑」弹窗 ✕ 关不掉。v0.16.16(2026-09-07):修会话知识库 Tab 误入编辑草稿显示源码——三层防误编辑(清残留草稿/吞草稿创建/禁 ✏️)。
v0.16.15(2026-09-07):
put/batch_put未指定类型自动默认text/markdown;警告fields.type是内容类型保留字段。v0.16.14(2026-09-07):修知识库 Tab「佚失条目」根因——浏览器端 TW 天生排除
$:/temp,改为 iframe 就绪后注入 + 原生 hash 导航。v0.16.11(2026-09-06):新增会话顶部「知识库」Tab(本会话相关 wiki 汇总,volatile
$:/temp)。v0.16.0(2026-09-05):回复流原生 TW 工具卡片 + 可点击 wiki 链接(新增
render-routeseed)。v0.15.0(2026-09-05):初始化不强制 + 可反初始化(seed 拆核心/可选两层)。
v0.14.0(2026-09-05):「发送给 Agent」按钮独立图标 + 附加说明 + 权限选择。
v0.13.0(2026-09-04):menubar 顶栏主题自适应。
v0.12.0(2026-09-04):新默认主页 + 「所有文章」两列分页页。
v0.11.0(2026-09-04):「发送给 Agent」支持选择工作模式(Agent 预设)。
v0.10.0(2026-09-04):统一 seed 注册表 + 设置页「初始化」。
v0.8.0(2026-09-04):嵌入式 TW 跟随 DSH 深浅主题。
v0.7.0(2026-09-03):TW 一键把当前笔记发送到 dsh 会话。
v0.6.0(2026-09-03):同源代理(远程访问核心)。
v0.5.0(2026-09-03):Agent 工具扩充 + 快速笔记草稿自动保存 + 统一知识库 FAB。
📦 发布
npm publish # 版本号在 package.json;文件白名单见 files 字段
tiddlywiki 依赖体较大(含全部语言包/插件)。
🔗 仓库与发布元数据
- GitHub:https://github.com/bbqisbbq/dsh-tiddlywiki
- npm:
dsh-tiddlywiki(https://www.npmjs.com/package/dsh-tiddlywiki) - 说明笔记、首页、示例文档、样式等预置内容由 seed 机制写入 wiki(见 🧩 初始化)
- MIT;Node ≥ 22;GitHub topics:
dshdsh-plugintiddlywikiknowledge-basenote-takinggit-syncagent-tools等
vshulcz/deja-vu
mnemon-dev/mnemon
syncable-dev/memtrace-public
huiliyi37/dsh-tianshu-tui
xiehuan123/dsh-deepread
PerryLink/dsh-plugin-guide
1na-ko/dsh-hdc-bridge
1841220388zzzcccxxx-star/dsh-git-graph