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 持久知识库」提示词可在设置页配置:默认精简版(v0.24.0 起 ~1.9KB,只保留工具 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)而不是静默覆盖或丢进回收站;给了哪个令牌就必须匹配哪个(v0.23.5:两个令牌是 AND 不是 OR——revision 是 TW 的内存计数器、重启会复位,旧逻辑会因此静默放行跨重启的覆盖);tiddlywiki_attach 的同名标题默认拒绝(要覆盖必须 force: true);tiddlywiki_delete 默认软删除进回收站,tiddlywiki_trash 可恢复(v0.19.0 / v0.19.1 / v0.19.5 / v0.23.5)。v0.25.0:tiddlywiki_append / tiddlywiki_rename / tiddlywiki_batch_put(逐条目)也支持并发令牌——它们同样是「读全文 → 整篇回写」,此前没有令牌可传,而注入的提示词恰恰让模型回传 expectedModified;tags: [] 现在表示清空全部标签(此前被当成「未传」而静默保留,模型按 lint 的 junk-tags 建议去清标签时什么都不会发生);tiddlywiki_rename 更新引用时若某个引用者在遍历期间被改动过,跳过它并在回执里报出数量,而不是覆盖它 |
| 🏷 工作区感知的读写 | 新建笔记自动带 ws/<项目名> 标签 + workspace 字段(项目名取自会话工作目录,note.workspaceMark 可关);tiddlywiki_search 因此默认先在本项目里找、区内 0 条才自动扩大到全库并在回执里写明实际范围,query 按空白切词、全部词命中才算(AND)。工作区只是附加标记,绝不改写笔记原有的标签/字段,也只在新建时打(v0.24.0) |
| 🕰 时效性内容只提示不删 | 阶段性笔记(版本记录 / 部署步骤 / 排期 / 临时方案)可声明 valid-until(硬过期)或 review-after(该复查),被取代时写 superseded-by + superseded 标签并保留旧笔记;tiddlywiki_lint 的 stale 检查只报告(含「版本号或 done 标签 + 长期未改动」的候选,明确标注非判定)——淘汰永远由人决定,插件不会自动删除或归档任何笔记(v0.24.0) |
| 🚰 重启不丢写入 | 停/重启 TW 只有一条路:drainThenStop()——排干 syncer 队列之后才停子进程,/restart、/admin/restart、插件/主题变更后的重启、知识库切换、/sync、seed 全部经它(此前其中三条直接杀进程,在一秒内点「重启 TW」会静默丢掉刚写的笔记);排干不完整会在回包里如实报 drained:false,而不是假装没事(v0.24.1) |
| 🕒 时间戳不再丢 | 插件写入的每条笔记都会带上 TW 的 created/modified(17 位紧凑 UTC,与 TW 编辑器逐字节一致):新建 = 两者都取当前时刻,覆盖 = 保留原 created、刷新 modified。此前这两个字段被当成「TW 服务端会补」而丢弃,而服务端从不补——缺 modified 的条目会被 TW 的 sortTiddlers 当空串,在 +[!sort[modified]] 页面上直接沉到最后一名(表现为「新日记没被收录」)。TiddlyWebClient.put() 还有一道兜底,任何写路径都不会写出无时间戳的条目(v0.22.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);[标题](/dsh-tiddlywiki/tw/#标题) 点击直达 TW 面板 |
| 📤 发送给 Agent | TW 笔记工具栏一键把当前笔记注入所选 dsh 会话(可选工作模式/权限/附加说明);成功/失败会弹出提示(v0.20.0 修复:此前提示把自由文本当 tiddler 标题传给 TW notifier,全部静默) |
| 📮 发布到微信公众号(可选,默认关) | 把笔记一键发到公众号草稿箱(可选点发表):TW 渲染 → 补内联样式 → 浏览器自动化复用你已登录的后台会话。绕开官方 API 权限封锁(2025-07 起个人主体账号的发布接口被回收),个人号可用;发表需管理员扫一次码。需额外安装(opencli + 浏览器扩展),插件不替你装;关闭时完全不打扰(不注入提示词、不写文档)。带发布元数据(pub-state/pub-platform/pub-wechat-* + no-publish 标签)避免重发或误发。v0.23.3 起 TW 工具栏有「发布到公众号」按钮(预检 + 进度轮询,只到草稿箱),也可继续用 CLI。见 docs/wechat-publish-setup.md |
| 🧭 内嵌编辑器 | 中央列内嵌完整 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 与草稿避让回归。v0.25.0 再加两道:verify-config-patch(设置页补丁必须过 normalizeConfigPatch:范围夹取 / 类型错误 400 / __proto__ 等危险键拒绝 / 未知键透传)与 verify-tool-views(源码级断言客户端 TOOL_VIEW_KEYS 与 host 注册的工具名完全一致、TOOL_LABELS 全覆盖、工作区前缀与 host 常量相同——此前只靠 AGENTS.md 一句「记得同步」,新增工具时卡片会静默退化成纯文本) |
| 🧩 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)。v0.25.0 补齐:归类含 append(增量写入)/ attach(附件)(此前用 append 写的笔记在这个 Tab 里完全不可见,而注入提示词恰好推荐 append),并新增「🗑 删除 / 回收站」一节;事件日志读不出来的会话会在页面上明说(不再静默吞掉、把「读不出来」显示成「没碰过笔记」);读取改为 4 路有界并发 + 12s 墙钟预算(最坏 375s → 有界,客户端 25s abort 后不再继续压着 TW 打);生成有 3s 单飞/复用;$:/temp 条目被 TW 重启清掉时自愈(三态探测:在 / 被清 / 状态未知——未知不计失败也不清零),另按 3 分钟节拍静默刷新,长期开着也能跟上会话 |
| 📝 快速笔记 | 输入框上方快捷按钮或右下角「知识库」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 防抖) |
| ⚙️ 设置页不再「假装生效」 | v0.25.0 把一批「保存了却不变」的项收敛掉:git.autoCommit/git.debounceMs/git.remote 保存后对运行中的插件立即生效(重建防抖提交器 + 指向新 remote;git.branch 只对首次初始化的仓库有意义,标签里已写明,状态行显示的是真实分支);数值项(端口 / 就绪窗口 / 分页条数 / 防抖毫秒)带 min/max 与字段旁红字,非法值拒绝保存而不是静默夹取;保存被拒(409,例如配置 tiddler 残留冲突标记)时错误持久显示而不是一闪而过的 toast;「没有改动」不再发请求、宿主也不重写配置 tiddler(每次空点保存都给 git 造 diff / 两台机器在 .meta 上冲突);插件/主题/语言的未应用勾选能活过「同步 / 重启」触发的重刷;表单有未保存内容时若配置在别处被改过,保留你的输入并给出显式提示而不是重建表单;微信发布的 command/adapter/token/dsn 补齐 UI(token 是密码型 + 显隐切换,掩码回填照旧) |
📦 安装
# ① 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),按相关度排序(标题命中 > 标签 > 正文命中次数),摘要取自命中处上下文而不是正文开头。v0.24.0:query 按空白切词、全部词命中才算(AND);默认先在工作区内查、区内 0 条才自动扩大到全库,回执里写明实际范围 |
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 守卫;(避免静默覆盖笔记),确认覆盖要传 (tags/自定义字段仍保留) |
知识库同步纪律:
- 开工先
tiddlywiki_git_sync action=pull(rebase + autostash,真冲突会 abort 并报文件)。
- 冲突后用
tiddlywiki_git_resolve 二选一解决,再重新 sync(绝不自动覆盖)。
- 收工
tiddlywiki_git_sync action=sync(pull → commit → push)。
🛡 带着冲突绝不提交(v0.23.4):commit 之前会探测「进行中的 rebase / 未合并路径 / 工作树里残留的冲突标记」,命中就拒绝提交(/sync 返回 409 + 文件名、自动提交只上报一次、/status 与设置页状态行显示「冲突未解决(N 个文件,已阻止提交)」)。这条守卫来自真实事故:autostash 重新应用冲突后 rebase --abort 已无事可 abort,冲突标记留在工作树里被自动提交永久写进了 git 历史(连带插件自己解析不了配置)。删冲突标记的方式:解决后 tiddlywiki_git_resolve(或手动编辑掉 <<<<<<</=======/>>>>>>> 三行)再 sync。
⚙️ 配置文件坏了会拒绝保存(v0.23.4):若 $:/plugins/dsh-tiddlywiki/config 不是合法 JSON(最典型就是残留冲突标记),设置页保存会被拒绝并在页面顶部显示红色横幅——而不是像以前那样拿空配置合并、把你其余的设置(prompt.extra/git.remote/ui.*…)一次抹掉。修好该 tiddler(或删掉它回落 config: 块)后即可正常保存。
🔍 检索/最近跳过二进制附件(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。
🕰 过期内容怎么淘汰(v0.24.0):很多笔记是阶段性的(版本记录、部署步骤、排期、临时方案、一次性口令),过一段时间就不适用了。策略是声明时效 + 人工决定,插件绝不自动删:写这类笔记时带 valid-until: YYYY-MM-DD(硬过期)或 review-after: YYYY-MM-DD(该复查);被取代时写 superseded-by: [[新笔记]] 并打 superseded 标签,旧笔记保留(wiki 是 git 仓库,留着的成本几乎为零,删错的成本很高)。tiddlywiki_lint 的 stale 检查会只报告三类:stale-expired(valid-until 已过)、stale-review(review-after 已到)、stale-candidates(带版本号或 done 标签且长期未改动——明确标注是候选,不是判定)。要清理就自己用 tiddlywiki_delete(默认进回收站,可恢复)。
🏷 新建笔记自动标工作区(v0.24.0,可用 note.workspaceMark: false 关闭):put/batch_put/append 新建条目时会自动带上 ws/<项目名> 标签 + workspace 字段,项目名取自当前会话的工作目录(C:\work\alpha → ws/alpha)。于是 tiddlywiki_search 默认就能「先在本项目里找」,而 field: workspace, value: <项目名> 可以精确按项目过滤。不需要也不应该手动加这两个标记(会在 agent-written 之外重复);内容明显属于另一个项目时,显式传 fields: {"workspace": "那个项目"} 即可(显式值优先,不会被自动值覆盖)。为什么标签要带 ws/ 前缀:裸项目名会和真实业务标签撞车——作者库里 dsh-tiddlywiki 这个标签已挂着 2510 篇导入的书籍章节,去掉前缀会让「在工作区内搜索」返回那 2510 篇。
🧠 注入的系统提示词(可配置)
插件会往每个会话的系统提示词里注入一段「TiddlyWiki 持久知识库」约定(设置页 → 系统提示词):
| 配置 | 作用 |
|---|
prompt.enabled | 关掉后本插件不注入任何文本 |
prompt.mode | slim(默认,v0.24.0 起约 1.9KB):只保留工具 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),(v0.16.19 起 片段管线,与回复流工具卡同链路),链接点击直达中央 TW 面板,不可编辑。
📍 知识库位置(可切换,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、不重装就切。
📮 发布到微信公众号(可选功能,默认关闭,2026-09-17)
这是可选功能:需要额外安装 opencli + Browser Bridge 浏览器扩展,插件不替你装。
开关 wechat.enabled 默认 false——关闭时不注入任何发布相关提示词、也不往 wiki 写
「发布元数据规范」。开启:DSH 设置 →「TiddlyWiki 知识库」→「可选功能:微信公众号发布」。
完整安装步骤与排错见 docs/wechat-publish-setup.md。
把 wiki 里的任意笔记一键发到微信公众号草稿箱(可选直接发表)。整套能力放在 tools/wechat/,不依赖公众号服务端 API——因为 2025-07 起官方已回收个人主体账号的「发布能力」接口权限;本方案改用浏览器自动化复用你已登录的后台会话,所以个人号也能用。
两条路,随便挑一条:
- 点按钮(v0.23.3,日常推荐):开启可选功能后,笔记工具栏出现「发布到公众号」。点它 → 先预检(opencli 在不在、adapter 缺不缺)→ 弹确认框(自动列出
no-publish / pub-state 警告)→「开始存草稿」→ 覆盖层每 2 秒显示进度与日志。只到草稿箱为止,发表请到后台点(需扫码)。背后是宿主进程起一个单并发的后台任务(POST /dsh-tiddlywiki/wechat/publish + 轮询 …/status),标题经 UTF-8 文件(--title-file)传给 adapter——不进 argv,避免 Windows cmd.exe shim 把 & 当命令分隔符、把中文解成乱码。
- 敲命令(等价,适合批量 / 脚本化):
# ① 先按 docs/wechat-publish-setup.md 装好 opencli + 浏览器扩展,并登录公众号
# ② 一次性:装 adapter 到本机 opencli(幂等,会自检扩展/登录状态)
node tools/wechat/install-wechat-adapters.mjs
# ③ 发布(注意必须带 --trace retain-on-failure,原因见下)
opencli weixin publish-note "笔记标题" --trace retain-on-failure -f json
opencli weixin publish-note "笔记标题" --cover ./cover.png -f json # 带封面
opencli weixin publish-note "笔记标题" --preview ./out -f json # 先导出排版预览
opencli weixin publish-note "笔记标题" --publish -f json # 直接发表(需管理员扫码)
# ④ 可选:回填存量「已发布」状态(默认 dry-run)
node tools/wechat/backfill-publish-state.mjs # 看
node tools/wechat/backfill-publish-state.mjs --write # 写
流程:笔记标题 → DSH 的 /render(TW 自己渲染成语义 HTML,含代码高亮)→ wechat-html.js 补内联样式(微信会剥 <style> 和 class,只认内联)→ opencli 驱动后台填表/写正文/传图/设封面/存草稿 →(可选)点发表。
三个要点:
- 必须带
--trace retain-on-failure——不带会对 mp.weixin.qq.com 稳定报 Navigation rejected(实测 trace 开 5/5 成功、关 8/8 失败;这是 opencli 1.8.7 的 bug,--site-session ephemeral 等绕法均无效)。
- 发表必须管理员扫码——后台点「发表」后微信要求管理员微信扫码确认,无法自动化。「一键」的真实含义是「脚本做到填表/排版/上传,你只需扫一次码」。默认走发表(不推送粉丝、不占群发额度),群发请自行在后台操作。
- 图片上传用 DataTransfer 注入,不用
page.setFileInput——后者依赖 CDP Page.fileChooserOpened,本机扩展版本组合下稳定失败;改用页面上下文直接塞 input.files,实测图片真进 mmbiz.qpic.cn。代价是单图 8MB 上限(字节要以 base64 穿过 evaluate)。
换机器还原见 docs/wechat-publish-setup.md(含 opencli / Browser Bridge 扩展安装、扫码登录、排错表)。设计依据与全部实测细节见 docs/plans/2026-09-17-wechat-publish-design.md。
🧩 初始化(一次性预置 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 | 「示例与文档」:主题汇总页·模板 + 教程 + 三个示例主题页(日志/决策记录/排障) | 自动写 |
| publish-spec / wechat-setup / wechat-publish(带 gate) | 只有开启「可选功能:微信公众号发布」才写:发布元数据规范 + 换机还原指南 + 「发布到公众号」工具栏按钮插件(v0.23.3) | 开启后自动写 |
| 🎀 可选(默认不写、设置页手动、可移除,可有可无) | 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
workspaceMark: true # v0.24.0:新建笔记自动带 ws/<项目名> 标签 + workspace 字段(项目名取自会话工作目录)
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 }
wechat: # 可选功能:微信公众号发布(默认关;三条 /wechat/* 路由在关时一律 403)
enabled: false # 开:注入发布约定 + 启动写 3 个 gated seed(元数据规范/换机指南/工具栏按钮)
adapter: "publish-note" # publish-note-imgs = 正文内嵌多图版(需该 adapter 已装)
command: "opencli" # CLI 路径(不在 PATH / 用了别名时填绝对路径)
token: "" # 非空时 /wechat/* 要求请求头 x-wechat-publish-token(按钮自动带)
dsn: "" # adapter 回连 DSH 的基址;空 = 按请求端口推导 loopback
uiLanguage: "" # 留空不干预;"zh-Hans" 自动启用简体
auth:
username: "" # 默认 loopback 匿名;暴露到非回环才需要
password: "" # 非空时插件内置客户端/就绪探测/浏览器代理都带 Basic 认证(v0.18.0 起真正可用)
运行时配置:设置页写入的 $:/plugins/dsh-tiddlywiki/config tiddler 是 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/<样式.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)。
📦 发布
npm publish # 版本号在 package.json;文件白名单见 files 字段
tiddlywiki 依赖体较大(含全部语言包/插件)。
🔗 仓库与发布元数据