dsh-tiddlywiki 0.28.14 → 0.29.0
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/docs/CHANGELOG.md +2 -0
- package/docs/development.md +41 -18
- package/docs/features.md +2 -2
- package/docs/seed-initialization.md +4 -3
- package/docs/usage.md +2 -2
- package/docs/wechat-publish-setup.md +1 -1
- package/lib/client.js +15 -15
- package/lib/index.js +249 -52
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/knowledge-fab.ts +46 -8
- package/src/client/note-widget.ts +83 -23
- package/src/client/rightbar-tab.ts +5 -0
- package/src/client/session-summary.ts +19 -1
- package/src/client/settings-page-config.ts +9 -0
- package/src/client/settings-page-runtime.ts +1 -6
- package/src/client/settings-page.ts +39 -7
- package/src/client/sidebar-entry.ts +14 -4
- package/src/client/tool-views.ts +5 -2
- package/src/client/wiki-scope.ts +33 -8
- package/src/host/admin-routes.ts +45 -4
- package/src/host/clip-bridge.ts +19 -1
- package/src/host/config.ts +48 -6
- package/src/host/prompt.ts +47 -19
- package/src/host/routes-session.ts +10 -2
- package/src/host/routes.ts +49 -6
- package/src/host/seed-wechat-docs.ts +1 -1
- package/src/host/session-scope.ts +16 -1
- package/src/host/tools-attach.ts +1 -1
- package/src/host/wiki-farm.ts +55 -10
- package/src/host/wiki-instance.ts +18 -5
- package/src/index.ts +22 -2
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
> 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
|
|
6
6
|
|
|
7
|
+
- **v0.29.0**(2026-09-29):**一轮只读审计(门禁全绿、0 个 open issue,问题全在门禁看不到的地方)之后的修复版**——三个 P1 都属"静默作用到错误的知识库",两条守门还是**假绿**。① **快速笔记 native 路径从不解析目标库**(默认 `ui.quickNoteMode=native`):名册与目标库的解析整段写在 `build()` 里,而 native 路径**从不建卡片** —— 于是 `targetWiki` 恒为 `undefined`、`rosterMode` 恒为 `'single'`,在 B 库写作时点「快速笔记」,笔记落进**默认库**、编辑器也是默认库的,而那个本该拦住它的「写入」下拉永远不会出现。修法:解析抽成 `ensureTarget()`(build 之外,两个入口都调),native 路径**先解析、目标库没在跑就拒绝**、再写。守门 `verify-wiki-focus.mjs` 只做源码字符串匹配(匹配的还是 helper 里的实现)→ 新增**调用点/顺序**断言(已反向验证:删掉 `await ensureTarget()` 或漏传 `wikiQuery` 都稳定变红)。② **`?wiki=<已登记但没在跑>` 静默回落默认库**(写路由也是):`targetRuntimeFor()` 注释只论证过"未知 id 回落是为了老书签",却把"已登记但没运行"一起回落了 —— 设置页写着「正在配置:books」却把配置写进默认库、`/admin/info` 改的是默认库的 `tiddlywiki.info`、`/sync`/`/restart` 动的是默认库。现在**未知 id 仍回落**(老书签不能 404),**已登记但没在跑一律 503 并点名那个库**(与 `/tw/<id>/` 代理早已给出的 503 语义一致);判断只有一份实现(`stoppedWikiFromRequest()` / `stoppedWikiMessage()`),`admin-routes` 的 state/info/config/prompt/seeds 先查 `targetProblem`,routes 侧 status/note/edit/sync/restart/upload 同样。③ **启动自举有两处裸 `server.restart()`**(`pluginAdded` 与 `uiLanguage` 分支)绕过 `drainThenStop()` —— 而守门用 `indexOf` 只看**第一处**,数不到它们。现在自举(含 seed 分支与 `start()` 的卸载中止)全部走 `instance.restart()` / `drainStop()`,`verify-restart-drain.mjs` 改成**枚举全部调用点**:每一个 `server.restart()/stop()` 都必须落在 `drainThenStop` 的 stop 回调里(`dispose()` 是唯一例外)。④ **注入提示词去重瘦身(1918 → 1011 字符,−47%)**:删掉与工具 description 逐字重复的句子(写入/并发 4 条 → 1 条;工作区标记、先窄后宽、多词 AND 交还 `put`/`search` 的 schema;intro 里手写的工具类别清单也删了,那是唯一还会漂移的副本),预算 2100 → 1200。**安全网换成 schema 侧断言**:`verify-prompt.mjs` 新增"委派的规则必须在工具 description 里",删一处可以、**两处一起删立刻红**(`attach` 的同名拒绝原本只写在提示词里,已补进它的 description)。⑤ **其余 P2**:卡片正文缓存失效时补上 wikiId(删除/批量写入后最多 5 分钟还能读到旧正文)、FAB 名册在打开菜单前对账(新增/移除/改名/启停库后不再显示过期清单)、会话「知识库」Tab 订阅作用域变化(切库后不再挂 3 分钟旧库内容)、`data-dsh-tw-wiki` 表达"host 实际服务的那个库"(多库下无显式作用域时不再跟随 GUI 焦点 → v0.28.11 报障的后半)、`catalogPending` 与配置表单重建键带上库作用域(A 库的勾选/脏补丁不再应用到 B)、侧边栏高亮按**完整名册**解析(焦点库没在跑时不再高亮错行/点成切换)、右侧栏 tab 创建即应用可见性、剪藏桥写入串行化(连点两次不再互相覆盖)、`session-scope`/`ConfigStore.set` 的读失败不再被当成"没有"(前者会丢其它会话作用域、后者会把配置写成只剩本次改动——铁律 #3)。⑥ **文档**:`usage.md` 删掉已删除的"2 秒回落"(它在教一个修掉的回归)、seed 表补 `wechat-publish`(13 项)、路由表补 `/admin/wikis` `/session/wiki` `/wechat/*` `/tw/<id>/` 并修正只读路由的方法、项目结构补 v0.28.8 拆出的模块、"重启只有一条路"按新实现改写。
|
|
8
|
+
|
|
7
9
|
- **v0.28.14**(2026-09-29):**修「点击切换知识库感觉会卡那么一下」**(作者报障,接在 v0.28.13 之后)。① **先量再改**(不然只是猜):`/status` 每次要 host 跑最多 5 个 git 进程(本机实测冷缓存 **300–400 ms**);而换库后的 TW 文档本身是 **9.9 MB / 29.9 MB / 28 MB**(三个库实测),并且 TW 自己回 `Cache-Control: no-store`、没有 `ETag` —— **既缓存不了也预取不了**。② **两段来源分开处理**:内核的焦点订阅原来只调 `doRefresh()`,而它**先等一次 `/status` 往返**才动 iframe —— "点下去"到"真的开始换"之间于是空了 0.3–0.4 秒,紧接着才是那份大文档的下载与解析。现在新增 `switchFrameNow()`:焦点一变就**同步**用上一次 `/status` 的 payload(`mode` + 代理基址 + 名册)把 iframe 指到新库,`doRefresh()` 退为**后台对账**(不再挡在点击与界面反应之间);拿不到可用 payload 时它什么都不做,行为与 v0.28.13 逐字一致。③ **侧边栏不再重复打 `/status`**:焦点变化原来会重跑一遍 `applyRoster()`(再打一次 `/status` + 重建所有行 + 重走放置逻辑),可名册根本没变、变的只是哪一行亮着;现在收成 `paintFocus()`,只重画高亮。④ **给可见说明**:换文档期间在 TW 界面底部挂一条 `正在载入知识库「个人」…`(`.dsh-tw-loading`),新文档 `load` 到达即收起,并留 **15s 兜底**(`load` 不来时不能把"正在载入"永久挂在界面上);`showError` / `showStarting` / `setVisible(false)` 三条路径也都会收掉它。提示条是 view 的**最后一个孩子**,刻意**不碰** `frame` 的显隐规则(那条"未载入 TW 地址就绝不显示 frame"是 v0.22.3 的血债)。⑤ **剩下还能不能更快**:不能 —— 剩下的时间全是 TW 自己的文档大小(10–30 MB、`no-store`),不是这套代码能缩短的;面板与右侧栏共用同一条提示。**守门**:`verify-frame-surface.mjs` 新增 2 条**行为级**单测(把 `/status` 打桩成**永不返回**后切库:`frame.src` 必须**已经**指到新库,且提示条可见、写明目标库名、`load` 后收起、15s 兜底收起);`verify-wiki-focus.mjs` 新增 1 条源码级(`switchFrameNow()` 必须早于 `doRefresh()`,订阅里不许 `await`;侧边栏焦点变化不许重跑名册 —— 反断言跑在**剥掉注释**的代码上;提示条必须**真有 CSS**,v0.28.9 的教训)。**已反向验证**四种注入(退回"只 doRefresh" / `load` 后不收提示 / 焦点重跑名册 / 提示条没有 CSS)都稳定变红,恢复即绿。单库安装行为逐字不变。
|
|
8
10
|
|
|
9
11
|
- **v0.28.13**(2026-09-29):**修「左侧多 wiki 入口有时候要点两次才能切到对应的库」**(作者报障)。① **症状**:面板正开着「工作」时点侧边栏「个人」那一行,得点两次才切过去。② **根因**:入口行的点击**一律**走 `state.toggle()` —— `setFocusWiki()` 确实把焦点换过去了(内核也开始换库),但**同一击**里的 toggle 又把面板关掉;用户看到的只是"面板没了",于是再点一次。开着面板时点**另一个**库,用户要的是切换,不是关面板。③ **修法**:判定收成一个纯函数 `resolveEntryClick()`(面板关着 → `open`;开着且就是当前显示的那个库 → `close`;开着但是别的库 → `switch`),副作用收进 `applyEntryClick()`;`switch` 只切焦点、面板保持打开,换库仍由焦点订阅驱动内核重载(`tw-frame.ts`)。**两条顺序/同源要求**:(a) 判定必须在 `setFocusWiki()` **之前**求值 —— 反了的话刚切过去的那个库会被当成"面板此刻显示的就是它"→ 判成 `close`,等于没修;(b) 行**高亮**与点击判定改用同一个解析 `shownWiki()` —— 原来高亮那一路把 `defaultId` 传成了 `undefined`,焦点还没显式设过时会点亮**第一行**而不是默认库;高亮与点击语义不一致时,"点看起来没亮的那一行"就会变成关面板(同一个报障的第二个来源)。④ **守门**:`verify-wiki-focus.mjs` 新增两条 —— 判定表(7 个用例,含单库那一行)与**行为级**用例(真 `PanelState` + 真 `setFocusWiki`,直接断言本次报障的原始场景:"面板开着时点另一个库,面板必须仍开着且焦点已切过去"),另加源码级反向断言(入口行里不得再出现 `toggle()`、判定必须在切焦点之前求值)。**已反向验证**:注入旧行为(切换判成关闭 / 退回无条件 toggle / 把判定挪到切焦点之后)三种改法都稳定变红。**单库安装行为逐字不变**(那一行没有 `wikiId`,仍是纯粹的开关)。⑤ **顺带修好一个长期红着没人看的守门**:`scripts/smoke-client.mjs`(CI 里那条「client bundle module-loader 形状」检查)的 React 替身缺 `createContext`,而 `src/client/tool-views.ts` 自 v0.28.8 起在**模块作用域**调用 `React.createContext(...)` —— 这个脚本于是每次都抛 `c.createContext is not a function`(已在 HEAD 的 `lib/client.js` 上复现确认,与本次改动无关),等于**从那时起就在 CI 里空转**。补全替身(`createContext`/`useContext`/`useMemo`/`useCallback`/`useLayoutEffect`/`forwardRef`/`memo`)并在注释里写清「stub 漏一个 API 就是漏一次检查」。
|
package/docs/development.md
CHANGED
|
@@ -10,7 +10,7 @@ npm run typecheck # tsc --noEmit
|
|
|
10
10
|
npm run build # clean + host tsdown + client tsdown + wrap(wrap 会校验 id 与体积 <900KB)
|
|
11
11
|
npm run selftest # headless:spawn TW → REST 读写 → git → 退出回收
|
|
12
12
|
npm run smoke:client # client bundle 的 module-loader 形状冒烟
|
|
13
|
-
npm run verify # = verify:static + verify:unit + verify:e2e(本地一键;CI 同款分档)
|
|
13
|
+
npm run verify # = verify:static + verify:unit + verify:e2e + verify:large(本地一键;CI 同款分档)
|
|
14
14
|
npm run verify:large # 3000+ 条目大 wiki:检索耗时 / 二进制零出现 / 真跑 commit(约 1 分钟)
|
|
15
15
|
node scripts/verify-send-to-agent-bundle.mjs # bundle 字段 + 源件逐字一致
|
|
16
16
|
node scripts/verify-seed-send-to-agent.mjs # 全新 wiki 上的 seed E2E
|
|
@@ -20,7 +20,7 @@ node scripts/verify-prompt.mjs # 注入提示词守门(slim 无参数
|
|
|
20
20
|
node scripts/verify-wiki-switch.mjs # 运行时切换知识库 E2E(真起 TW:切换 / 回滚 / 指针文件 / 非法输入,v0.22.0)
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
> 📦 从 **npm
|
|
23
|
+
> 📦 从 **npm 包**安装的用户拿到的是 `lib/` + `src/` + `docs/` + `skills/` + `tools/` + `cordis.patch.yml` + README/LICENSE(`scripts/` 不在发布包里,避免把构建脚本塞进依赖树)——想跑上面的验收脚本请用 git 仓库:`git clone https://github.com/bbqisbbq/dsh-tiddlywiki && npm install`。
|
|
24
24
|
|
|
25
25
|
**改 bundle/seed 的再生成流水线**(不要手改 `seed-*.ts` 里的生成常量;bundle 版本号只在 `scripts/bundle/versions.mjs` 定义一处):
|
|
26
26
|
|
|
@@ -52,56 +52,79 @@ node scripts/gen-seed-ui-styles.mjs '<wiki>/tiddlers/<样式.css>' … src/host/
|
|
|
52
52
|
|
|
53
53
|
| 路由 | 方法 | 用途 |
|
|
54
54
|
|---|---|---|
|
|
55
|
-
| `/dsh-tiddlywiki/status` | GET | 面板健康(service/url/git/tag/ui
|
|
56
|
-
| `/dsh-tiddlywiki/note` `/edit`
|
|
55
|
+
| `/dsh-tiddlywiki/status` | GET | 面板健康(service/url/git/tag/ui + 知识库名册 `mode`/`defaultId`/`wikis[]`) |
|
|
56
|
+
| `/dsh-tiddlywiki/note` `/edit` | POST | 快速笔记、打开编辑器 |
|
|
57
|
+
| `/dsh-tiddlywiki/tags` `/recent` `/get` `/search` | **GET** | tag / 最近 / 单个 / 搜索(只读:`rejectNonRead`,POST 会 405。列表路由都支持 `limit`;`/tags` 另支持 `sort=alpha\|count` 与 `total`/`truncated`,v0.19.4) |
|
|
57
58
|
| `/dsh-tiddlywiki/render` | POST | TW 片段渲染(host 净化后返回,回复流卡片/会话汇总用,v0.19.1) |
|
|
58
59
|
| `/dsh-tiddlywiki/sync` `/upload` `/restart` | POST | 一键同步、文件上传、重启 TW |
|
|
59
60
|
| `/dsh-tiddlywiki/session/summary` | POST | 会话「知识库」Tab 汇总 |
|
|
61
|
+
| `/dsh-tiddlywiki/session/wiki` | GET/POST | 会话级知识库作用域:读 = 当前选择 + 解析结果(`scope`/`resolved`/`reason`/`mode`,v0.29.0 起带 `mode`);写 = 选择或清空(v0.28.0) |
|
|
60
62
|
| `/dsh-tiddlywiki/agent/sessions` `/modes` `/send` `/create` | GET/POST | TW「发送给 Agent」:会话/模式/发送/新建 |
|
|
63
|
+
| `/dsh-tiddlywiki/wechat/ready` `/publish` `/publish/status` | GET/POST | 公众号发布(可选功能,`wechat.enabled` 关闭时一律 403,v0.23.3) |
|
|
61
64
|
| `/dsh-tiddlywiki/api/*` | any | 透传 TW 服务(JSON) |
|
|
62
|
-
| `/dsh-tiddlywiki/tw/*` | any | 同源 TW
|
|
65
|
+
| `/dsh-tiddlywiki/tw/*` | any | 同源 TW 代理(远程访问核心);`/tw/<id>/…` 按库定向,裸 `/tw/` = 默认库别名(v0.28.0) |
|
|
66
|
+
| `/dsh-tiddlywiki/admin/state` `/info` `/config` `/restart` | GET/POST | 设置页:状态快照 / 插件·主题·语言 / 配置读写 / 重启(v0.28.0 起全部按 `?wiki=` 定向) |
|
|
63
67
|
| `/dsh-tiddlywiki/admin/seeds` `/run` `/remove` | GET/POST | seed 状态(v0.22.0 起含内容哈希的「有更新 / 本地已修改」)/ 运行 / 反初始化 |
|
|
64
68
|
| `/dsh-tiddlywiki/admin/prompt` | GET/POST | 当前注入提示词全文(GET = 已保存的有效配置,v0.21.0);POST 带 `{enabled,mode,extra,override}` 则按**草稿**渲染、写入零副作用,供设置页预览未保存的表单值(v0.22.7) |
|
|
69
|
+
| `/dsh-tiddlywiki/admin/wikis` | GET/POST | 多库清单读写:`add`/`update`/`remove`/`set-default`/`set-mode` + 运行态 `start`/`stop`(v0.28.0) |
|
|
65
70
|
| `/dsh-tiddlywiki/admin/wiki/location` | GET | 当前知识库位置 + 来源(指针/配置/默认)+ 指针文件路径 + 同目录候选 wiki(v0.22.0) |
|
|
66
71
|
| `/dsh-tiddlywiki/admin/wiki/switch` `/reset` | POST | 运行时切换知识库 / 恢复为配置默认(失败自动回滚并报告,v0.22.0) |
|
|
67
72
|
|
|
73
|
+
> ⚠️ **`?wiki=<id>` 的三种语义**(v0.29.0 定稿):命名的库在跑 → 就是它;**已登记但没在跑 → 一律 503 并点名那个库**(绝不静默落到默认库:设置页、快速笔记、`/admin/info` 都曾因此改错库);**未知 id → 回落默认库**(老书签不能 404)。三种判断只有一份实现:`host/wiki-farm.ts` 的 `targetRuntimeFor()` / `stoppedWikiFromRequest()`。
|
|
74
|
+
|
|
68
75
|
### 项目结构
|
|
69
76
|
|
|
70
77
|
```
|
|
71
78
|
src/
|
|
72
|
-
├── index.ts # host
|
|
79
|
+
├── index.ts # host 入口:装配农场(多库)/路由/工具/提示词/自动 commit
|
|
80
|
+
├── index-wikis.ts # 知识库视图与切换(v0.28.8 拆出)
|
|
81
|
+
├── index-git.ts # git 层装配(按仓库去重的提交者)
|
|
82
|
+
├── index-prompt.ts # 提示词 section 的注册与按会话求值(v0.28.8 拆出)
|
|
83
|
+
├── index-clip.ts # 剪藏桥装配
|
|
73
84
|
├── sdk.ts # 自包含 defineTool + dshHomePath(零 @deepseek-ai 运行时依赖)
|
|
74
85
|
├── host/
|
|
75
86
|
│ ├── wiki.ts # WikiServer:spawn/kill/自愈/端口探测/就绪轮询(策略见 ready-policy.ts)+ 迟到就绪复探;TW_PROXY_PATH 同源代理
|
|
87
|
+
│ ├── wiki-instance.ts / wiki-farm.ts / wiki-registry.ts / wiki-switch.ts / wiki-location.ts
|
|
88
|
+
│ │ # 多库(v0.28.0):一个库的运行时 / 谁该在跑与会话作用域 / 清单与动作规则(纯函数)/ 单库切换 / 位置解析
|
|
76
89
|
│ ├── ready-policy.ts # TW 启动就绪策略(v0.22.5):软窗口 60s(可配)/ 硬上限 3× / awaitReady 纯策略(注入时钟,可单测)
|
|
77
90
|
│ ├── tw-api.ts # TiddlyWeb REST 客户端
|
|
78
91
|
│ ├── git.ts # git init/commit/pull/push/sync/status + AutoCommitter
|
|
79
|
-
│ ├──
|
|
80
|
-
│ ├──
|
|
81
|
-
│ ├──
|
|
92
|
+
│ ├── repo-committers.ts # 按**仓库**去重的自动提交者(多库可共用仓库,v0.28.0)
|
|
93
|
+
│ ├── routes.ts # 路由装配(barrel)+ 非代理路由;实现分在下面三个同族文件里
|
|
94
|
+
│ ├── routes-session.ts / routes-tw-proxy.ts
|
|
95
|
+
│ │ # 会话/agent-send/session-summary(前者)/ `/tw` 与 `/api` 代理(后者)
|
|
96
|
+
│ ├── http.ts # 共用 HTTP 助手(readBody/json/guardHandler/同源守卫)
|
|
97
|
+
│ ├── clip-bridge.ts # 本地剪藏桥(v0.16.24):127.0.0.1 监听 + POST /clip 写 wiki(Host 校验/token/CORS preflight;v0.29.0 起写入串行化)
|
|
82
98
|
│ ├── session-summary.ts # 会话「知识库」Tab 后端
|
|
83
|
-
│ ├──
|
|
99
|
+
│ ├── session-scope.ts # 会话级作用域持久化($DSH_HOME/dsh-tiddlywiki/sessions.json)
|
|
100
|
+
│ ├── admin.ts # 设置页后台装配(barrel);实现分 admin-{catalog,secrets,routes}.ts
|
|
84
101
|
│ ├── config.ts # ConfigStore:cordis config 基底 + 配置 tiddler 覆盖层
|
|
85
|
-
│ ├── seeds.ts # 统一 seed 注册表(
|
|
86
|
-
│ ├── prompt.ts # 系统提示词(v0.21.0):slim/full 两种形态 + extra/override,full 的目录由工具注册表实时生成;v0.22.7
|
|
102
|
+
│ ├── seeds.ts # 统一 seed 注册表(13 项,三层:核心/起步/可选)
|
|
103
|
+
│ ├── prompt.ts # 系统提示词(v0.21.0):slim/full 两种形态 + extra/override,full 的目录由工具注册表实时生成;v0.22.7 起草稿预览;v0.29.0 slim 去重到 ~1.0KB
|
|
87
104
|
│ ├── seed-*.ts # 各 seed 实现(bundle/首页/ui-styles 常量脚本生成;starter-docs/menubar/clip-bridge 手工维护)
|
|
88
|
-
│ └── tools.ts # 15 个 tiddlywiki_*
|
|
105
|
+
│ └── tools.ts # 15 个 tiddlywiki_* 工具的**装配与注册顺序**;实现分 tools-{support,read,notes,attach,git}.ts(v0.28.8)
|
|
89
106
|
└── client/ # 浏览器半部
|
|
90
107
|
├── index.ts # client 入口(inject ['slots'],纯 DOM,永不 throw)
|
|
91
108
|
├── endpoints.ts # 客户端同源端点常量 + describeSyncResult(同步回执唯一实现,v0.22.8)
|
|
92
109
|
├── status-cache.ts # 共享 /status 读取器(2s TTL + 在途合并)
|
|
93
110
|
├── ui-config.ts # 共享 ui.* 投影 + invalidate/subscribeUiConfig(v0.22.8 扩到全部 FAB 开关)
|
|
94
111
|
├── render-fetch.ts # **唯一**的 POST /render 调用(v0.22.8)
|
|
95
|
-
├──
|
|
96
|
-
│ #
|
|
112
|
+
├── wiki-focus.ts / wiki-scope.ts / wiki-scope-dock.ts / scope-seat.ts / sidebar-entry.ts
|
|
113
|
+
│ # 焦点库记忆 / 会话作用域读取(含 v0.29.0 的订阅)/ 选择器 / 空白会话座位 / 侧边栏入口
|
|
114
|
+
├── knowledge-fab.ts / quick-note-dock.ts / note-widget{,-draft,-tags,-upload}.ts / editor-popup.ts
|
|
115
|
+
│ # 知识库 FAB / 快捷按钮 / 快速笔记(v0.28.8 拆分)/ 原生编辑弹窗
|
|
97
116
|
├── markdown-editor.ts # CodeMirror 6 Markdown 编辑器
|
|
98
117
|
├── session-summary.ts # 会话「知识库」Tab(conversation.view 槽位)
|
|
99
118
|
├── tool-views.ts # 回复流工具卡片(tool.call.toolview)
|
|
100
|
-
├── theme-sync.ts /
|
|
101
|
-
│ # 主题同步 /
|
|
119
|
+
├── theme-sync.ts / sync-button.ts / settings-page{,-runtime,-wikis,-config,-catalog}.ts
|
|
120
|
+
│ # 主题同步 / 同步按钮 / 设置页(v0.28.8 拆成装配 + 4 个 section)
|
|
102
121
|
├── tw-frame.ts # **TW frame 内核(v0.22.4 起唯一实现)**:createTwFrameSurface(skin) 管 lazy-load / status 轮询 /
|
|
103
122
|
│ # 错误与启动态 / 主题同步 / FAB 重载 / hash 导航 / dispose;中央面板与右侧栏共用同一份
|
|
104
|
-
└── panel.ts / rightbar-tab.ts /
|
|
123
|
+
└── panel.ts / rightbar-tab.ts / state.ts / styles.ts / toast.ts
|
|
124
|
+
|
|
125
|
+
> ⚠️ v0.28.8 起大文件按**模块族**拆分:`<base>.ts` 一律保留为装配/barrel,实现放 `<base>-xxx.ts`。
|
|
126
|
+
> 守门脚本用 `scripts/lib/source-family.mjs` 的 `readFamily()` 把一族拼成一份文本 ——
|
|
127
|
+
> **新增拆分文件必须用 `<base>-xxx.ts` 命名**,否则守门读不到、断言会静默失效。
|
|
105
128
|
|
|
106
129
|
> ⚠️ v0.22.8 起 `endpoints.ts` 的 `describeSyncResult()`、`render-fetch.ts`、`ui-config.ts` 各是**唯一实现**:
|
|
107
130
|
> 同步回执、渲染调用、`ui.*` 投影都不要再在客户端面里各写一份(此前已因此漂移)。
|
package/docs/features.md
CHANGED
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
| 📍 **知识库位置可切换** | 设置页「知识库位置」可把插件切换到**任意本地文件夹**(不用改 cordis 配置、不用重装):就地停/起 TW 子进程,目标目录没有 `tiddlywiki.info` 时自动 `--init server` 建一个全新知识库;选择记在 `$DSH_HOME/dsh-tiddlywiki/location.json`——一个**在 wiki 之外**的指针文件(所以切到新 wiki 后仍记得「我用的是哪个」),「恢复为配置默认」一键清除;**切换失败自动回滚**到原知识库并如实告知(v0.22.0)。⚠️ 它一次只有一个库在线;要**多库同时在线**见上面的「多知识库」(v0.28.0) |
|
|
17
17
|
| 🔄 **seed 更新检测** | seed 标记记录**内容哈希**:内置内容在本 wiki 预置之后更新过 → 设置页显示「⬆ 有更新」;被你改过 → 显示「✏️ 本地已修改」,且「重新初始化」前**二次确认**;两者都基于哈希判定,绝不猜(旧格式标记会明确显示「尚未启用更新检测」,不会误报为「你改过」,v0.22.0) |
|
|
18
18
|
| 🎨 **自定义样式** | 「自定义样式」seed:编辑器美化 / 窄屏侧栏隐藏 / menubar 加高 / 批注弹窗等 5 张通用样式表,新 wiki 也能一键初始化(可选,v0.16.22) |
|
|
19
|
-
| 📝 **可配置的注入提示词** | 插件注入每个会话的「TiddlyWiki 持久知识库」提示词可在设置页配置:**默认精简版**(v0.
|
|
19
|
+
| 📝 **可配置的注入提示词** | 插件注入每个会话的「TiddlyWiki 持久知识库」提示词可在设置页配置:**默认精简版**(v0.29.0 起 ~1.0KB,只保留工具 schema **表达不了**的约定——同步时机 / 写入被拒后重读而不用 `force` / 时效标注 / 淘汰权归人 / `human-edited` / 链接格式 / todo 约定),可选**完整版**(额外附一份**由工具注册表实时生成**的参数索引,不会再过期);`extra` 追加自定义规范、`override` 整段接管、可整体停用;**保存后无需重启 dsh web**(section 即时重注册,当前会话下一步即生效),设置页可**按表单当前值预览**即将注入的全文(未保存的形态切换也立刻可见,v0.21.0 / v0.22.7)。**v0.29.0 去重**:与工具 description 逐字重复的句子(工作区标记 / 先窄后宽 / 多词 AND / tags·type 保留规则)从提示词里删掉、**只留 schema 一份**,`verify-prompt.mjs` 改为在 schema 侧逐条断言「从提示词删 ≠ 丢了」 |
|
|
20
20
|
| 🤖 **Agent 工具** | 15 个 `tiddlywiki_*` 工具:检索(**相关度排序 + 命中处片段 + 字段过滤**)、读写、**增量追加**、批量、重命名、**软删除/回收站**、**反向链接**、**附件入库**、**知识库体检**、git 同步与冲突解决(v0.19.0;检索/最近仍在**服务端**排除二进制附件,大 wiki 上从 515MB/17s 降到 ~0.4s) |
|
|
21
21
|
| 🛡️ **不会被覆盖的写入** | 所有写入路径(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` 更新引用时若某个引用者在遍历期间被改动过,**跳过它**并在回执里报出数量,而不是覆盖它 |
|
|
22
22
|
| 🏷 **工作区感知的读写** | **新建**笔记自动带 `ws/<项目名>` 标签 + `workspace` 字段(项目名取自会话工作目录,`note.workspaceMark` 可关);`tiddlywiki_search` 因此默认**先在本项目里找、区内 0 条才自动扩大到全库**并在回执里写明实际范围,`query` 按空白切词、**全部词命中**才算(AND)。工作区只是**附加**标记,绝不改写笔记原有的标签/字段,也**只在新建时**打(v0.24.0) |
|
|
23
23
|
| 🕰 **时效性内容只提示不删** | 阶段性笔记(版本记录 / 部署步骤 / 排期 / 临时方案)可声明 `valid-until`(硬过期)或 `review-after`(该复查),被取代时写 `superseded-by` + `superseded` 标签并**保留旧笔记**;`tiddlywiki_lint` 的 `stale` 检查**只报告**(含「版本号或 done 标签 + 长期未改动」的**候选**,明确标注非判定)——**淘汰永远由人决定**,插件不会自动删除或归档任何笔记(v0.24.0) |
|
|
24
|
-
| 🚰 **重启不丢写入** | 停/重启 TW 只有一条路:`drainThenStop()`——**排干 syncer 队列之后才停子进程**,`/restart`、`/admin/restart`、插件/主题变更后的重启、知识库切换、`/sync`、seed
|
|
24
|
+
| 🚰 **重启不丢写入** | 停/重启 TW 只有一条路:`drainThenStop()`——**排干 syncer 队列之后才停子进程**,`/restart`、`/admin/restart`、插件/主题变更后的重启、知识库切换、`/sync`、seed、**以及启动自举路径**(v0.29.0:`pluginAdded` 与 `uiLanguage` 两处曾是裸 `server.restart()`,现在全部走 `instance.restart()`)都经它;排干不完整会在回包里如实报 `drained:false`,而不是假装没事(v0.24.1)。唯一的例外是 `dispose()`(卸载路径按设计不排干,且它只从会先排干的 `stopEntry` 到达)|
|
|
25
25
|
| 🕒 **时间戳不再丢** | 插件写入的每条笔记都会带上 TW 的 `created`/`modified`(17 位紧凑 UTC,与 TW 编辑器逐字节一致):新建 = 两者都取当前时刻,覆盖 = **保留原 `created`、刷新 `modified`**。此前这两个字段被当成「TW 服务端会补」而丢弃,而服务端**从不补**——缺 `modified` 的条目会被 TW 的 `sortTiddlers` 当空串,在 `+[!sort[modified]]` 页面上**直接沉到最后一名**(表现为「新日记没被收录」)。`TiddlyWebClient.put()` 还有一道兜底,任何写路径都不会写出无时间戳的条目(v0.22.5) |
|
|
26
26
|
| 🧼 **渲染片段净化** | 回复流卡片与会话汇总注入的 TW 片段先经 **host 白名单净化**(丢 `iframe`/`script`/`svg`/`on*`/`javascript:`/`data:text/html` 等)——TW 自己的解析器只剥 `on*`,`<iframe src="javascript:…">` 会原样通过并在 DSH 页面里执行(v0.19.1 修复的存储型 XSS) |
|
|
27
27
|
| 🔒 **写路由方法校验** | 每个写路由只接受自己的 HTTP 方法:跨站 `GET /sync`、`GET /restart`、`GET /upload` 一律 405 且无副作用(v0.19.0 修复了「任意网页一张 `<img>` 即可触发 pull/commit/push」的 CSRF 面) |
|
|
@@ -60,13 +60,14 @@ interface SeedDef {
|
|
|
60
60
|
| `clip-bridge` | `seed-clip-bridge.ts` → `seedClipBridge` / `unseedClipBridge` | 「本地剪藏桥 + 书签小工具」使用说明(Markdown 文档,带书签代码 / 启用步骤 / 安全说明,tag `dsh-docs`)——真功能在 `clip-bridge.ts` 运行时代码里 | `$:/plugins/dsh-tiddlywiki/seed-clip-bridge` | 可选 |
|
|
61
61
|
| `publish-spec` | `seed-publish-spec.ts` → `seedPublishSpec` / `unseedPublishSpec` | 「发布元数据规范」(Markdown,tag `dsh-docs`)——pub-state / pub-* 字段与 no-publish 标签约定,供微信发布流程判断「发过没有 / 能不能发」 | `$:/dsh-tiddlywiki/publish-spec-seeded` | **起步(gated)** |
|
|
62
62
|
| `wechat-setup` | `seed-wechat-docs.ts` → `seedWechatDocs` / `unseedWechatDocs` | 「微信公众号发布指南」(Markdown,tag `dsh-docs`)——**逐字节等于 `docs/wechat-publish-setup.md`**(由 `scripts/gen-seed-wechat-docs.mjs` 生成,勿手改常量):opencli / 扩展 / 登录 / adapter 安装与换机还原、三个坑、排错表 | `$:/plugins/dsh-tiddlywiki/seed-wechat-docs` | **起步(gated)** |
|
|
63
|
+
| `wechat-publish` | `seed-wechat-publish.ts` → `seedWechatPublish` / `unseedWechatPublish` | `$:/plugins/dsh/wechat-publish` 工具栏按钮 bundle(`application/json`)——TW 笔记工具栏的「发布到公众号」按钮 | `$:/plugins/dsh-tiddlywiki/seed-wechat-publish` | **起步(gated)** |
|
|
63
64
|
| `tw-web-host` | `seeds.ts` 内联 | `$:/config/tiddlyweb/host` → `/dsh-tiddlywiki/tw/` | 无 marker(ensure 型,见 §4) | **核心** |
|
|
64
65
|
|
|
65
66
|
> ℹ️ `home-index` 的 seed 版首页是**通用版**:生成脚本**默认**剥离作者 wiki 里的个人元素(主题页 tabs、书籍书架入口等,仅 `--keep-private` 才原样嵌入),并内置「📚 插件文档」tabs 栏(`[tag[dsh-docs]!is[system]]`,默认展开插件说明)。作者自己的 wiki 首页不受影响(seed 是 ONE-SHOT,不会覆盖)。
|
|
66
67
|
>
|
|
67
68
|
> ℹ️ **v0.22.0 起 marker 记内容哈希**:marker tiddler(`$:/plugins/dsh-tiddlywiki/seed-*`)的正文从一行 `seeded-once` 升级为 JSON `{ version, hashes: { <标题>: <sha256 前 16 位> }, at }`——哈希记录的是**我们写下的内置正文**,据此可区分「内置内容更新了」与「用户自己改过」(见 §3.1)。旧 marker 仍可读,按文本比对,并在下一次重新初始化时升级。
|
|
68
69
|
>
|
|
69
|
-
> ℹ️ **v0.23.0 起 gated seed**:`publish-spec` / `wechat-setup`(v0.23.1)虽是起步层(`startup: true`),但带 `gate: (ctx) => ctx.wechat === true`——**只在设置页开启「微信公众号发布」(`wechat.enabled`)时**才参与启动写入;不开该功能的用户 wiki 里不会出现发布相关文档(提示词里也没有指针,死链风险只存在于开启侧)。`gate` 只作用于启动路径 `runAllSeeds`;设置页手动「初始化」走 `runSeedById` 不受它约束(显式请求)。`checkAllSeeds`
|
|
70
|
+
> ℹ️ **v0.23.0 起 gated seed**:`publish-spec` / `wechat-setup`(v0.23.1)/ `wechat-publish`(v0.23.3)虽是起步层(`startup: true`),但带 `gate: (ctx) => ctx.wechat === true`——**只在设置页开启「微信公众号发布」(`wechat.enabled`)时**才参与启动写入;不开该功能的用户 wiki 里不会出现发布相关文档(提示词里也没有指针,死链风险只存在于开启侧)。`gate` 只作用于启动路径 `runAllSeeds`;设置页手动「初始化」走 `runSeedById` 不受它约束(显式请求)。`checkAllSeeds` 照常报告三项「缺失」,属预期。
|
|
70
71
|
>
|
|
71
72
|
> ℹ️ **v0.22.0 起 `doc-note` 正文是生成的**:工具清单来自 `tiddlywikiToolSummary()`(`docNoteText(tools)`),不再手抄「N 个 agent 工具」。无注册表的 headless 调用会退化成一句指针,绝不写出过期数量。`wechat-setup` 的正文同理由 `docs/wechat-publish-setup.md` 生成(`scripts/gen-seed-wechat-docs.mjs`),`scripts/verify-wechat-docs-seed.mjs` 守逐字节一致。
|
|
72
73
|
|
|
@@ -289,8 +290,8 @@ npm run typecheck && npm run build && npm run selftest
|
|
|
289
290
|
## 8. 验证
|
|
290
291
|
|
|
291
292
|
- `npm run typecheck` / `npm run build`:编译与打包;
|
|
292
|
-
- `npm run selftest`:5d
|
|
293
|
-
- `node scripts/verify-seeds-admin.mjs`:全新 wiki + 真实 HTTP,端到端验证 `GET /admin/seeds`
|
|
293
|
+
- `npm run selftest`:5d 段覆盖注册表清单(**13 项**,含 `core` / `removable` / `startup`)、**启动只 seed 核心 + 起步项(wechat 关时 5 项)且不碰可选项**、手动全跑只写缺失、单跑幂等、force 重写、unknown id、tw-web-host 三分支(custom 保留 / force 写回 / legacy 修复)、**反初始化**(单移除 / 核心拒绝 / unknown / 全部移除保留核心)——另含 starter-docs 安全跳过、ui-styles 仅功能 tag、seed 版首页剥离私有人口 + 文档栏等断言;
|
|
294
|
+
- `node scripts/verify-seeds-admin.mjs`:全新 wiki + 真实 HTTP,端到端验证 `GET /admin/seeds` 状态流转(**13 项全缺失** → 启动后核心+起步就绪、可选项仍缺失)与 `POST /admin/seeds/run`(force 单跑恢复被改坏的首页、非 force 不覆盖用户内容、force-all 恢复代理基址、unknown id 400)+ `POST /admin/seeds/remove`(移除非核心、核心 400、remove-all 仅剩核心)。
|
|
294
295
|
|
|
295
296
|
---
|
|
296
297
|
|
package/docs/usage.md
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
| 配置 | 作用 |
|
|
49
49
|
|---|---|
|
|
50
50
|
| `prompt.enabled` | 关掉后本插件不注入任何文本 |
|
|
51
|
-
| `prompt.mode` | `slim`(**默认**,v0.
|
|
51
|
+
| `prompt.mode` | `slim`(**默认**,v0.29.0 起约 1.0KB):只保留工具 schema 表达不了的约定(**同步时机**、写入被拒后重读而不用 `force`、时效标注 `valid-until`/`review-after`/`superseded-by`、淘汰权归人、`human-edited`、可点击链接格式、todo 约定)。与工具 description 逐字重复的句子**不再复述**(工作区标记、先窄后宽检索、多词 AND、tags/type 保留规则都在对应工具的 schema 里,`verify-prompt.mjs` 会在 schema 侧逐条守住"从提示词删 ≠ 丢了");`full`:额外附一份**参数索引**,由工具注册表在运行时生成,因此永远不会与真实工具脱节 |
|
|
52
52
|
| `prompt.extra` | 追加在末尾的自定义规范(团队 / 个人偏好),始终生效 |
|
|
53
53
|
| `prompt.override` | 非空时整段取代内置文本(`extra` 仍会追加)——想完全自写提示词时用 |
|
|
54
54
|
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
- **切库为什么需要等一下**(v0.28.14):切换 = 在同一个 iframe 里**换成另一个库的整份 TW 文档**(一个 iframe 只能装一个编辑器)。本机实测这份文档是 **9.9 MB / 29.9 MB / 28 MB**,而且 TW 自己回 `Cache-Control: no-store`、没有 ETag —— **缓存不了也预取不了**,所以每次切换都要真下载解析一遍。这一版做了三件事让它不"看起来卡住":① 点击**立即**开始换(不再先等一次 `/status`,那次往返在这台机器上要 300–400 ms,因为 host 每次都要跑最多 5 个 git 进程);② 侧边栏的选中高亮即时跟上,且不再重复请求 `/status`;③ TW 界面底部显示 **`正在载入知识库「个人」…`**,新文档到达即收起(另有 15 秒兜底)。**剩下的等待是 TW 文档大小决定的**,不是可以再优化的延迟。
|
|
106
106
|
- **「移出列表」不删目录**:只是让插件不再管理它,内容原样保留。
|
|
107
107
|
- **每个库一个图标**(v0.28.8):知识库列表每行的图标是个**弹出式网格**——里面是 **DSH 官方的 36 个图标**(与侧边栏/工具栏那套同源,深浅主题都对)、本插件自绘的 8 个(书籍 / 公文包 / 首页 / 笔记本 / 烧瓶 / 地球 / 星标 / 归档),外加一组 emoji 快捷选择;图标多了按 **48 个一页**翻页。选中即写入 `wikis.json` 的 `icon` 字段。当前值若不在候选里(比如你手写的短 emoji)会原样保留,不会被候选列表抹掉。**v0.28.8 同时修了一个真 bug**:此前选了图标界面会立刻变回默认 —— `/admin/wikis` 的读取视图漏了 `icon` 字段,于是"写进去了、读回来是 undefined",看起来就是没生效(现在有守门钉死这个字段,反向验证过)。
|
|
108
|
-
- **还没发过消息的新会话也能选库**(v0.28.8
|
|
108
|
+
- **还没发过消息的新会话也能选库**(v0.28.8,v0.28.11 修):选择器此前只长在输入框上方;新会话(空白页,输入框还没出现)时它会挂到**预设/模式选择旁边**那一格(`conversation.input.selector.context`)。实现是**声明感知**的:DSH 声明了那一格才注入,**声明不到就一直留在 dock 里那一行**——不会再"2 秒后回落到 dock"另注册一个(那个回落会在新会话里同时出现两个选择器,v0.28.11 已删除)。
|
|
109
109
|
- **会话「知识库」Tab 在多库下按会话作用域取数**(v0.28.8):汇总只统计**该会话作用域那个库**里的笔记;不这样做就会出现"A 库的笔记标题在 B 库里渲染成空白卡片"。
|
|
110
110
|
- **桌面版(DSH Desktop)**(v0.28.8):TW 子进程需要真正的 `node`。以前直接拿 `process.execPath` —— 在桌面版里那是 Electron 可执行文件,TW 根本起不来。现在先按 `DSH_TIDDLYWIKI_NODE` 环境变量、再 `where node` / `which node`、最后才回落 `process.execPath`;解析结果缓存,并在启动日志里写明用了哪个。
|
|
111
111
|
- **清单文件**:`$DSH_HOME/dsh-tiddlywiki/wikis.json`(在每本 wiki 之外,所以它不会随某个库被搬走)。
|
|
@@ -205,7 +205,7 @@ wiki 里既有**早已发布**的文章,也有**明确不能发**的内容。
|
|
|
205
205
|
|
|
206
206
|
**规范全文在 wiki 里**:笔记「**发布元数据规范**」(随插件 seed 分发,`dsh-docs` 标签,
|
|
207
207
|
开机自动写入;也可手动跑 `npx tsx tools/wechat/seed-publish-spec-now.mts` 立即写入)。
|
|
208
|
-
注入给 agent
|
|
208
|
+
注入给 agent 的系统提示词里**只有一句指针**(规范全文太长,不适合放进每个会话都要付的常驻预算 —— v0.29.0 把 slim 从 ~1.9KB 瘦到 ~1.0KB 之后依然如此,指针就够了:需要时 Agent 会去读那篇笔记)。
|
|
209
209
|
|
|
210
210
|
### 字段(自定义字段,不是标签)
|
|
211
211
|
|