dsh-tiddlywiki 0.30.60 → 0.30.61
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 +1 -0
- package/lib/index.js +9 -3
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/host/tools-support.ts +19 -2
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.30.61**(2026-10-09):**修 `tiddlywiki_trash list` 少报一条 —— TW 给块级片段的首元素套 `<p>`** —— v0.30.60 实跑时 `list` 对**126 条**回收站报「共 125 条」,少的那一条**恰好是排序后的第一条**(实测片段为 `<p>$:/trashbin/__验收测试_trashbin软删除__|…`,而 `startsWith('$:/trashbin/')` 对带 `<p>` 的首条不成立)。**「列表少一条」是最坏的失败形态之一** —— 少的那条可能正是用户最想找的那条,而工具报告成功、不报错。现在改为**先定位前缀再剥标签**(`indexOf` 取到前缀处、再 `replace(/<[^>]*>/g,'')`),与首条是否被段落包裹无关。② 同时兼容旧字段名:`trash-iso` 是 v0.30.60 起的名字,**此前写的副本只带 `trash-at`**,不兼容读它时回执里「删除于」那一栏**整列为空**(实测);现在两个字段都读,`trash-iso` 优先。**守门** `scripts/verify-trashbin-probe.mjs` 增至 **11 条**,新增两条钉住上述两点;**反向验证**:去掉剥标签逻辑 ⇒ 红、改回 `\n` 拆分 ⇒ 红,各自精确点名,恢复后逐字一致。
|
|
7
8
|
- **v0.30.60**(2026-10-09):**修 v0.30.59 的 `tiddlywiki_trash` 静默谎报「回收站是空的」** —— v0.30.59 发布后第一次实跑,`list` 就报「共 0 条」,而 wiki 里明明有 126 条 `$:/trashbin/` 副本。**两个独立缺陷叠在一起,缺一个都不会这么静默**:① `listTrashbin()` 的探针写成 `<$list … variable="ignore">` —— **`variable="ignore"` 会占用 `currentTiddler` 这个保留变量名**,于是循环体内的 `<$text text=<<currentTiddler>>/>` 全部绑到空上下文,实测返回 **126 个分隔符、零个标题**;② 分隔符原写成 `\n`,而片段是 **HTML**、换行会被折成空格,按 `\n` 拆会把整个列表当成**一行**,那行又过不了 `$:/trashbin/` 前缀检查。两者都产出 `[]`,而「空的回收站」是完全正常的答案 —— 于是工具**报告成功、同时撒谎**。③ 补一道自检:**有分隔符却零标题 = 探针坏了,必须显式报错**(不再回落成空列表)。④ 逐条 `wiki.get()` 改**有界并发(8)**:125 条串行就是 125 次 REST 往返。⑤ 溯源时间字段由 `trash-at` 改名 **`trash-iso`** —— TW 会把任何 `*-at`/`*-date` 字段当日期**重新序列化成本地格式**(实测 PUT 进去的 ISO 读回来是 `10/09/2026 05:11:54`),机器可读的值会丢。⑥ 配套发现并修正一处**流程事实**:`plugins/dsh-tiddlywiki`(源码仓库,0.30.59)与 `profiles/*/node_modules/dsh-tiddlywiki`(运行时实际加载,0.30.57)**是两份不同的副本** —— 改完源码 + 重启 DSH 不会生效,必须走发布流程(tag → npm publish → 升级运行时副本),这是 AGENTS.md §4 末尾第 8 步「同步线上 wiki」的真实含义。**守门**(新增 `scripts/verify-trashbin-probe.mjs`,进 `verify:unit`,8 条):钉住探针不含 `variable="ignore"`、必须输出 `<<currentTiddler>>`、必须按 `|` 拆而非换行、有分隔符零标题必须 throw、有界并发、字段名。**反向验证**:把 `variable="ignore"` 注回去 ⇒ 红;把 `|` 换回 `\n` ⇒ 红;恢复后逐字一致。
|
|
8
9
|
- **v0.30.59**(2026-10-09):**软删除改为「跟着 wiki 已有的回收站机制走」;同时把一条会误导人的注释改成实测事实** —— 本机 work 库已装 [kookma/trashbin](https://github.com/kookma/TW-Trashbin)(v1.3.6,`$:/trashbin/<原标题>` + `$:/tags/trashbin` 标签),但 `tiddlywiki_delete` 此前**看不见它**:软删除一律写 `$:/dsh-tiddlywiki/trash/<时间戳>/<原名>` + JSON 索引,于是 agent 删掉的东西只有 agent 能列出/恢复,人在 TW 侧边栏里一条都看不到,两套回收站互不相通。现在:① `tools-support.ts` 新增 `hasTrashbin()` 探测(**只读**,不写探针 tiddler——那会在从不装 trashbin 的库里留垃圾,而它正是要检测的东西;判据是 `$:/tags/trashbin` / `$:/plugins/kookma/trashbin/sidebar-tab` **是否存在条目**,**不是查 `tiddlywiki.info`**——浏览器安装的 trashbin 压根不在 info 里(实测:服务器无 `plugin.info`、info 无登记,却照常工作),查 info 会在「恰恰装了它的库」上误报 false);② 命中时 `delete` 写 trashbin 格式副本(保留原 `created`/`modified`,另记 `trash-of`/`trash-iso`),**不再写 trash-index**,同名二次删除显式拒绝而非静默覆盖;③ 未命中时走原路径(未装 trashbin 的库行为不变)。**⚠️ 顺带修正一条错误的注释**(`tools-support.ts` 原先写「`$:/` 系统标题无法被枚举」,v0.30.58 之前 agent 据此连续三次误判,包括否掉一个实际可行的方案):实测证明「不可枚举」**只对 HTTP 列举端点成立**(`get-tiddlers-json.js` 给任何 filter 追加 `+[!is[system]]`,实测 `tiddlers.json` 恒 138 条、系统条目恒 0),而**filter 引擎无此限制**(服务端渲染 `[tag[$:/tags/trashbin]]` 得 `COUNT=125`)、**启动期 `store.area.template.html` 内嵌整个 store** 使客户端一开始就持有全部 tiddler——**三条通道必须分开说**,这也是 trashbin 格式不需要索引的根本原因。
|
|
9
10
|
- **v0.30.58**(2026-10-09):**`tiddlywiki_git_sync` 不再要求显式配 `git.remote` —— 配置为空时回落到该库所在仓库自己的 `origin`**(作者 2026-10-09 裁定,方案 A)。起因是一个**同一个问题两个答案**的真实现场:设置页/FAB 的「同步」按钮一直是在目录里跑 `pull/commit/push`、按仓库 `origin` 推,而 Agent 工具把 `git.remote` 当成"开启同步"的开关 —— 同一个仓库,界面点得动、工具却回「没有任何知识库配置了 git.remote(同步远端)」并**整库跳过**(实测:本机 notes 仓库已推到远端、`git remote -v` 有 origin,工具仍报三个库皆未配置)。现在:① 判定改为「**`git.remote` 或仓库 `origin`**」,`git.remote` 降级为**覆盖**(也仍是 `ensureRemote` 写入的目标);② 回落**只在「没配 **且** 真在 git 仓库里」时发生** —— 不在仓库里就不白跑 `git`(新增 `GitFace.originOf()`,**只读、不建远端**);③ `GitSyncTarget` 新增 `remoteSource: 'config' | 'origin' | 'none'`,**回执逐仓库写出远端与来源**(「自动识别自仓库 origin」/「来自 git.remote 配置」),且 URL 里的**凭据先剥掉**(`git.remote` 可能带 PAT,`/admin/state` 对同一个值打码 —— 回执是新开的一条出口);④ `skipped` 分得清「未配 `git.remote`,仓库也没有 origin」与「不在 git 仓库里」,零目标时的文案同时给出两条出路;⑤ 设置页「git 远端」提示改为「空=自动用该库所在仓库的 origin」,`docs/features.md` / `docs/usage.md` / `AGENTS.md` 同步改写。**守门**:`scripts/verify-git-multi-sync.mjs` 新增「回落只在该回落时发生」(**假 farm + 假 GitFace 直接驱动 `createGitLayer().gitTargets()`**,断言 `originOf` 的**调用点集合**:有配置的不探、不在仓库的不探)、回执来源文案、凭据剥离、两种跳过原因;`scripts/verify-repo-keying.mjs` 用真临时仓库钉 `originOf()` 的三态(有 origin / 没有 / 不在仓库里)与「只读不建远端」。`createGitLayer` 因此进入公共面(`scripts/index-barrel-surface.json` 已更新)。**反向验证**:把回落那一行改回 `''` ⇒ 新守门当场点名 `personal` 的 `remoteSource`;恢复后逐字一致。**顺手修好一处既存红灯**:`AGENTS.md` §5 的开发文档索引还指着 2026-10-04 那次笔记整理里**已被合并删除**的 5 篇旧笔记(常见坑 / 架构事实 / 仓库布局 / 易变清单 / 发布流程),而 `scripts/verify-wiki-pointers.mjs` 正是为此存在 —— 指针已改指**整理后仍在的三篇**(《dsh-tiddlywiki 事实总表》《TiddlyWiki 使用与技巧事实总表》《拆库丢失的系统条目清单》)+ 仓库 `docs/CHANGELOG.md` / `docs/development.md`,§2 §4 §6 §7 里同样的旧名字一并改掉。**不恢复那些笔记**(删除是有意为之),`verify:sync` 因此恢复全绿。
|
package/lib/index.js
CHANGED
|
@@ -2742,7 +2742,10 @@ async function listTrashbin(wiki, renderFilter) {
|
|
|
2742
2742
|
return;
|
|
2743
2743
|
}
|
|
2744
2744
|
if (typeof html !== "string") return void 0;
|
|
2745
|
-
const titles = html.split("|").map((
|
|
2745
|
+
const titles = html.split("|").map((chunk) => {
|
|
2746
|
+
const at = chunk.indexOf(TRASHBIN_PREFIX);
|
|
2747
|
+
return at === -1 ? "" : chunk.slice(at);
|
|
2748
|
+
}).map((title) => title.replace(/<[^>]*>/g, "").trim()).filter((title) => title.startsWith(TRASHBIN_PREFIX));
|
|
2746
2749
|
if (titles.length === 0 && html.includes("|")) throw new Error("tiddlywiki_trash: 回收站列表渲染结果异常——分隔符存在但没有任何可识别的条目标题(TW 的 <$list> 上下文或转义行为与预期不符)。已中止,未改动任何数据。");
|
|
2747
2750
|
const entries = [];
|
|
2748
2751
|
const CONCURRENCY = 8;
|
|
@@ -2750,10 +2753,13 @@ async function listTrashbin(wiki, renderFilter) {
|
|
|
2750
2753
|
const slice = titles.slice(i, i + CONCURRENCY);
|
|
2751
2754
|
const rows = await Promise.all(slice.map(async (trash) => {
|
|
2752
2755
|
const t = await wiki.get(trash);
|
|
2756
|
+
const of = typeof t?.fields?.["trash-of"] === "string" ? t.fields[TRASHBIN_OF_FIELD] : trash.slice(12);
|
|
2757
|
+
const iso = typeof t?.fields?.["trash-iso"] === "string" ? t.fields[TRASHBIN_AT_FIELD] : "";
|
|
2758
|
+
const legacy = typeof t?.fields?.["trash-at"] === "string" ? t.fields["trash-at"] : "";
|
|
2753
2759
|
return {
|
|
2754
2760
|
trash,
|
|
2755
|
-
of
|
|
2756
|
-
at:
|
|
2761
|
+
of,
|
|
2762
|
+
at: iso !== "" ? iso : legacy !== "" ? legacy : t?.modified ?? ""
|
|
2757
2763
|
};
|
|
2758
2764
|
}));
|
|
2759
2765
|
entries.push(...rows);
|