dsh-tiddlywiki 0.28.9 → 0.28.10

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
@@ -67,7 +67,9 @@ dsh plugin --profile web add dsh-tiddlywiki
67
67
 
68
68
  ## 🕘 版本记录
69
69
 
70
+ - **v0.28.10**(2026-09-28):**修「图标弹层出现在设置弹窗后面、被遮挡」**(作者 v0.28.9 重启后实测报障)。根因是**层级用错了数**:设置页是 DSH 的 `Modal`,渲染进 portal 且根层就是 `position:fixed; z-index:1000`(`dsh-client-ui-primitives/Modal.module.css`),而我把弹层写成 `z-index:60` —— **`z-index` 只在同一个层叠上下文里比较**,所以"写了 60"看着有值、整层仍被 Modal 盖住。现在改为 **1100**:这不是随手挑的大数,而是 DSH 自己给「锚点在对话框内部的浮层」定的值(`Menu.module.css` 的 `.portal`,注释原话 *"Portaled lists must layer above modal overlays (z 1000) — an anchor inside a dialog still expects its menu on top"*),对齐它即高于 Modal(1000),且与我们自己的 toast(10001) 不冲突。**守门**断言弹层 `z-index ≥ 1100`(已反向验证:改回 60 → 红)。顺带补了一条 `styles.ts` 模板串守门:CSS 正文里出现反引号会让模板串提前结束、构建到一半失败(本仓库踩过两次,v0.28.9 我又踩了一次 —— 在注释里用行内代码记号解释 z-index)。**这条守门的第一版是错的、值得记**:它检查「第一个闭引号之前有没有反引号」,可一旦正文多了反引号,那个反引号**本身就变成了闭引号的位置**,于是"没有反引号"永远成立 —— **用出错的输入去验证出错的解析器,必然假绿**。改成检查「模板串是否被提前截断」(正文须以 CSS 注释开头、以 `}` 结尾;闭引号后必须紧跟正常模块代码),再注入反引号即稳定变红。
70
71
  - **v0.28.9**(2026-09-28):**修「点击图标没有正常弹出」**(作者重启后实测报障)。根因:v0.28.8 的图标弹层只写了 DOM 与接线,**`styles.ts` 里一条 CSS 都没有** —— 弹层照样被 append 到 `document.body`,但它是个无宽高约束的裸块、压在页面底部,视觉上就是「点了没反应」。现在补齐 `.dsh-tw-iconpicker`(含 `position:fixed`——它挂在 body 上,用 absolute 会被页面滚动带走)、8 列网格、格子(含当前项高亮)、分页器与按钮图标位共 12 条规则。**守门一并补强**:`verify-wiki-focus.mjs` 原先只断言「TS 源码里出现过 `dsh-tw-iconpicker` 这个字符串」—— 而 class 名当然会出现在 TS 里(它是 `make()` 的参数),所以组件没样式也照样绿。现在改为**双向**断言:弹层/网格/格子/分页器必须真有 CSS 规则,且 **picker 里 `make()` 出来的每个 `dsh-tw-*` 类都必须在 `styles.ts` 里有下落**(下次再加子元素忘写 CSS 会当场变红)。新断言已反向验证(删掉那段 CSS → 红)。顺带被这条新守门抓出第二处漏写:按钮文字位 `.dsh-tw-settings-iconbtn-label` 也没样式。教训:**断言「某个类名存在」不等于断言「这个组件可用」** —— 渲染型组件的守门至少要跨两个文件,一个说"我生成了这个 DOM",一个说"这个 DOM 有样式"。
72
+
71
73
  - **v0.28.8**(2026-09-28):**多库第五批反馈:图标真能用了、设置页分页了、新会话也能选库了 + 拆大文件**(12 条反馈一次做完)。① **图标选择器用上 DSH 官方图标系统** —— 从 8 个手绘图标扩到 **36 个官方图标**(内联的是上游 path 数据:客户端是纯 DOM、零运行时依赖)+ 8 个自绘 + 一组 emoji,弹出网格 **48 个一页**分页。② **修「选了图标立刻变回默认」** —— 根因在 `/admin/wikis` 的**读取视图漏了 `icon` 字段**:写进去了、读回来是 `undefined`,客户端拿它重渲染就回落默认,看起来完全像"没保存"。补上该字段,并加**源码级守门**钉死它(去掉修复即红)。③ **多库下设置页分页**:十几块面板挤一页既分不清"改这个库"还是"改整个插件"、改完也没有退出口 —— 现在分「**总览 / 本库配置 / 全局**」三个 tab,「插件管理 / 主题管理 / 语言管理 / 初始化」这些 per-库面板**只在点了某个库的「配置」之后**才出现,按钮变成「**退出配置**」;单库安装没有 tab 条,逐字不变。④ **新会话也能选知识库**:选择器此前只长在输入框上方(新会话还没有输入框),现在挂在预设/模式选择旁边 —— 声明感知注入 + 2 秒回落 + `blankOnly`,两种布局不会同时出现两个。⑤ **剪藏可指定落哪个库**(`bridge.wiki`,设置页下拉,留空 = 默认库)。⑥ **回复流卡片、会话「知识库」Tab 按会话作用域取数**:不这样做会出现"A 库的标题在 B 库里渲染成空白卡片"。⑦ **桌面版能起 TW 了**:`process.execPath` 在桌面版里是 Electron,TW 根本起不来 —— 现在按 `DSH_TIDDLYWIKI_NODE` → `where/which node` → `execPath` 解析并缓存,行为级守门进 `verify:unit`。⑧ **代码清理**:`tools.ts` 1913→132、`admin.ts` 1265→24、`index.ts` 1407→1001、`note-widget.ts` 1245→916、`settings-page.ts` 1815→400(全部**纯搬移**,注册顺序与装配顺序逐字保持),并新增 `scripts/lib/source-family.mjs` 让 12 个守门按「模块族」读源码 —— 以后纯搬迁不会再假红。⑨ **复核确认无需改动的两条**:注入提示词本来就是**按会话求值**的(换库后下一步即生效,且读的是那个库自己的 `prompt.*`),15 个工具在多库下全部正常(回执在可见库 >1 时标明库名)。全链路复跑:`typecheck` / `verify:static` / `verify:unit` / `verify:e2e` / `verify:large` 全绿(含真起两个 TW 子进程、3100 条大库 64s)。
72
74
  ① **图标选择器用上 DSH 官方图标系统** —— 从 8 个手绘图标扩到 **36 个官方图标**(内联的是上游 path 数据:客户端是纯 DOM、零运行时依赖)+ 8 个自绘 + 一组 emoji,弹出网格 **48 个一页**分页。② **修「选了图标立刻变回默认」** —— 根因在 `/admin/wikis` 的**读取视图漏了 `icon` 字段**:写进去了、读回来是 `undefined`,客户端拿它重渲染就回落默认,看起来完全像"没保存"。补上该字段,并加**源码级守门**钉死它(去掉修复即红)。③ **多库下设置页分页**:十几块面板挤一页既分不清"改这个库"还是"改整个插件"、改完也没有退出口 —— 现在分「**总览 / 本库配置 / 全局**」三个 tab,「插件管理 / 主题管理 / 语言管理 / 初始化」这些 per-库面板**只在点了某个库的「配置」之后**才出现,按钮变成「**退出配置**」;单库安装没有 tab 条,逐字不变。④ **新会话也能选知识库**:选择器此前只长在输入框上方(新会话还没有输入框),现在挂在预设/模式选择旁边 —— 声明感知注入 + 2 秒回落 + `blankOnly`,两种布局不会同时出现两个。⑤ **剪藏可指定落哪个库**(`bridge.wiki`,设置页下拉,留空 = 默认库)。⑥ **回复流卡片、会话「知识库」Tab 按会话作用域取数**:不这样做会出现"A 库的标题在 B 库里渲染成空白卡片"。⑦ **桌面版能起 TW 了**:`process.execPath` 在桌面版里是 Electron,TW 根本起不来 —— 现在按 `DSH_TIDDLYWIKI_NODE` → `where/which node` → `execPath` 解析并缓存,行为级守门进 `verify:unit`。⑧ **代码清理**:`tools.ts` 1913→132、`admin.ts` 1265→24、`index.ts` 1407→1001、`note-widget.ts` 1245→916、`settings-page.ts` 1815→400(全部**纯搬移**,注册顺序与装配顺序逐字保持),并新增 `scripts/lib/source-family.mjs` 让 12 个守门按「模块族」读源码 —— 以后纯搬迁不会再假红。⑨ **复核确认无需改动的两条**:注入提示词本来就是**按会话求值**的(换库后下一步即生效,且读的是那个库自己的 `prompt.*`),15 个工具在多库下全部正常(回执在可见库 >1 时标明库名)。全链路复跑:`typecheck` / `verify:static` / `verify:unit` / `verify:e2e` / `verify:large` 全绿(含真起两个 TW 子进程、3100 条大库 64s)。
73
75
  - **v0.28.7**(2026-09-28):**会话知识库选择器改成与「快速笔记」同一行 + 单库专属配置项不再在多库下出现**(两条都是作者报障)。① **选择器"没和对话框对齐"** —— 上次的修法方向就错了:`conversation.input.dock` 是**竖向 flex 列,一个条目独占一整行**,选择器和快速笔记是**两个条目**时永远是上下两行,怎么调内边距都不可能并排。现在选择器不再是独立条目,而是由快速笔记条目通过 `scope` 参数渲染在**自己这一行里**(按钮前面),整行统一与输入框右缘对齐,一行只测一次。顺手修掉合并时的一处遗留:选择器组件里还留着上一版的 `alignDockEntry` 自测,并入同一行后会把右内边距补两遍——已移除(`wiki-scope` 也从客户端 slot 表里消失,回归由 `verify-wiki-focus.mjs` 断言"input.dock 只能有一个条目"守住)。② **「侧边栏 TW 入口显示名称」在多库下不该出现** —— 多库时侧边栏是每个库各占一行、各用自己 `wikis.json` 里的显示名,`ui.sidebarLabel` 只喂单库那一行,所以多库下它是个**改了不生效的假配置项**。现在该字段只在单库模式渲染(多库时换成一行说明"去知识库列表改各自的显示名");模式探测失败**回落成单库**(保守:宁可多给一个真能用的字段,也不要因为一次请求失败把设置项藏了),并反向断言不许写成 `!== 'single'`(那会把未知模式误判成多库)。两条守门断言都做了反向验证。
package/docs/CHANGELOG.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  > 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
6
6
 
7
+ - **v0.28.10**(2026-09-28):**修「图标弹层出现在设置弹窗后面、被遮挡」**(作者 v0.28.9 重启后实测报障)。① **根因是层级用错了数**:设置页是 DSH 的 `Modal`,渲染进 portal 且根层就是 `position:fixed; z-index:1000`(`dsh-client-ui-primitives/Modal.module.css` 的 `.root`),而弹层写的是 `z-index:60`。**`z-index` 只在同一个层叠上下文里比较** —— 弹层虽然是 `document.body` 的直接子节点(自己也在根上下文),但 60 < 1000,所以整层被 Modal 盖住:弹是弹了,在设置弹窗**后面**。② **修法**:改为 **1100**。这不是随手挑的"大一点的数",而是 DSH 自己给「锚点在对话框内部的浮层」定的值 —— `Menu.module.css` 的 `.portal`,注释原话:*"Portaled lists must layer above modal overlays (z 1000) — an anchor inside a dialog still expects its menu on top"*。跟它对齐即高于 Modal(1000)、低于我们自己的 toast(10001)。③ **守门**:断言弹层 `z-index ≥ 1100`,并**解析规则体时先剥掉注释**(第一版按字符往后切 400 字符,结果切到了我新写的注释里那句「DSH Modal 的 1000」,解析出 1000 而误报)。已反向验证:改回 `z-index:60` → 红;恢复 1100 → 绿。④ **顺带补 `styles.ts` 模板串守门**:CSS 正文里的反引号会让 `CSS_TEXT` 提前结束,`typecheck` 报 TS1005、而 `lib/` 已被 `clean-lib` 删掉(构建到一半失败)。本仓库踩过两次(v0.25.0 注释里引 `.dsh-tw-settings`;v0.28.9 我在解释 z-index 时又写了一次)。⑤ **这条守门的第一版是错的,值得单独记**:它检查「第一个闭引号之前有没有反引号」—— 可一旦正文多了一个反引号,**那个反引号本身就变成了"闭引号"的位置**,body 在它之前就结束了,于是"body 里没有反引号"**永远成立**:注入反引号反而让断言更容易通过。**用出错的输入去验证出错的解析器,必然假绿。** 改成检查「模板串有没有被提前截断」——正文须以 CSS 注释开头、以 `}` 结尾,且闭引号之后必须紧跟正常模块代码(`/**` / `import` / `const` …)。再注入反引号即稳定变红。⑥ 复核:`typecheck` / `build`(`client.bundle.js` 704856 字节,并确认 `z-index:1100` 进了 bundle)/ `verify:static` / `verify:unit` / `verify:e2e` / `verify:large` 全绿。
7
8
  - **v0.28.9**(2026-09-28):**修「点击图标没有正常弹出」**(作者重启后实测报障)。本版只有一个修复,但值得单独发一版:它暴露的是**守门的失效模式**,不是普通的漏写。① **现象**:设置页知识库列表里点「图标」,弹层没有出现。② **根因**:v0.28.8 的 `settings-icon-picker.ts` 生成了完整 DOM(弹层 / 网格 / 格子 / 分页器)、接线也对,**但 `styles.ts` 里一条 CSS 都没有** —— 弹层照样被 append 到 `document.body`,而它是个无宽高约束的裸块、压在页面最底部,视觉上就等于「点了没反应」。③ **修复**:补齐 12 条规则 —— `.dsh-tw-iconpicker`(含 `position:fixed`:弹层挂在 body 上,用 absolute 会被页面滚动带走、也受祖先 overflow 影响)、`min(420px, 100vw-24px)` 宽度与 `max-height` 上限、8 列网格、格子悬停与当前项高亮、名称省略(8 列必须对齐)、分页器分隔线,以及按钮的图标位与文字位。④ **守门为什么没拦住(本版最重要的部分)**:`verify-wiki-focus.mjs` 原本断言的是 `assert.match(settings, /dsh-tw-iconpicker/)` —— 检查「TS 源码里出现过这个字符串」。但**类名当然会出现在 TS 里**(它是 `make('div', 'dsh-tw-iconpicker')` 的参数),所以组件一条 CSS 都没有时这条断言照样绿。**通用教训:断言「某个类名存在」不等于断言「这个组件可用」。** 渲染型组件的守门至少要跨两个文件——一个说「我生成了这个 DOM」,一个说「这个 DOM 有样式」。⑤ **新守门(双向)**:弹层 / 网格 / 格子 / 分页器四个类必须真有 CSS 规则;并且从 picker 源码里**解析出所有 `make()` 生成的 `dsh-tw-*` 类名**,逐个要求它们在 `styles.ts` 里有下落 —— 这条通用网能拦住「下次再加子元素、又忘了写 CSS」。**已反向验证**:删掉那段 CSS → 红;恢复 → 绿。⑥ **新守门当场抓出第二处漏写**:按钮的文字位 `.dsh-tw-settings-iconbtn-label` 同样没有样式。⑦ 复核:`typecheck` / `build`(`client.bundle.js` 701305 → **704155 字节**,并确认 CSS 真进了 bundle)/ `verify:static` / `verify:unit` / `verify:e2e` / `verify:large` 全绿。
8
9
  - **v0.28.8**(2026-09-28):**多库第五批反馈(12 条一次做完)+ 拆大文件**。① **图标选择器接上 DSH 官方图标系统**(反馈 1)—— 从 8 个手绘图标扩到 **36 个官方图标**:没有 `require` 上游的 React 图标组件(客户端是纯 DOM,那样会引入运行时依赖、还会让改名对不上),而是把**上游的 path 数据内联**进 `src/client/wiki-icon.generated.ts`(由 `scripts/gen-wiki-icons.mjs` 生成,`scripts/extract-dsh-icons.mjs` 是取图素材的开发助手);实心图标(data / plugin / settings / dark)与线性图标分两套渲染。弹出网格 **48 个一页**分页,另有 8 个自绘图标与一组 emoji。守门断言 host↔client 的图标名单**双向完全一致**(少一个即红)。② **修「选了图标立刻变回默认」**(反馈 2)—— 根因是 `/admin/wikis` 的**读取视图漏了 `icon` 字段**(`buildWikisView()` 逐字段手写,加字段时漏了一处):写进 `wikis.json` 了,读回来是 `undefined`,客户端拿它重渲染就回落默认图标 —— 症状"完全像没保存"。补上 `...(entry.icon !== undefined ? { icon: entry.icon } : {})`,并加**源码级守门**钉死该字段(去掉修复即红)。③ **多库下设置页按作用域分页**(反馈 3/4/11)—— 十几块面板挤一页,既分不清「改这个库」还是「改整个插件」,改完也找不到退出口。现在分「**总览 / 本库配置 / 全局**」三个 tab;「插件管理(自带官方插件)/ 主题管理 / 语言管理 / 初始化」这些 **per-库** 面板只在你点了某个库那一行的「配置」之后才出现(此前它们和全局项混排,看着像所有库共用一个设置);「配置」按钮变成**开关**(再点 = 退出配置),顶部「配置作用域」条一直显示正在改哪个库。**单库安装没有 tab 条**,就是原来那一页。④ **新会话也能选知识库**(反馈 9)—— 选择器此前只长在 `conversation.input.dock`(新会话还没有输入框)。现在挂在**预设/模式选择旁边**:先声明式探测 `conversation.input.selector.context`,2 秒内没等到就回落到 dock,两条路径带 `blankOnly` 互斥,不会同时出现两个。⑤ **剪藏可指定落哪个库**(反馈 8)—— 新增 `bridge.wiki` 配置与设置页下拉(留空 = 默认库)。剪藏来自浏览器书签、没有"当前会话"可以跟随,所以这里必须是**显式钉死**;填了不存在的 id 时 `/clip` 回执会带 `wiki` 字段说明实际落点,插件日志也提示一次。⑥ **回复流卡片与会话「知识库」Tab 按会话作用域取数**(反馈 7/10)—— 卡片取数 / 链接 / 缓存 key / 汇总的存在性探测与渲染全部带上会话作用域的那个库;不这样做会出现"A 库的笔记标题在 B 库里渲染成空白卡片"。工具卡片右上角还会显示库名徽标。⑦ **桌面版能起 TW**(反馈 12)—— TW 子进程需要真正的 `node`,而桌面版里 `process.execPath` 是 Electron。现在按 `DSH_TIDDLYWIKI_NODE` → `where node` / `which node` → `process.execPath` 的顺序解析并缓存,启动日志写明用了哪个;新增 `scripts/verify-desktop-node.mjs` 做**行为级**断言(进 `verify:unit`)。⑧ **复核后确认无需改动的两条**:注入提示词**本来就是按会话求值**的(`systemPrompt.section` 的 text 是函数,DSH 每次装配传入该会话的 agent,插件据此读作用域库的 `prompt.*`)—— 在输入框上方换库,**下一步**就生效,不需要重启或新开会话;15 个 `tiddlywiki_*` 工具在多库下全部正常(可见库 >1 时每条回执由一处包装统一标明库名)。单库安装两条都是逐字节不变。⑨ **代码清理**(反馈 5)—— `tools.ts` 1913→132、`admin.ts` 1265→24(barrel)、`index.ts` 1407→1001、`note-widget.ts` 1245→916、`settings-page.ts` 1815→400,**全部纯搬移**(15 个工具的注册顺序、`apply()` 的装配顺序、所有注释与字符串逐字保持)。配套新增 `scripts/lib/source-family.mjs`:`readFamily()` 把 `<base>.ts` 与 `<base>-*.ts` 拼成一份文本,12 个守门脚本改用它 —— **以后纯搬迁不再假红**(断言的是"规则"而不是"路径")。`verify-frame-guards` 的 runSwitch 断言跟着新形状更新(`disposed` → `deps.isDisposed()`),并顺手收紧成必须命中**那一条**消息(旁边 `repointDefault` 的「已取消修改」曾因前缀相同而误判通过),两条都做了反向验证。⑩ **文档**:`docs/usage.md` 补 `bridge.wiki` / 设置页分页 / 新会话选择器 / 每个库一个图标 / 桌面版 node;`docs/features.md` 补四条能力;README 顶部版本记录同步。**验证**:`npx tsc --noEmit` 全绿、`npm run build` OK(`client.bundle.js` 701305 字节 / 684.9 KB,远低于 900KB 闸门)、`verify:static` / `verify:unit`(26 个脚本)/ `verify:e2e` / `verify:large` 全绿(含 `WIKI FARM BOOT` 真起两个 TW 子进程、`LARGE WIKI` 3100 条 64s)。
9
10
  - **v0.28.7**(2026-09-28):**会话知识库选择器改成与「快速笔记」同一行 + 单库专属配置项不再在多库下出现**(两条都是作者报障)。① **选择器"没和对话框对齐"** —— 上次的修法方向就错了:`conversation.input.dock` 是**竖向 flex 列,一个条目独占一整行**,选择器和快速笔记是**两个条目**时永远是上下两行,怎么调内边距都不可能并排。现在选择器不再是独立条目,而是由快速笔记条目通过 `scope` 参数渲染在**自己这一行里**(按钮前面),整行统一与输入框右缘对齐,一行只测一次。顺手修掉合并时的一处遗留:选择器组件里还留着上一版的 `alignDockEntry` 自测,并入同一行后会把右内边距补两遍——已移除(`wiki-scope` 也从客户端 slot 表里消失,回归由 `verify-wiki-focus.mjs` 断言"input.dock 只能有一个条目"守住)。② **「侧边栏 TW 入口显示名称」在多库下不该出现** —— 多库时侧边栏是每个库各占一行、各用自己 `wikis.json` 里的显示名,`ui.sidebarLabel` 只喂单库那一行,所以多库下它是个**改了不生效的假配置项**。现在该字段只在单库模式渲染(多库时换成一行说明"去知识库列表改各自的显示名");模式探测失败**回落成单库**(保守:宁可多给一个真能用的字段,也不要因为一次请求失败把设置项藏了),并反向断言不许写成 `!== 'single'`(那会把未知模式误判成多库)。两条守门断言都做了反向验证。
@@ -0,0 +1,151 @@
1
+ # 给「另一台旧机器」的整段指令(多知识库迁移)
2
+
3
+ > 用途:把这台机器上**已经落地的多库拆分方案**,同步到另一台仍跑旧版本、单库的机器。
4
+ > 用法:下面「=== 复制开始 ===」到「=== 复制结束 ===」之间的整段,**原样复制**丢给那台机器上的 Agent 会话。
5
+ > 依据:`docs/wiki-split.md`(人读的拆分页)+ `skills/dsh-tiddlywiki-wiki-split/SKILL.md`(Agent 的操作手册)+ 本机实测的 `wikis.json`。
6
+
7
+ ---
8
+
9
+ === 复制开始 ===
10
+
11
+ 我的 dsh-tiddlywiki 知识库要升级成**多知识库(多实例)**方案,并且要**把笔记和插件一起同步过来**。
12
+ 这台机器是旧版本、单库。请按下面做,**每一步先只读体检、报告给我,我确认再动手**。
13
+
14
+ ## 0. 先把版本升到 ≥ 0.28.9(不然多库功能不存在)
15
+
16
+ 1. 先报告当前版本:读 `C:\Users\bbq\.dsh\profiles\web\node_modules\dsh-tiddlywiki\package.json` 的 `version`,
17
+ 以及 `C:\Users\bbq\.dsh\profiles\web\package.json` 里 `dsh-tiddlywiki` 的声明版本。
18
+ 2. 升级(**必须显式指定官方源**,本机默认 `registry.npmmirror.com` 是只读镜像,可能还没有新版本):
19
+ ```
20
+ dsh plugin --profile web up dsh-tiddlywiki --registry=https://registry.npmjs.org
21
+ ```
22
+ 3. 注意:**开发仓库 ≠ 运行时加载的那份插件**。dsh web 实际加载的是 profile 里的副本,
23
+ 所以「改了仓库代码」不会生效,必须走上面的安装命令 + **重启 dsh web**。
24
+ 4. 升完先**重启 dsh web**,再继续。多库功能需要 ≥ 0.28.0;本方案的界面细节需要 ≥ 0.28.9。
25
+
26
+ ## 1. 先做只读体检,不要改任何文件
27
+
28
+ 报告这些数字(命令都只读):
29
+
30
+ - 当前是不是单库:`GET http://127.0.0.1:<DSH端口>/dsh-tiddlywiki/status`,看有没有 `mode` / `wikis[]`。
31
+ (旧版本没有这两个字段 = 单库模式,只有「切换知识库位置」。)
32
+ - 当前 wiki 根目录在哪、指针文件 `C:\Users\bbq\.dsh\dsh-tiddlywiki\location.json` 有没有内容。
33
+ - tiddler 数量、tag 分布 Top-20、`files/` 附件体积与文件数。
34
+ - `git rev-parse --show-toplevel` 与各仓库体积、`git remote -v`。
35
+ - **`git status --porcelain` 必须是干净的**(不干净就先同步完再继续,否则后面搬迁会混在一起)。
36
+
37
+ ## 2. 我这边已落地的目标方案(照这个来,除非我另行说明)
38
+
39
+ **三个库,两套 git 拓扑:**
40
+
41
+ | 显示名 | id | 收什么 | 目录 | git 仓库 | Agent 可见 | 开局自启 | 图标 |
42
+ |---|---|---|---|---|---|---|---|
43
+ | 工作 | `work` | 日常笔记、开发文档、会议/决策记录 | `C:\Users\bbq\.dsh\tiddlywiki\notes\work` | `dsh-tiddlywiki-data`(与个人库**共用**) | ✅ 是 | ✅ 是 | 默认 |
44
+ | 个人 | `personal` | 个人笔记、生活记录、归档的旧日志 | `C:\Users\bbq\.dsh\tiddlywiki\notes\personal` | 同上(共用) | ✅ 是 | ✅ 是 | `briefcase` |
45
+ | 书籍 | `books` | 书籍/语料/扫描件,基本只读 | `D:\corpus\books` | `dsh-tiddlywiki-books`(**独立仓库,且是 private**) | ❌ **隐身** | ❌ 否 | `book` |
46
+
47
+ **关键设计点(这些是有意为之,别"优化"掉):**
48
+
49
+ - **工作 + 个人共用同一个 git 仓库**(`notes/` 是一个仓库,两个库是它下面的两个文件夹)。
50
+ 为什么:`git add -A` 从子目录执行会暂存**整个工作树**,所以**一个仓库只能有一个 committer**;
51
+ 两个库共用仓库 = 一次提交同时覆盖两者,不会互相踩。
52
+ - **书籍库独立仓库且在 D 盘**:语料约 740MB(其中 `files/` 附件 907 个文件 / 364MB),
53
+ 不能背在 60 秒一次的自动提交上。
54
+ 它同时是 **private** 仓库(`dsh-tiddlywiki-books`)。
55
+ - **书籍库 `agentVisible: false`**:Agent 永远碰不到它(检索 / lint / 反向链接 / 会话选择器都不出现)。
56
+ 这是"防检索被语料淹没"的正解。
57
+ - **书籍库 `autostart: false`**:不随 DSH 启动(每个库一个 TW 子进程,约 150MB),
58
+ 在你打开或选中它时才自动拉起来。
59
+ - **书籍的图片放在 wiki 自己的 `files/` 里**(907 个文件 / 364MB),**不要**改成外链或图床 ——
60
+ 必须保证书籍能独立打开、扫描件不裂图。
61
+ - **`wikis.json` 放在每本 wiki 之外**(`C:\Users\bbq\.dsh\dsh-tiddlywiki\wikis.json`),
62
+ 这样它不会随某个库被搬走。
63
+
64
+ **`wikis.json` 的目标内容(结构照抄,路径按那台机器实际情况改):**
65
+
66
+ ```json
67
+ {
68
+ "version": 1,
69
+ "mode": "multi",
70
+ "defaultId": "work",
71
+ "wikis": [
72
+ { "id": "work", "label": "工作", "root": "C:\\Users\\bbq\\.dsh\\tiddlywiki\\notes", "name": "work",
73
+ "agentVisible": true, "autostart": true },
74
+ { "id": "personal", "label": "个人", "root": "C:\\Users\\bbq\\.dsh\\tiddlywiki\\notes", "name": "personal",
75
+ "agentVisible": true, "autostart": true, "icon": "briefcase" },
76
+ { "id": "books", "label": "书籍", "root": "D:\\corpus\\books", "name": ".",
77
+ "agentVisible": false, "autostart": false, "icon": "book" }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ 手写注意:
83
+ - `id` 只能小写字母/数字加 `._-`,且不能是 `status`/`files`/`recipes`/`render` 这类与 TW 根路径撞名的保留字。
84
+ - 两个库不能指向同一目录,**也不能互相嵌套**(外层库的 `git add -A` 会把内层内容一起提交进去)。
85
+ - `name` 是**该 root 目录下的文件夹名**;`name: "."` 表示 root 本身就是库根(书籍库就是这样)。
86
+
87
+ ## 3. 分步执行(每步做完停下来报告)
88
+
89
+ 1. **备份**:给现有仓库打 tag(例如 `pre-split-<日期>`),保证能整体回滚。**旧库一个都不许删。**
90
+ 2. **建目录 / 搬迁**:用 `git mv` 尽量保住历史。
91
+ ⚠️ **`git mv` 不能跨仓库**(会 `fatal: ... is outside repository`)。
92
+ 跨仓库搬迁的正确姿势:先在**原仓库内** `git mv` 到暂存目录并提交(历史保住在原仓库),
93
+ 再物理移动到新位置、在新位置 `git init` 建新仓库。
94
+ 3. **每个库补 `tiddlywiki.info`**(容器根的 `tiddlywiki.info` 要改名让位,例如
95
+ `tiddlywiki.info.container-backup`,否则 TW 会把它当成一个库根)。
96
+ 容器根下原本的 tiddler 要归档挪走(本机挪到了 `notes\_container-root-tiddlers\`,446 个文件)。
97
+ 4. **写 `wikis.json`**(内容见上),`mode: multi`。
98
+ 5. **重启 dsh web**,然后设置页里确认「知识库列表」出现三行。
99
+ 6. **恢复首页**:三库都要有首页 —— `$:/DefaultTiddlers` 指向 `[[🏠 主页]]`,
100
+ 每库各自设 `SiteTitle` / `SiteSubtitle`(工作 / 个人 / 书籍)。
101
+ `🏠 主页` 是 `toc-tabbed-external-nav`,用 `索引` 标签收集索引页。
102
+ 7. **第三方插件恢复**:把原来那批第三方插件**补回每个库**。本机确认要有的 11 个:
103
+ `BTC_TiddlyFlex`、`BTC_resizer`、`dyp_LXGWNeoXiHeiScreenFull`、`Gk0Wk_CPL-Repo`、`kookma_narenj`、
104
+ `kookma_pinboard`、`linonetwo_fira-code-font`、`linonetwo_gallery`、`linonetwo_simple-layout-launcher`、
105
+ `nico_notebook-mobile`、`oeyoews_mermaid`
106
+ (在每库的插件管理里勾选;这些是**经 TW 原生方式装进 wiki 的**,落盘为
107
+ `tiddlers/$__plugins_<author>_<name>.json`,**不会**写进 `tiddlywiki.info`)。
108
+ 8. **校验**:
109
+ - 各库 tiddler 计数与预期一致;
110
+ - 工作库检索**不再命中**书籍语料;
111
+ - 每个库能独立打开、独立提交(`git status` 在各仓库里都干净);
112
+ - 书籍库在会话选择器里**不出现**(隐身生效);
113
+ - 书籍里的扫描图片能正常显示(不是裂图)。
114
+
115
+ ## 4. 软性节点提醒(容易踩的)
116
+
117
+ - **`heading` 定位**:`tiddlywiki_append` 的 `heading` 落点是「该标题之后、下一个任意级别标题之前」,
118
+ 不是整节末尾;**未命中不会静默**,会返回 `headingMatched=false` 并说明已追加到文末。认这个字段。
119
+ - **一切内容改动走插件 API**(`put`/`append`/`batch_put`/`rename`/`delete`),
120
+ **不要**直接用文件工具编辑 `tiddlers/` —— 运行中的插件有内存快照,看不见你的磁盘改动,
121
+ 而且下次写入会用内存版**覆盖**你的改动。
122
+ - **要整篇重写大 tiddler,别让模型复述全文**:用脚本在磁盘上做手术 → `POST /dsh-tiddlywiki/restart`
123
+ (自带 `drainThenStop`,安全)让 TW 重新读盘 → 校验。**前提是先确认 `git status` 干净**,
124
+ 否则重启时的 flush 会把内存里的旧版本写回、覆盖你的手术。
125
+ - **`git pull` 冲突时不要无脑 `keep-local`**:它只改工作区、**那个领先的本地提交没变**,
126
+ 下一次 pull 会重放同一个提交 → 同一个冲突(原地打转)。时间戳-only 的冲突要丢弃本地那个提交。
127
+ - **wiki 指针文件在 wiki 之外**(`location.json`),权限优先级:指针文件 > cordis config > 默认值。
128
+
129
+ ## 5. 我要你先回答我
130
+
131
+ 1. 体检数字(第 1 步那些)。
132
+ 2. 那台机器的实际路径跟我上表里的**哪些不一样**(D 盘存不存在?`notes/` 这个结构适不适合照搬?)。
133
+ 3. 有没有第二块盘 / 书籍库放哪个盘。
134
+ 4. 现有仓库的远端是什么、要不要也拆成两个远端。
135
+
136
+ **我确认之前,不要创建、移动、删除任何文件。**
137
+
138
+ === 复制结束 ===
139
+
140
+ ---
141
+
142
+ ## 附:为什么这样拆(给人看的背景,不用发给那台机器)
143
+
144
+ - **检索被淹没**是本方案的直接动因:书库 4026 个 tiddler + 907 个扫描附件,
145
+ 和日常笔记混在一个库时,Agent 搜一个词前十条全是语料。
146
+ - **`agentVisible: false` 是"彻底隐身"**,不是"优先级低"——检索、lint、反向链接、会话选择器
147
+ 全都不会碰它。比"让 Agent 自己判断"可靠得多。
148
+ - **一个仓库一个 committer** 是硬约束(`git add -A` 的语义),所以「共用仓库」不是偷懒,
149
+ 而是这两个库必须共用才能各自独立提交而不互相踩。
150
+ - 每个库有**自己的一套配置**(各自的 `$:/plugins/dsh-tiddlywiki/config` tiddler),
151
+ 设置页顶部会显示「配置作用域」,不会出现"改了但不生效"。
package/lib/client.js CHANGED
@@ -847,7 +847,16 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
847
847
  .dsh-tw-settings-iconbtn-face > svg { width: 16px; height: 16px; display: block; }
848
848
  .dsh-tw-settings-iconbtn-label { font-size: 12px; }
849
849
  .dsh-tw-iconpicker {
850
- position: fixed; z-index: 60;
850
+ position: fixed;
851
+ /* ⚠️ 1100 —— 不是"随便一个够大的数"。设置页是 DSH 的 Modal,它渲染进 portal
852
+ 且根层就是 position:fixed + z-index:1000(dsh-client-ui-primitives 的
853
+ Modal.module.css)。所以弹层写 z-index:60 会被整个 Modal 盖住:弹是弹了,
854
+ 但在"设置弹窗的后面"(v0.28.9 真机报障)。
855
+ 1100 是 DSH 自己给「锚点在对话框内部的浮层」定的值 —— Menu.module.css 的
856
+ .portal,注释原话:"Portaled lists must layer above modal overlays (z 1000)
857
+ — an anchor inside a dialog still expects its menu on top"。
858
+ 对齐它即高于 Modal(1000),与我们自己的 toast(10001) 不冲突。 */
859
+ z-index: 1100;
851
860
  width: min(420px, calc(100vw - 24px));
852
861
  max-height: min(70vh, 420px); overflow: auto;
853
862
  padding: 10px; border-radius: 12px;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-tiddlywiki",
3
3
  "description": "把 TiddlyWiki 5 变成你和 Agent 共用的本地文档中心(纯文本 + git):你在 DSH 界面里阅读、写作、记日记,Agent 用 15 个 tiddlywiki_* 工具读写同一批笔记;每条笔记都是你能读、能改、能审计、能随时带走的文件——不是自动记忆插件,不做后台抓取。可选一键发布到微信公众号草稿箱。 Turn TiddlyWiki 5 into a document center you and your agent share, in plain text under git — a knowledge base you can read, edit, audit and take with you, not an auto-memory plugin. Mounts via the official dsh plugin system; no DSH source changes.",
4
- "version": "0.28.9",
4
+ "version": "0.28.10",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "dsh",
@@ -856,7 +856,16 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
856
856
  .dsh-tw-settings-iconbtn-face > svg { width: 16px; height: 16px; display: block; }
857
857
  .dsh-tw-settings-iconbtn-label { font-size: 12px; }
858
858
  .dsh-tw-iconpicker {
859
- position: fixed; z-index: 60;
859
+ position: fixed;
860
+ /* ⚠️ 1100 —— 不是"随便一个够大的数"。设置页是 DSH 的 Modal,它渲染进 portal
861
+ 且根层就是 position:fixed + z-index:1000(dsh-client-ui-primitives 的
862
+ Modal.module.css)。所以弹层写 z-index:60 会被整个 Modal 盖住:弹是弹了,
863
+ 但在"设置弹窗的后面"(v0.28.9 真机报障)。
864
+ 1100 是 DSH 自己给「锚点在对话框内部的浮层」定的值 —— Menu.module.css 的
865
+ .portal,注释原话:"Portaled lists must layer above modal overlays (z 1000)
866
+ — an anchor inside a dialog still expects its menu on top"。
867
+ 对齐它即高于 Modal(1000),与我们自己的 toast(10001) 不冲突。 */
868
+ z-index: 1100;
860
869
  width: min(420px, calc(100vw - 24px));
861
870
  max-height: min(70vh, 420px); overflow: auto;
862
871
  padding: 10px; border-radius: 12px;