dsh-tiddlywiki 0.19.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,8 @@
26
26
  | 🏠 **文档中心起步包** | 首次安装自动 seed:插件说明 + 「示例与文档」(主题汇总模板 / 教程 / 三个示例主题页),首页「📚 插件文档」栏一键查阅;**同名 tiddler 已存在一律安全跳过,绝不覆盖你的数据**(v0.16.22) |
27
27
  | 🎨 **自定义样式** | 「自定义样式」seed:编辑器美化 / 窄屏侧栏隐藏 / menubar 加高 / 批注弹窗等 5 张通用样式表,新 wiki 也能一键初始化(可选,v0.16.22) |
28
28
  | 🤖 **Agent 工具** | 15 个 `tiddlywiki_*` 工具:检索(**相关度排序 + 命中处片段 + 字段过滤**)、读写、**增量追加**、批量、重命名、**软删除/回收站**、**反向链接**、**附件入库**、**知识库体检**、git 同步与冲突解决(v0.19.0;检索/最近仍在**服务端**排除二进制附件,大 wiki 上从 515MB/17s 降到 ~0.4s) |
29
- | 🛡️ **不会被覆盖的写入** | `tiddlywiki_put(..., expectedModified)` 乐观并发:读取后若有人(在 TW 编辑器里)改过,写入被拒绝而不是静默覆盖;`tiddlywiki_delete` 默认**软删除进回收站**,`tiddlywiki_trash` 可恢复(v0.19.0) |
29
+ | 🛡️ **不会被覆盖的写入** | 所有写入路径(agent 工具 **与** 快速笔记/编辑器路由)都**先读后写**:不传 tags 就保留原有标签与自定义字段;`tiddlywiki_put(..., expectedModified/expectedRevision)` 乐观并发——读取后若有人(在 TW 编辑器里)改过,写入被拒绝(HTTP 409)而不是静默覆盖;`tiddlywiki_delete` 默认**软删除进回收站**,`tiddlywiki_trash` 可恢复(v0.19.0 / v0.19.1) |
30
+ | 🧼 **渲染片段净化** | 回复流卡片与会话汇总注入的 TW 片段先经 **host 白名单净化**(丢 `iframe`/`script`/`svg`/`on*`/`javascript:`/`data:text/html` 等)——TW 自己的解析器只剥 `on*`,`<iframe src="javascript:…">` 会原样通过并在 DSH 页面里执行(v0.19.1 修复的存储型 XSS) |
30
31
  | 🔒 **写路由方法校验** | 每个写路由只接受自己的 HTTP 方法:跨站 `GET /sync`、`GET /restart`、`GET /upload` 一律 405 且无副作用(v0.19.0 修复了「任意网页一张 `<img>` 即可触发 pull/commit/push」的 CSRF 面) |
31
32
  | 📊 **回复流卡片** | 工具结果显示原生 TW 卡片(**按笔记自己的内容类型渲染**:Markdown 笔记就是 Markdown,v0.18.0);`[标题](/dsh-tiddlywiki/tw/#标题)` 点击直达 TW 面板 |
32
33
  | 📤 **发送给 Agent** | TW 笔记工具栏一键把当前笔记注入所选 dsh 会话(可选工作模式/权限/附加说明) |
@@ -240,6 +241,7 @@ node scripts/gen-seed-ui-styles.mjs '<wiki>/tiddlers/<样式.css>' … src/host/
240
241
  |---|---|---|
241
242
  | `/dsh-tiddlywiki/status` | GET | 面板健康(service/url/git/tag/ui) |
242
243
  | `/dsh-tiddlywiki/note` `/edit` `/tags` `/recent` `/get` `/search` | POST/GET | 快速笔记、打开编辑器、tag/最近/单个/搜索 |
244
+ | `/dsh-tiddlywiki/render` | POST | TW 片段渲染(host 净化后返回,回复流卡片/会话汇总用,v0.19.1) |
243
245
  | `/dsh-tiddlywiki/sync` `/upload` `/restart` | POST | 一键同步、文件上传、重启 TW |
244
246
  | `/dsh-tiddlywiki/session/summary` | POST | 会话「知识库」Tab 汇总 |
245
247
  | `/dsh-tiddlywiki/agent/sessions` `/modes` `/send` `/create` | GET/POST | TW「发送给 Agent」:会话/模式/发送/新建 |
@@ -265,7 +267,7 @@ src/
265
267
  │ ├── config.ts # ConfigStore:cordis config 基底 + 配置 tiddler 覆盖层
266
268
  │ ├── seeds.ts # 统一 seed 注册表(10 项,三层:核心/起步/可选)
267
269
  │ ├── seed-*.ts # 各 seed 实现(bundle/首页/ui-styles 常量脚本生成;starter-docs/menubar/clip-bridge 手工维护)
268
- │ └── tools.ts # 10 个 tiddlywiki_* 工具(列表式注册)
270
+ │ └── tools.ts # 15 个 tiddlywiki_* 工具(列表式注册)
269
271
  └── client/ # 浏览器半部
270
272
  ├── index.ts # client 入口(inject ['slots'],纯 DOM,永不 throw)
271
273
  ├── endpoints.ts # 客户端同源端点常量
@@ -289,6 +291,8 @@ lib/ # 预构建产物(发布含 lib/**,提交入库;
289
291
 
290
292
  > 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
291
293
 
294
+ - **v0.19.1**(2026-09-11):**第二轮代码审计的修复版 + 让 CI 重新变绿**。**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/*`,并先做实体解码挡 `&#106;avascript:` 这类混淆),新增 **`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 描述同步。
295
+
292
296
  - **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-host` check 不再吞错;重启 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 后新会话生效;客户端改动需刷新页面。
293
297
  - **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` 不再默认打作者本机端口。
294
298
  - **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` 规避冲突。