dsh-tiddlywiki 0.26.5 → 0.26.7
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/LICENSE +21 -21
- package/README.md +3 -1
- package/cordis.patch.yml +13 -13
- package/lib/client.js +27 -27
- package/lib/index.js +89 -17
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/client/endpoints.ts +27 -0
- package/src/client/markdown-editor.ts +128 -128
- package/src/client/note-widget.ts +8 -5
- package/src/client/state.ts +39 -39
- package/src/client/status-cache.ts +7 -0
- package/src/client/toast.ts +22 -22
- package/src/client/tw-frame.ts +20 -4
- package/src/host/http.ts +34 -1
- package/src/host/routes.ts +16 -3
- package/src/host/tools.ts +56 -15
- package/docs/code-review-2026-09-17.md +0 -151
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 dsh-tiddlywiki contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-tiddlywiki contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ dsh plugin --profile web add link:/path/to/dsh-tiddlywiki
|
|
|
101
101
|
| `tiddlywiki_get` | 读单个 tiddler 全文(`modified` 以 ISO 返回,可直接用作 `expectedModified`) |
|
|
102
102
|
| `tiddlywiki_put` | 写/覆盖;**新建**未指定类型时默认 `text/markdown`(`$:/` 系统条目除外),**覆盖既有条目时保留原 `type`/tags/自定义字段**(v0.20.1,改类型要显式 `fields.type`);`expectedModified` + `force` 提供乐观并发保护 |
|
|
103
103
|
| `tiddlywiki_batch_put` | 批量写入(`overwrite=false` 跳过已存在;单条失败不影响其余、逐条报错;4 路并发但结果保持入参顺序) |
|
|
104
|
-
| `tiddlywiki_append` | **增量追加**:`mode=append\|prepend`、`heading=某标题`
|
|
104
|
+
| `tiddlywiki_append` | **增量追加**:`mode=append\|prepend`、`heading=某标题` 定位写入(落点 = 该标题之后、**下一个任意级别标题之前**;CRLF 行尾的笔记同样有效),写日志/批注无需读全文;标题不存在时**不报错但也不再装成功**——追加到文末并返回 `headingMatched=false` + 回执明说;与 `put` 同一套写策略(保留原 `type`/tags/自定义字段,新条目才默认 markdown),支持 `fields` 显式覆盖 |
|
|
105
105
|
| `tiddlywiki_rename` | 重命名 + 尽量同步其他条目里的引用;旧标题删除失败时如实回报「两份副本都在」 |
|
|
106
106
|
| `tiddlywiki_delete` | 删除(幂等)。默认**软删除**进 `$:/dsh-tiddlywiki/trash/`,`permanent=true` 才真删;支持 `expectedModified`/`expectedRevision`/`force` 乐观并发(读后被改动则拒绝,不把人类的新改动丢进回收站) |
|
|
107
107
|
| `tiddlywiki_trash` | 回收站:`action=list\|restore\|empty`(索引读不到或损坏时显式报错,绝不把回收站当空的重建) |
|
|
@@ -419,6 +419,8 @@ lib/ # 预构建产物(发布含 lib/**,提交入库;
|
|
|
419
419
|
|
|
420
420
|
> 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
|
|
421
421
|
|
|
422
|
+
- **v0.26.7**(2026-09-26):**修「DSH 桌面版里 TW 面板没有『添加条目』按钮」——嵌入式 TW 被渲染在自定义 scheme 上,于是它根本没有同步器**。现象(用户报障,桌面版):TW 面板能看能搜,但页面控件里 **添加条目 / 添加日志 / 添加图片 / 导入 / 条目管理器** 整排不见,单条笔记的 **编辑 / 克隆 / 删除** 也不见,像装了个只读版 TW。**根因不在本插件,而在 TW 内核的一处协议判定 + 桌面版新增的渲染 scheme**:TiddlyWiki 自己的 TiddlyWeb sync adaptor 只在**文档协议以 `http` 开头**时才导出自己(`plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js`:`if($tw.browser && document.location.protocol.substr(0,4) === "http")`);而桌面版用自定义 scheme `dsh-app:` 渲染界面(已在本机运行中的 Electron 渲染进程命令行里核实 `--standard-schemes=dsh-app --secure-schemes=dsh-app …`),于是 iframe 里的 TW **没有 syncadaptor → 没有 `$tw.syncer`**:`$:/status/IsReadOnly` 永远没人写,TW 自己的只读样式表 `$:/plugins/tiddlywiki/tiddlyweb/readonly`(`<$reveal … default="yes">`,**状态未知即当只读**)就把那批按钮 `display:none` 掉;同时 saver 退化成本地 `dirtyTracking`,**在那儿做的编辑根本存不回 wiki**。实测复现(不依赖桌面版):把同一份 wiki 页面用 `file://` 打开(同样非 http),+ 同样消失——所以这不是「按钮坏了」,而是「这个文档里 TW 没有同步器」。**修复思路:让嵌入式 TW 跑在真正的 http origin 上**。① 宿主 `/status` / `/edit` / `/session/summary` 在原有相对字段旁,新增**绝对孪生字段** `twProxyAbsolute` / `twUrlAbsolute`(`absoluteHostBase()`,由请求 `Host` 头推导;脏头一律拒绝 `/^[A-Za-z0-9.\-[\]:]+$/`,避免把路径/凭据拼进回给浏览器的 URL);② 客户端新增 `resolveTwUrl()`(`endpoints.ts`)——**页面本身是 http(s) 时继续走相对路径**(loopback / 局域网 / Tailscale / 域名 / HTTPS 行为一字不变,绝不把 https 页面改源),**只有页面不是 http(s) 时**才改用宿主回环 http 基址,于是桌面版 iframe 里 TW 的协议变成 `http:`,sync adaptor 正常加载、同步器回来、按钮与保存一起复原;③ 随之而来的跨源:桌面版下 TW frame 与宿主页面不同源,`tw-frame.ts` 的 hash 导航把「读跨源 `$tw` 抛 SecurityError」包进 try/catch 并直接走整页兜底(不再冒泡、链接不丢),`theme-sync` 本就是 best-effort 跨源静默。守门:新增 `scripts/verify-tw-origin.mjs`(7 条:Host 头推导 / 脏头拒绝 / http(s) 忽略绝对基址 / `dsh-app:`+`file:` 采用绝对基址 / 老服务端不回归 / 两处接线断言 / 跨源兜底源码断言),`verify-frame-surface` 再增 2 条行为单测(`dsh-app:` 页面必须把 frame 指到宿主 http 基址、且 http 页面仍用同源相对地址;跨源 frame 读 `$tw` 抛错时必须整页兜底)。**注意**:这修的是「TW 被非 http(s) 文档嵌入」;「在浏览器里直连 TW 子端口(`http://127.0.0.1:<port>/`)」是另一回事——那样 TW 的 API 基址会被指到 DSH 代理前缀而 404,同样显示成只读,请一律用 DSH 同源入口(面板 / 右侧栏知识库 tab / `<DSH origin>/dsh-tiddlywiki/tw/`)。
|
|
423
|
+
- **v0.26.6**(2026-09-26):**修 `tiddlywiki_append` 的 `heading` 在 CRLF 笔记上完全失效、且静默回退到文末**(作者本机知识库的一篇 25KB / 454 行长笔记上连续踩两次后定位到源码)。现象:对这篇笔记连做两次带 `heading` 的 append,内容**全部**落到了文末,而回执照样打印「段落「X」」——看起来完全成功。**根因**:`insertIntoSection` 用 `base.split('\n')`,而 CRLF 正文的**每一行结尾都留着 `\r`**;JS 里 `(.*)` **不匹配 `\r`**、`$` 也**不匹配 `\r` 之前的位置**,于是 `/^#{1,6}\s+(.*)$/` 对**每一个**标题都匹配失败 ⇒ `start < 0` ⇒ 走「追加到文末」的回退分支。**只在 CRLF 笔记上复现**(纯 LF 笔记一切正常),所以它看起来像偶发;落盘文件的「**376 个 CRLF + 78 个裸 LF**」混合行尾正是走过该分支的签名(`lines.join('\n')` 保留每行原有 `\r`、只把新块用 `\n` 接上)。**修复三处**:① 标题匹配前**只**剥掉行尾 `\r`(原文行尾一个字节都不动;**没有**改成 `split(/\r?\n/)`——那会让每次 append 都把整篇重写成 LF,炸出全文件 diff);② 新块按**文档自己的行尾**写入(`base.includes('\r\n')` 判定),CRLF 笔记不再越写越乱;③ `insertIntoSection` 改为返回 `{ text, matched }`,`tiddlywiki_append` 把它作为 **`headingMatched`** 一并返回,未命中时回执改为「⚠️ 未找到标题「X」,已改为追加到文末」——**不再把「定位失败」伪装成「写进了那一节」**(Agent 因此完全无法自检,这是本 bug 最坑的一点)。顺带把 `heading` 的真实落点语义写进 schema:实为「该标题之后、**下一个任意级别标题之前**」,标题后紧跟子标题时落在两者之间(=章节开头),并非 schema 原先暗示的「整节末尾」。守门:`verify-tools` +4 条 E2E(CRLF 正文的笔记必须 `headingMatched=true` 且标记落在目标段内、段内不得混入裸 LF;未命中必须 `headingMatched=false` 且回执含「未找到标题」、不得再宣称写进该段落;命中时的反向保护;wikitext `!` 标题同样可定位),**已反向验证**(撤掉 lib 里的行尾 CR 剥离即红 1 条)。
|
|
422
424
|
- **v0.26.5**(2026-09-23):**修 P0:`fields` 参数被按字符拆成几十个垃圾字段**(用户实测复现两次后报障)。现象:`tiddlywiki_put` / `batch_put` / `append` 传 `fields: {"review-after":"2026-12-22"}` 后,条目上出现 `0={`、`1="`、`2=r`… 几十个**单字符字段**,真正的自定义字段**一个都没写进去**;又因为 `fields.type` 是**改内容类型的唯一入口**,这期间也无法把条目写成 wikitext / `text/css`。**根因两层**:① 参数 schema 声明为 `{type:'json'}`,而 DSH 的 schema 里 `type:'json'` 是**纯注解**——编译后连 `type` 都没有(`src/sdk.ts` 的 `compileValue`),模型收不到「这是个对象」的信息,于是把 JSON 当**字符串**发来;② 新建笔记 + 自动工作区标记走 `withWorkspaceMark()` 的 `{ ...(fields ?? {}) }`,而**展开字符串是按字符展开**的(`{...'{"r"'}` → `{0:'{',1:'"',2:'r'…}`),这些索引键随后被当成自定义字段写入;旧 `applyCustomFields()` 对非对象又是**静默 return**,所以全程没有任何报错。**修复(三处)**:① 三个写工具的 `fields` schema 改成真正的 `object` + `additionalProperties: true`(模型能直接看到类型);② 新增 `normalizeFieldsArg()`(`write-policy.ts`)——对象原样返回、`undefined`/`null`/空串视同未给(保留基底)、**JSON 字符串解析成对象**(兼容仍按字符串发参的模型)、数组/数字/解析不出对象的字符串**明确抛错**;`defineTool` 相应新增 `normalizeArgs` 钩子,让归一化跑在 schema 预校验**之前**(放到之后会被「must be an object」先拦掉,兼容层就没机会生效);③ `applyCustomFields()` 遇到非对象**抛错**而不是静默忽略,`withWorkspaceMark()` 只为已归一化的对象做展开。守门:`verify-write-policy` +5 条纯函数(字符串解析 / 对象原样 / 三种坏输入拒绝 / 字符串在 `buildWriteTiddler` 处被拦 / 归一化后无索引键),`verify-tools` +4 条 E2E(三个工具的 schema 必须 `type:object`、按字符串发参仍写对字段且不产生 `0=` 垃圾、坏输入明确报错且不留半成品条目、`append`/`batch_put` 走同一套归一化)。**注意**:本次修复只影响写入端;已被写进条目的垃圾字段需要重建该条目(`fields` 只能覆盖、不能删除单个字段),本机知识库已扫描确认无残留。
|
|
423
425
|
- **v0.26.4**(2026-09-23):**修「发送给 Agent」因配置被浏览器自动填充而 404 + 设置页文本框防自动填充**。实测:设置页「TW 端请求基址」(`ui.sendToAgent.endpoint`)被浏览器自动完成当成 URL/账号字段填进 `/dsh-tiddlywiki/tw/root`,于是 send-to-agent 把请求拼成 `/dsh-tiddlywiki/tw/root/agent/sessions`,命中 TW 代理子路径 → 404「获取会话列表失败」。**两层加固**:① 设置页 `textField` 一律 `autocomplete=off`(`tokenField` 早已如此,URL 类文本框 `endpoint`/`git.remote`/`wechat.dsn` 等不再被自动填充污染);② send-to-agent bundle `baseEndpoint()` 校验自定义 endpoint——一旦含 `/tw/`、`/api/`、`/recipes/`、`/files/` 等 TW 子路径或非 origin/根绝对路径(判为浏览器误填),**回退到 `location.origin + "/dsh-tiddlywiki"` 自动推导**,按钮不再因误配 endpoint 而 404。另修 `scripts/gen-seed-send-to-agent.mjs` 模板字符串里一处未转义反引号(`ok:false`)导致再生成 seed 必崩的 bug。bundle send-to-agent 0.3.5→0.3.6。
|
|
424
426
|
- **v0.26.3**(2026-09-23):**修正 starter-docs 教程里一处技术性错误说法**:「方法一」原来写「点标签后 TW 会自动生成该标签的页面,列出所有带此标签的笔记」——这不准确。实测(TiddlyWiki 5.4.1 内核,已核对 `$:/config/ViewTemplateBodyFilters.multids` 与 `$:/core/ui/TagTemplate`):内核**没有**"标签页"这种自动页面,点标签丸/侧边栏标签弹出的是**下拉列表**(`list-tagged-draggable`,全量不分页),直接打开以标签命名的条目只会看到条目本身(缺失则提示),不会自动列出成员笔记。教程现在如实描述弹层行为与它的局限(不分页、不可分享链接),并指出想要「一个页面 + 可翻页」的标签列表应自行写汇总页(笔记多时套分页)。纯 seed 文案修正,不影响任何运行时行为;新装 wiki 的「示例与文档」seed 应用新文案,已有 wiki 不受影响(seed 是 ONE-SHOT)。
|
package/cordis.patch.yml
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# dsh-tiddlywiki bundle patch: inserts the plugin row into the web profile
|
|
2
|
-
# roster. Applied as a profile bundle layer (the `dsh.bundle.patch` manifest
|
|
3
|
-
# field) over dsh-base; activate with
|
|
4
|
-
# `dsh plugin --profile web add link:<path-to-this-package>` and restart dsh web.
|
|
5
|
-
#
|
|
6
|
-
# The row is a bare plugin by package name: the node half (exports ".") runs
|
|
7
|
-
# in the host process (WikiServer, routes, tiddlywiki_* tools, prompt section,
|
|
8
|
-
# auto-commit), and the `dsh.client` declaration in package.json makes the
|
|
9
|
-
# browser half (exports "./client", served at /plugins/dsh-tiddlywiki/client.js)
|
|
10
|
-
# load in the web GUI.
|
|
11
|
-
- insert:
|
|
12
|
-
- id: dsh-tiddlywiki
|
|
13
|
-
name: dsh-tiddlywiki
|
|
1
|
+
# dsh-tiddlywiki bundle patch: inserts the plugin row into the web profile
|
|
2
|
+
# roster. Applied as a profile bundle layer (the `dsh.bundle.patch` manifest
|
|
3
|
+
# field) over dsh-base; activate with
|
|
4
|
+
# `dsh plugin --profile web add link:<path-to-this-package>` and restart dsh web.
|
|
5
|
+
#
|
|
6
|
+
# The row is a bare plugin by package name: the node half (exports ".") runs
|
|
7
|
+
# in the host process (WikiServer, routes, tiddlywiki_* tools, prompt section,
|
|
8
|
+
# auto-commit), and the `dsh.client` declaration in package.json makes the
|
|
9
|
+
# browser half (exports "./client", served at /plugins/dsh-tiddlywiki/client.js)
|
|
10
|
+
# load in the web GUI.
|
|
11
|
+
- insert:
|
|
12
|
+
- id: dsh-tiddlywiki
|
|
13
|
+
name: dsh-tiddlywiki
|