dsh-tiddlywiki 0.22.3 → 0.22.5

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 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
@@ -193,6 +193,8 @@ seed 是把「wiki 里预置内容」随插件分发的机制:**ONE-SHOT(只
193
193
  branch: "main"
194
194
  note:
195
195
  tag: "inbox" # 快速笔记默认 tag
196
+ startup:
197
+ readyTimeoutMs: 60000 # TW 启动就绪窗口(v0.22.5,5s–600s;超出只警告并继续等,硬上限 = 3×,仍未就绪才判失败)
196
198
  prompt:
197
199
  enabled: true # false = 本插件不注入任何提示词
198
200
  mode: "slim" # slim(默认:只留约定)/ full(+ 由工具注册表实时生成的参数索引)
@@ -222,7 +224,7 @@ seed 是把「wiki 里预置内容」随插件分发的机制:**ONE-SHOT(只
222
224
  password: "" # 非空时插件内置客户端/就绪探测/浏览器代理都带 Basic 认证(v0.18.0 起真正可用)
223
225
  ```
224
226
 
225
- > **运行时配置**:设置页写入的 `$:/plugins/dsh-tiddlywiki/config` tiddler 是 `config:` 块之上的覆盖层(tiddler 优先、随 wiki git 同步),改 note tag / git / ui 开关 / **注入提示词(`prompt.*`)** 都无需动 cordis;**提示词改动保存后立即生效**(section 即时重注册,当前会话下一步生效),剪藏桥端口改动仍需重启 dsh web 重新绑定监听。
227
+ > **运行时配置**:设置页写入的 `$:/plugins/dsh-tiddlywiki/config` tiddler 是 `config:` 块之上的覆盖层(tiddler 优先、随 wiki git 同步),改 note tag / git / ui 开关 / **注入提示词(`prompt.*`)** 都无需动 cordis;**提示词改动保存后立即生效**(section 即时重注册,当前会话下一步生效),剪藏桥端口改动仍需重启 dsh web 重新绑定监听;**`startup.readyTimeoutMs` 对下一次 TW 启动/重启生效**(v0.22.5)。
226
228
  >
227
229
  > **知识库位置是三层**(v0.22.0):指针文件 `$DSH_HOME/dsh-tiddlywiki/location.json` > `config:` 块的 `wikiRoot`/`wiki` > 内置默认(`$DSH_HOME/tiddlywiki` + `main`)。`wikiRoot`/`wiki` 因此是「默认位置」而不是「唯一位置」——设置页切过的位置存在指针文件里(一个在 wiki 之外的文件),所以要换回配置值就点「恢复为配置默认」。
228
230
 
@@ -327,10 +329,11 @@ src/
327
329
  ├── markdown-editor.ts # CodeMirror 6 Markdown 编辑器
328
330
  ├── session-summary.ts # 会话「知识库」Tab(conversation.view 槽位)
329
331
  ├── tool-views.ts # 回复流工具卡片(tool.call.toolview)
330
- ├── theme-sync.ts / panel.ts / sidebar-entry.ts / sync-button.ts / rightbar-tab.ts
331
- │ # 共享 TW iframe 机制在 tw-frame.ts(v0.16.23:lazy-load/status/主题/互斥/live-frame 路由);
332
- │ # TW tab 只注册在 DSH 原生右侧栏(rightbar-tab.ts)
333
- └── settings-page.ts / ui-config.ts / state.ts / styles.ts / toast.ts
332
+ ├── theme-sync.ts / sidebar-entry.ts / sync-button.ts
333
+ │ # 主题同步 / 侧边栏入口 / 同步按钮
334
+ ├── tw-frame.ts # **TW frame 内核(v0.22.4 起唯一实现)**:createTwFrameSurface(skin) 管 lazy-load / status 轮询 /
335
+ │ # 错误与启动态 / 主题同步 / FAB 重载 / hash 导航 / dispose;中央面板与右侧栏共用同一份
336
+ └── panel.ts / rightbar-tab.ts / settings-page.ts / ui-config.ts / state.ts / styles.ts / toast.ts
334
337
  scripts/ # 构建/校验/再生成脚本
335
338
  docs/seed-initialization.md # seed 机制详解(权威)
336
339
  lib/ # 预构建产物(发布含 lib/**,提交入库;零 @deepseek-ai 运行时 import)
@@ -342,6 +345,10 @@ lib/ # 预构建产物(发布含 lib/**,提交入库;
342
345
 
343
346
  > 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
344
347
 
348
+ - **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 的重启断言(窗口热改 + 夹取 + 仍判就绪)。
349
+
350
+ - **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` 的失败属环境问题(手动复核过断言全过),与本版无关。
351
+
345
352
  - **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()` 走真实函数(前缀 / 裸名 / 缺失 / 读失败),静态断言会剥掉注释行以免匹配到自己的说明文字。
346
353
 
347
354
  - **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:{...}}` 对象,导致「发布包内容」检查假失败(与本次改动无关,但会卡住发布流程)。
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