dsh-tiddlywiki 0.30.57 → 0.30.59

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 CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  > 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
6
6
 
7
+ - **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-at`),**不再写 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 格式不需要索引的根本原因。
8
+ - **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` 因此恢复全绿。
7
9
  - **v0.30.57**(2026-09-30):**给 `AGENTS.md` 的注入预算装上守门** —— 这条纪律的**存在理由就是它自己**。本文件顶部写着:宿主给 workspace instructions 的预算是 **65536 字节**,「过去它长到 ~120KB,**截断正好砍掉最后几节(发布流程 / 维护规则 / 常见坑)**」—— 也就是说**这份文件当初被拆成「规则 + 指针」的原因,就是它撞过预算上限**。而那条教训**只写在正文里,没有任何东西在量它**(`verify-doc-links` 管链接、`verify-wiki-pointers` 管指针,都不管篇幅),失效方式依然是沉默的:文件继续长到超限,宿主从末尾截断,被砍掉的正好是**最该被看到的规则**,**没有人会收到报错**。新增 `scripts/verify-agents-budget.mjs`(进 `verify:static`):**两级硬阈值** —— 硬上限 **65536**(宿主预算=事实边界)与软上限 **45000**(自我警戒线),**两级都红**(本仓库的教训是「只打印 warning 的守门等于没有守门」;要抬 SOFT 必须明确改常量=有意识的决定)。⚠️ 顺带守一件更隐蔽的事:**文件第 5 行对自身体积的自述不得漂移** —— 它当时写着「现在拆完约 **12KB**」,而实测已 **40.7KB**(**偏差 70%**,文件在对自己撒谎而无人被冒犯)。**这正是本守门第一次运行就抓到的**:`顶部自述「约 12KB」,实测 40.7KB`。已改为实测值并把守门写进那句旁边。**反向验证**:填充到 46920 字节(> 软上限)⇒ 红;填充到 66920 字节(> 硬上限)⇒ 红并点名「注入会被从末尾截断」;恢复后哈希逐字一致。当前实况:`41890 字节 / 65536 = 63.9%`。
8
10
  - **v0.30.56**(2026-09-30):**`AGENTS.md` 的 wiki 指针现在有守门了** —— §5「开发文档索引」是这套文档体系的**承重墙**(细节搬进 wiki、注入文件只留指针),但指针断掉的后果是**沉默的**:新会话按它去读会读到空气,而 `tsc` / 任何现有守门都不会报错(`verify-doc-links.mjs` 只管仓库内的相对文件链接)。新增 `scripts/verify-wiki-pointers.mjs`(并进 `npm run verify:sync`):**从 `AGENTS.md` 的表格行里**取出 `[[…]]` 指针(**只取表格行** —— 正文里的 `[[标题]]` 是 TW 语法示例、不是指针,这个区分是判据的核心),再从 wiki 数据根解析出**全部条目标题**(meta 的 `title:` 优先、退回文件名),要求每个指针都命中。**多库模式也认**(优先读 `$DSH_HOME/dsh-tiddlywiki/wikis.json` 的 `defaultId`/全部库,退回单库的 `location.json`)—— 实测本机上插件跑在多库模式、`location.json` 根本不存在,只认单库的话这个守门会**永远 SKIP**。⚠️ **找不到 wiki 数据根时 SKIP 而不是 FAIL**(别人的机器 / CI 上 wiki 可能不存在,前提不成立),但 SKIP **必须明说**「本轮未验证」;也正因如此它**不进 `verify:static`**(CI 上必然 SKIP,等于给人「已守」的错觉),而与 `verify:lib-sync` 同挂在 `verify:sync`(本机环境相关、提交/发布前跑)。**反向验证**:把 §5 的一个指针改成不存在的笔记名(=笔记被改名后的真实形状)⇒ **红并点名**;`--self-test` 模式另行证明「不存在的指针名会被判为缺失」。当前实况:**5 个指针全部命中 · 3 个库 · 2041 条条目**。
9
11
  - **v0.30.55**(2026-09-30):**把新守门接进 `prepublishOnly` + 修 `verify-all` 的收尾** —— ① `package.json` 的 `prepublishOnly` 此前只跑 `typecheck + build + verify:static + verify:unit`,**不含 `verify:e2e` / `verify:large` / `selftest` / `smoke:client`**,且**不跑 `verify:sync`** ⇒ 发布时构建产物可能**没被校验过与 `src/` 同步**(正是 v0.30.52 那个缺口的发布形态)。现在改为 **`npm run verify:all`**(= `verify:sync` + 8 步 `verify`),发布前的门与 CI 完全一致。② `verify-lock-sync.mjs`(v0.30.54 新增)此前只在 `verify:static` 里;本版确认它在 `prepublishOnly` 路径上也一定会跑(`verify:all` → `verify` → `verify:static` 的第一步就是它)。③ 顺手把交接卡与三篇 wiki 笔记更新到 v0.30.55。**发布前的门 = CI 的门 = 本地的门**,三处同源。
package/docs/features.md CHANGED
@@ -18,7 +18,7 @@
18
18
  | 🎨 **自定义样式** | 「自定义样式」seed:编辑器美化 / 窄屏侧栏隐藏 / menubar 加高 / 批注弹窗等 5 张通用样式表,新 wiki 也能一键初始化(可选,v0.16.22) |
19
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
  | 🌐 **中英双语界面**(v0.30.6) | 插件自己的界面(FAB / 侧边栏 / 快速笔记 / 工具卡片 / 设置页 / toast)与 TW 子进程**共用同一个 `uiLanguage` 设置**;文案按区域分片成 `i18n-*.ts` 的 `zh`/`en` 目录,守门保证两侧键集合一致、且**客户端代码里不再有硬编码中文文案** |
21
- | 🤖 **Agent 工具** | 15 个 `tiddlywiki_*` 工具:检索(**相关度排序 + 命中处片段 + 字段过滤**)、读写、**增量追加**、批量、重命名、**软删除/回收站**、**反向链接**、**附件入库**、**知识库体检**、git 同步与冲突解决(v0.30.5 起 `git_sync` **一次同步所有配了 `git.remote` 的库**、按仓库去重、逐仓库独立成败;v0.19.0;检索/最近仍在**服务端**排除二进制附件,大 wiki 上从 515MB/17s 降到 ~0.4s) |
21
+ | 🤖 **Agent 工具** | 15 个 `tiddlywiki_*` 工具:检索(**相关度排序 + 命中处片段 + 字段过滤**)、读写、**增量追加**、批量、重命名、**软删除/回收站**、**反向链接**、**附件入库**、**知识库体检**、git 同步与冲突解决(v0.30.5 起 `git_sync` **一次同步所有可同步的库**、按仓库去重、逐仓库独立成败;**v0.30.58 起「有远端」= 配了 `git.remote` **或**该库所在仓库自己的 `origin`**,配置为空即回落、回执写明远端与来源;v0.19.0;检索/最近仍在**服务端**排除二进制附件,大 wiki 上从 515MB/17s 降到 ~0.4s) |
22
22
  | 🛡️ **不会被覆盖的写入** | 所有写入路径(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` 更新引用时若某个引用者在遍历期间被改动过,**跳过它**并在回执里报出数量,而不是覆盖它 |
23
23
  | 🏷 **工作区感知的读写** | **新建**笔记自动带 `ws/<项目名>` 标签 + `workspace` 字段(项目名取自会话工作目录,`note.workspaceMark` 可关);`tiddlywiki_search` 因此默认**先在本项目里找、区内 0 条才自动扩大到全库**并在回执里写明实际范围,`query` 按空白切词、**全部词命中**才算(AND)。工作区只是**附加**标记,绝不改写笔记原有的标签/字段,也**只在新建时**打(v0.24.0) |
24
24
  | 🕰 **时效性内容只提示不删** | 阶段性笔记(版本记录 / 部署步骤 / 排期 / 临时方案)可声明 `valid-until`(硬过期)或 `review-after`(该复查),被取代时写 `superseded-by` + `superseded` 标签并**保留旧笔记**;`tiddlywiki_lint` 的 `stale` 检查**只报告**(含「版本号或 done 标签 + 长期未改动」的**候选**,明确标注非判定)——**淘汰永远由人决定**,插件不会自动删除或归档任何笔记(v0.24.0) |
package/docs/usage.md CHANGED
@@ -19,13 +19,13 @@
19
19
  | `tiddlywiki_backlinks` | 反向链接:谁用 `[[标题]]`/`{{标题}}` 引用了它、谁把它当标签 |
20
20
  | `tiddlywiki_attach` | 把**本机文件或公网 http(s) 地址**存成附件(图片/PDF/… 等二进制存 **`type` + base64 正文**;`text/markdown`·`text/plain`·`application/json` 等**文本**存 `type` + **纯文本正文**,这样 TW 才渲染得出来、也才搜得到 —— v0.30.22),可嵌入某篇笔记;URL 走 SSRF 守卫;**同名 tiddler 已存在时默认拒绝**(避免静默覆盖笔记),确认覆盖要传 `force: true`(tags/自定义字段仍保留) |
21
21
  | `tiddlywiki_lint` | 知识库体检(**只读**):垃圾标签 / 死链 / 空笔记 / 缺内容类型的类 Markdown 笔记 / **时效性内容**(`valid-until`·`review-after` 过期,以及「版本号或 done 标签 + 长期未改动」的**候选**,`staleAfterDays` 可调) |
22
- | `tiddlywiki_git_sync` | `action: pull\|push\|sync` —— **作用于所有配了 `git.remote` 的库**(v0.30.5):多库各自独立仓库时逐仓库同步、**每个仓库只跑一次**(多库共用一个工作树时不会重复 pull/commit/push),一个仓库冲突不影响其余;回执逐仓库标注「哪个库 @ 哪个仓库」,没配 remote 的库被列出来而不是静默略过 |
22
+ | `tiddlywiki_git_sync` | `action: pull\|push\|sync` —— **作用于所有可同步的库**(v0.30.5;判定见 v0.30.58):**「有远端」= 该库配了 `git.remote`,或它所在仓库有自己的 `origin`**(没配就自动回落,与设置页「同步」按钮同口径),两者都没有、或不在 git 仓库里的库被列出来而不是静默略过。多库各自独立仓库时逐仓库同步、**每个仓库只跑一次**(多库共用一个工作树时不会重复 pull/commit/push),一个仓库冲突不影响其余;回执逐仓库标注「哪个库 @ 哪个仓库」与**远端及其来源**(配置 / 自动识别自 origin;URL 里的凭据已剥) |
23
23
  | `tiddlywiki_git_resolve` | pull 冲突后按 tiddler 二选一(`keep-local\|keep-remote`) |
24
24
 
25
25
  **知识库同步纪律**:
26
26
  1. 开工先 `tiddlywiki_git_sync action=pull`(rebase + autostash,真冲突会 abort 并报文件)。
27
27
  2. 冲突后用 `tiddlywiki_git_resolve` 二选一解决,再重新 sync(**绝不自动覆盖**)。
28
- 3. 收工 `tiddlywiki_git_sync action=sync`(pull → commit → push)。**它与「同步」按钮的区别**(v0.30.5):工具作用于**所有**配了 `git.remote` 的库(一次一个仓库,各自独立成败),而设置页/FAB 的「同步」按钮只作用于**当前那个库**(它带着 `?wiki=`)。多库各有仓库时,冲突回执会写清是哪个库,解决时把那个库的 id 传给 `tiddlywiki_git_resolve wiki=<id>`。
28
+ 3. 收工 `tiddlywiki_git_sync action=sync`(pull → commit → push)。**它与「同步」按钮的区别**(v0.30.5;v0.30.58 起口径对齐):工具作用于**所有**可同步的库(一次一个仓库,各自独立成败),而设置页/FAB 的「同步」按钮只作用于**当前那个库**(它带着 `?wiki=`)。**「可同步」两边现在同源** —— 该库配了 `git.remote`,或它所在仓库有自己的 `origin`(v0.30.58 前工具只认前者,于是界面点得动、工具却回「没有任何知识库配置了 git.remote」)。多库各有仓库时,冲突回执会写清是哪个库,解决时把那个库的 id 传给 `tiddlywiki_git_resolve wiki=<id>`。
29
29
 
30
30
  > 🛡 **带着冲突绝不提交**(v0.23.4):`commit` 之前会探测「进行中的 rebase / 未合并路径 / **工作树里残留的冲突标记**」,命中就**拒绝提交**(`/sync` 返回 409 + 文件名、自动提交只上报一次、`/status` 与设置页状态行显示「冲突未解决(N 个文件,已阻止提交)」)。这条守卫来自真实事故:autostash 重新应用冲突后 `rebase --abort` 已无事可 abort,冲突标记留在工作树里被自动提交**永久写进了 git 历史**(连带插件自己解析不了配置)。**删冲突标记的方式**:解决后 `tiddlywiki_git_resolve`(或手动编辑掉 `<<<<<<<`/`=======`/`>>>>>>>` 三行)再 sync。
31
31
  >
package/lib/client.js CHANGED
@@ -20,9 +20,9 @@ Ctrl+Enter to save`,"note.uploadTitle":`Upload a file into the wiki and insert a
20
20
  Current: {root}`,"settings.wikis.moveNamePrompt":`Folder name (current: {name}; enter . to use the root folder above directly)`,"settings.wikis.rootRequired":`The root folder cannot be empty`,"settings.wikis.moving":`Moving (this wiki will be stopped and started)…`,"settings.wikis.needRootAndName":`Please fill in both the root folder and the folder name`,"settings.wikis.adding":`Adding (a new wiki has to be initialised and cold-started, one moment)…`,"settings.wikis.listFailed":`Could not read the knowledge-base list: {message}`,"settings.wikis.locationTitle":`Knowledge base location (switchable)`,"settings.wikis.rootPlaceholderSingle":`Absolute path, e.g. D:\\notes or $DSH_HOME/tiddlywiki`,"settings.wikis.folderPlaceholderSingle":`Folder name (default main; enter . to use the folder above directly)`,"settings.wikis.rootField":`Root folder (wikiRoot)`,"settings.wikis.folderField":`Folder name (wiki)`,"settings.wikis.switchHere":`Switch to this location`,"settings.wikis.resetToConfig":`Reset to the configured default`,"settings.wikis.locationHint":"Switching stops and restarts the TW child process in place (a few seconds); if the new folder has no tiddlywiki.info yet, the plugin runs `--init server` to create a fresh knowledge base there. The chosen location is remembered in a pointer file under $DSH_HOME (outside any wiki) and can be cleared with Reset to the configured default.","settings.wikis.locationUnavailable":`request failed`,"settings.wikis.current":`Current: {path}`,"settings.wikis.unknownPath":`(unknown)`,"settings.wikis.sourceState":`Source: pointer file (switched from this settings page)`,"settings.wikis.sourceConfig":`Source: cordis config (config.wikiRoot / config.wiki)`,"settings.wikis.sourceDefault":`Source: defaults ($DSH_HOME/tiddlywiki + main)`,"settings.wikis.sourceLine":`{source} · Configured default: {path}`,"settings.wikis.stateFile":`Pointer file: {path} (absent = using the configured default)`,"settings.wikis.candidatesLabel":`Wikis available in the same folder:`,"settings.wikis.rootItself":`(the root folder itself)`,"settings.wikis.candidateTitle":`Fill in the folder name "{name}"`,"settings.wikis.locationFailed":`Could not read the location: {message}`,"settings.wikis.needRoot":`Please fill in the root folder (an absolute path) first`,"settings.wikis.switchConfirm":`Switch the knowledge base to:
21
21
  {path}
22
22
 
23
- The TW child process will be stopped and restarted; this conversation and the tools will then read and write the new knowledge base. Continue?`,"settings.wikis.switching":`Switching… (restarting TW)`,"settings.wikis.switched":`Switched to {path}`,"settings.wikis.switchedWarn":`Switched to {path} (note: {warning})`,"settings.wikis.switchFailed":`Switch failed: {message}`,"settings.wikis.resetConfirm":`Reset to the configured default location? The location pointer file will be deleted and (if needed) the knowledge base from the config will be used again.`,"settings.wikis.resetDone":`Reset to the configured default: {path}`,"settings.wikis.resetWarn":`Reset to the default (note: {warning})`,"settings.wikis.resetFailed":`Reset failed: {message}`,"settings.iconPicker.label":`Icon`,"settings.iconPicker.aria":`Choose entry icon`,"settings.iconPicker.titleDefault":`Choose entry icon (default)`,"settings.iconPicker.titleCurrent":`Choose entry icon (current: {icon})`,"settings.iconPicker.default":`Default icon`,"settings.iconPicker.prev":`‹ Previous`,"settings.iconPicker.next":`Next ›`,"settings.iconPicker.page":`Page {page} of {pages} · {total} icons`,"settings.iconPicker.total":`{total} icons`,"settings.icon.archive":`Archive`,"settings.icon.archiveCheck":`Archive (done)`,"settings.icon.archiveOff":`Unarchive`,"settings.icon.unarchive":`Take out of archive`,"settings.icon.database":`Database`,"settings.icon.data":`Data`,"settings.icon.folder":`Folder`,"settings.icon.globe":`Globe / public`,"settings.icon.branch":`Branch`,"settings.icon.list":`List`,"settings.icon.checklist":`Checklist`,"settings.icon.flatList":`Flat list`,"settings.icon.skill":`Skill`,"settings.icon.goal":`Goal`,"settings.icon.compact":`Compact`,"settings.icon.clock":`Clock / history`,"settings.icon.alarm":`Reminder`,"settings.icon.pin":`Pinned`,"settings.icon.shield":`Secure / private`,"settings.icon.api":`API`,"settings.icon.code":`Code`,"settings.icon.users":`Team`,"settings.icon.user":`Personal`,"settings.icon.plugin":`Plugin`,"settings.icon.pinwheel":`Pinwheel`,"settings.icon.gauge":`Gauge / usage`,"settings.icon.tree":`Workspace tree`,"settings.icon.personalization":`Personalisation`,"settings.icon.link":`Link`,"settings.icon.search":`Search`,"settings.icon.settings":`Settings`,"settings.icon.sparkle":`Sparkle`,"settings.icon.think":`Thinking`,"settings.icon.light":`Light`,"settings.icon.dark":`Dark`,"settings.icon.refresh":`Refresh`,"settings.icon.book":`Book`,"settings.icon.briefcase":`Briefcase`,"settings.icon.home":`Home`,"settings.icon.notebook":`Notebook`,"settings.icon.flask":`Lab`,"settings.icon.star":`Star`,"settings.plugin.title":`Plugins (bundled official plugins)`,"settings.plugin.hint":`A tick writes the plugin into the startup install list in tiddlywiki.info (offline, matched to the engine version) and TW restarts on apply. This covers engine-bundled plugins only; plugins installed, disabled or removed in the TW control panel appear below under "Plugins inside the wiki".`,"settings.plugin.searchPlaceholder":`Search plugins…`,"settings.plugin.apply":`Apply plugins (restart TW)`,"settings.plugin.badgeDisabled":`Disabled in TW`,"settings.plugin.badgeDisabledTitle":`This plugin is in tiddlywiki.info but was disabled in the TW control panel ($:/config/Plugins/Disabled) — re-enable it there`,"settings.plugin.badgeInstalled":`Installed in wiki`,"settings.plugin.badgeInstalledTitle":`Not in the startup list, but the wiki holds a plugin tiddler with the same title (installed natively in TW) and the TW runtime is already using it`,"settings.plugin.applied":`Plugins applied, TW restarted`,"settings.wikiPlugins.title":`Plugins inside the wiki (installed natively in TW, read-only)`,"settings.wikiPlugins.hint":`These plugins are stored as tiddlers inside the wiki files (TW control panel → Plugins → install/import) and are not affected by the ticks above. Enable, disable or remove them from the TW control panel.`,"settings.wikiPlugins.disabled":`Disabled`,"settings.wikiPlugins.disabledTitle":`This plugin was disabled in the TW control panel`,"settings.themes.title":`Themes (bundled themes)`,"settings.themes.hint":`"Loaded" = themes available in TW (multi-select; the dependency chain comes along, e.g. heavier pulls in snowwhite+vanilla); "Active" = the theme you see (single choice, added to the loaded set automatically). TW restarts on apply.`,"settings.themes.colLoad":`Loaded`,"settings.themes.colActive":`Active`,"settings.themes.colTheme":`Theme`,"settings.themes.apply":`Apply themes (restart TW)`,"settings.themes.loadTitle":`Load this theme`,"settings.themes.activeTitle":`Make this the active theme`,"settings.themes.applied":`Themes applied, TW restarted`,"settings.langs.title":`Languages (bundled official language packs)`,"settings.langs.hint":`Tick to enable a language plugin and restart TW; for Chinese pick zh-Hans (simplified) or zh-CN.`,"settings.langs.apply":`Apply languages (restart TW)`,"settings.langs.applied":`Languages applied, TW restarted`,"settings.catalog.applyFailed":`Apply failed: {message}`,"settings.seeds.title":`Initialisation (one-time seeds)`,"settings.seeds.hint":`These are the tiddlers and settings the plugin seeds into the wiki so that it can work with dsh. "Send to agent button" and "TW front-end API base URL" are required: they are written automatically at startup (only when missing, never overwriting your edits). The rest are optional — not written by default and never forced. Click Re-initialise when you want them, and De-initialise to take them back out.`,"settings.seeds.fetchFailed":`request failed`,"settings.seeds.present":`Present`,"settings.seeds.missing":`Missing`,"settings.seeds.updateChip":`⬆ Update available`,"settings.seeds.updateTitle":`The built-in content changed after this wiki was seeded — click Re-initialise to take it`,"settings.seeds.modifiedChip":`✏️ Edited locally`,"settings.seeds.modifiedTitle":`This one is your content: re-initialising will overwrite it`,"settings.seeds.updateToBuiltin":`Update to built-in version`,"settings.seeds.reinit":`Re-initialise`,"settings.seeds.rewriteTitle":`Force-rewrite the built-in content of "{title}" (overwrites the current tiddler)`,"settings.seeds.overwriteModified":`"{title}" has local edits and updating will overwrite them.`,"settings.seeds.overwriteUnknown":`Cannot tell whether "{title}" was edited (old-style marker); updating may overwrite your changes.`,"settings.seeds.overwriteConfirm":`{warning}Overwrite with the built-in version?`,"settings.seeds.running":`Working…`,"settings.seeds.reinitFailed":`Re-initialise failed: {message}`,"settings.seeds.reinitDone":`Re-initialised "{title}"`,"settings.seeds.remove":`De-initialise`,"settings.seeds.removeTitle":`Remove the tiddlers and markers written by "{title}" (back to the never-seeded state)`,"settings.seeds.removeConfirm":`De-initialise "{title}"? The tiddlers it wrote (including its one-time marker) will be deleted; you can bring them back later with Re-initialise.`,"settings.seeds.removing":`Removing…`,"settings.seeds.removeFailed":`De-initialise failed: {message}`,"settings.seeds.removeDone":`De-initialised "{title}"`,"settings.seeds.statusLine":`{total} items, {present} ready; {removable} removable`,"settings.seeds.loadStatusFailed":`Could not load the initialisation status: {message}`,"settings.seeds.runAll":`Re-initialise all`,"settings.seeds.runAllTitle":`Force-rewrite every one-time seed (optional seeds included; overwrites the current tiddlers and settings)`,"settings.seeds.allReinitDone":`All seeds re-initialised`,"settings.seeds.removeAll":`De-initialise all`,"settings.seeds.removeAllTitle":`Remove the tiddlers and markers written by every optional seed (required items are kept)`,"settings.seeds.removeAllConfirm":`De-initialise all optional seeds? Every tiddler they wrote (including their one-time markers) will be deleted. Required items (the send-to-agent button and the TW front-end API base URL) are kept.`,"settings.seeds.allRemoved":`All optional seeds de-initialised`}},{zh:{"config.title":`常规配置`,"config.token.showHide":`显示 / 隐藏`,"config.num.empty":`不能为空`,"config.num.nan":`请输入数字`,"config.num.integer":`必须是整数`,"config.num.belowMin":`不能小于 {min}`,"config.num.aboveMax":`不能大于 {max}`,"config.num.invalidHint":`⚠️ {message}(保存会被拒绝)`,"config.note.tag":`快速笔记默认 tag`,"config.note.workspaceMark":`新建笔记自动标工作区(ws/<项目名> 标签 + workspace 字段,取自当前会话工作目录)`,"config.git.autoCommit":`自动 commit(防抖)`,"config.git.debounceMs":`自动 commit 防抖(ms;范围 0–3600000)`,"config.git.remote":`git 远端(空=仅本地;保存后即时生效,但**清空不会删除已配置的 origin**,需要时请用 git 命令处理)`,"config.git.branch":`git 分支(**只在仓库首次初始化时生效**;已有仓库请用 git 命令改分支——上面的状态行显示的是真实分支)`,"config.startup.readyTimeoutMs":`TW 启动就绪等待(ms;默认 60000,范围 5000–600000,超时上限为其 3 倍,对下次启动/重启生效)`,"config.ui.showQuickNote":`显示「知识库」按钮里的「快速笔记」入口`,"config.ui.showQuickNoteDock":`显示聊天输入框上方的「快速笔记」快捷按钮`,"config.ui.quickNoteMode":`点击「快速笔记」的打开方式`,"config.ui.quickNoteModeNative":`原生编辑器:直接弹出 TW 原生编辑页(新建/恢复草稿)`,"config.ui.quickNoteModeCard":`Markdown 卡片:弹出现有快速笔记卡片(CodeMirror 编辑器)`,"config.ui.multiWikiSidebarHint":`侧边栏入口:多库模式下每个知识库各占一行、各用自己的「显示名」(在「知识库列表」里改),不再是统一的一个名称,所以这里没有对应配置项。`,"config.ui.sidebarLabel":`侧边栏 TW 入口显示名称`,"config.ui.showPanelStatus":`显示「知识库」按钮里的 TW 面板/重载入口与状态行`,"config.ui.showSyncButton":`显示「知识库」按钮里的「同步」入口与 git 状态点`,"config.ui.followDshTheme":`嵌入式 TW 跟随 DSH 深浅主题(暗色时自动切深色 palette,不写回 wiki)`,"config.ui.darkPalette":`暗色时 TW palette(tiddler 标题)`,"config.ui.tabLabel":`会话顶部「知识库」Tab 名称`,"config.ui.showSessionTab":`显示会话顶部「知识库」Tab(本会话相关 wiki 笔记汇总)`,"config.ui.showRightbarTab":`在 DSH 右侧边栏提供 TiddlyWiki 入口/Tab(与聊天并排)`,"config.ui.sendToAgent.enabled":`启用「发送给 Agent」(TW 笔记 → DSH 会话注入)`,"config.ui.sendToAgent.endpoint":`TW 端请求基址(空=自动取当前 DSH origin)`,"config.ui.sendToAgent.token":`共享 token(非空时路由校验 x-send-to-agent-token 头;已设置时显示为 ********,原样保存=不改,清空=删除)`,"config.ui.allArticles.pageSize":`「所有文章」每页条数(1–200)`,"config.wechat.title":`可选功能:微信公众号发布`,"config.wechat.hint":`把 wiki 笔记一键发到公众号草稿箱(可选点发表)。**需要额外安装**:opencli 与 Browser Bridge 浏览器扩展,并让浏览器登录 mp.weixin.qq.com;adapter 在本仓库 tools/wechat/,安装与排错见 docs/wechat-publish-setup.md。不安装/不开启它,插件其他功能完全不受影响。开启后:注入提示词会多一条「发布前先读发布元数据规范」的约定,并在启动时把「发布元数据规范」与「微信公众号发布指南」(安装/换机还原步骤,等于仓库 docs/wechat-publish-setup.md)两篇文档写进 wiki(同名不覆盖)。`,"config.wechat.enabled":`启用微信公众号发布(默认关;需先按 docs/wechat-publish-setup.md 安装 opencli + 浏览器扩展)`,"config.wechat.command":`opencli 命令(默认 opencli;用别名或绝对路径时填这里。仅在启用微信发布时生效)`,"config.wechat.adapter":`发布适配器(仅在启用微信发布时生效)`,"config.wechat.adapterDefault":`publish-note(默认):图文排版,封面单图`,"config.wechat.adapterImgs":`publish-note-imgs:正文内嵌图全部上传 CDN(需先重跑 install-wechat-adapters.mjs)`,"config.wechat.token":`发布 token(非空时 /wechat/* 校验 x-wechat-publish-token 头,强烈建议设置,否则任何能打开本页的人都能替你发文;已设置时显示为 ********,原样保存=不改,清空=删除。仅在启用微信发布时生效)`,"config.wechat.dsn":`渲染基址 dsn(adapter 回连 DSH 用,形如 http://127.0.0.1:<端口>/dsh-tiddlywiki;留空=按请求自动推导。仅在启用微信发布时生效)`,"config.prompt.title":`系统提示词(注入每个会话)`,"config.prompt.hint":`插件把自己的约定(同步纪律 / 标签约定 / 链接格式等)注入每个会话的系统提示词。保存后**无需重启 dsh web**:section 会即时重新注册,当前会话从下一步起就使用新文本。`,"config.prompt.enabled":`注入 TiddlyWiki 提示词(关闭后本插件不再注入任何文本)`,"config.prompt.mode":`内置文本形态`,"config.prompt.modeSlim":`精简(默认):只保留工具 schema 表达不了的约定`,"config.prompt.modeFull":`完整:额外附一份由工具注册表实时生成的参数索引`,"config.prompt.extra":`附加说明(永远追加在末尾,可放团队/个人规范)`,"config.prompt.override":`整段替换(非空时取代上面的内置文本,附加说明仍会追加)`,"config.prompt.preview":`预览注入文本(按表单当前值)`,"config.prompt.previewTitle":`按表单当前值渲染注入文本(不用先保存);点「保存配置」后这就是实际注入的内容`,"config.prompt.fetchFailed":`获取失败`,"config.prompt.previewDisabled":`(已关闭:不会注入任何提示词)`,"config.prompt.previewHeader":`# 形态 {mode} · {length} 字符{dirty}
23
+ The TW child process will be stopped and restarted; this conversation and the tools will then read and write the new knowledge base. Continue?`,"settings.wikis.switching":`Switching… (restarting TW)`,"settings.wikis.switched":`Switched to {path}`,"settings.wikis.switchedWarn":`Switched to {path} (note: {warning})`,"settings.wikis.switchFailed":`Switch failed: {message}`,"settings.wikis.resetConfirm":`Reset to the configured default location? The location pointer file will be deleted and (if needed) the knowledge base from the config will be used again.`,"settings.wikis.resetDone":`Reset to the configured default: {path}`,"settings.wikis.resetWarn":`Reset to the default (note: {warning})`,"settings.wikis.resetFailed":`Reset failed: {message}`,"settings.iconPicker.label":`Icon`,"settings.iconPicker.aria":`Choose entry icon`,"settings.iconPicker.titleDefault":`Choose entry icon (default)`,"settings.iconPicker.titleCurrent":`Choose entry icon (current: {icon})`,"settings.iconPicker.default":`Default icon`,"settings.iconPicker.prev":`‹ Previous`,"settings.iconPicker.next":`Next ›`,"settings.iconPicker.page":`Page {page} of {pages} · {total} icons`,"settings.iconPicker.total":`{total} icons`,"settings.icon.archive":`Archive`,"settings.icon.archiveCheck":`Archive (done)`,"settings.icon.archiveOff":`Unarchive`,"settings.icon.unarchive":`Take out of archive`,"settings.icon.database":`Database`,"settings.icon.data":`Data`,"settings.icon.folder":`Folder`,"settings.icon.globe":`Globe / public`,"settings.icon.branch":`Branch`,"settings.icon.list":`List`,"settings.icon.checklist":`Checklist`,"settings.icon.flatList":`Flat list`,"settings.icon.skill":`Skill`,"settings.icon.goal":`Goal`,"settings.icon.compact":`Compact`,"settings.icon.clock":`Clock / history`,"settings.icon.alarm":`Reminder`,"settings.icon.pin":`Pinned`,"settings.icon.shield":`Secure / private`,"settings.icon.api":`API`,"settings.icon.code":`Code`,"settings.icon.users":`Team`,"settings.icon.user":`Personal`,"settings.icon.plugin":`Plugin`,"settings.icon.pinwheel":`Pinwheel`,"settings.icon.gauge":`Gauge / usage`,"settings.icon.tree":`Workspace tree`,"settings.icon.personalization":`Personalisation`,"settings.icon.link":`Link`,"settings.icon.search":`Search`,"settings.icon.settings":`Settings`,"settings.icon.sparkle":`Sparkle`,"settings.icon.think":`Thinking`,"settings.icon.light":`Light`,"settings.icon.dark":`Dark`,"settings.icon.refresh":`Refresh`,"settings.icon.book":`Book`,"settings.icon.briefcase":`Briefcase`,"settings.icon.home":`Home`,"settings.icon.notebook":`Notebook`,"settings.icon.flask":`Lab`,"settings.icon.star":`Star`,"settings.plugin.title":`Plugins (bundled official plugins)`,"settings.plugin.hint":`A tick writes the plugin into the startup install list in tiddlywiki.info (offline, matched to the engine version) and TW restarts on apply. This covers engine-bundled plugins only; plugins installed, disabled or removed in the TW control panel appear below under "Plugins inside the wiki".`,"settings.plugin.searchPlaceholder":`Search plugins…`,"settings.plugin.apply":`Apply plugins (restart TW)`,"settings.plugin.badgeDisabled":`Disabled in TW`,"settings.plugin.badgeDisabledTitle":`This plugin is in tiddlywiki.info but was disabled in the TW control panel ($:/config/Plugins/Disabled) — re-enable it there`,"settings.plugin.badgeInstalled":`Installed in wiki`,"settings.plugin.badgeInstalledTitle":`Not in the startup list, but the wiki holds a plugin tiddler with the same title (installed natively in TW) and the TW runtime is already using it`,"settings.plugin.applied":`Plugins applied, TW restarted`,"settings.wikiPlugins.title":`Plugins inside the wiki (installed natively in TW, read-only)`,"settings.wikiPlugins.hint":`These plugins are stored as tiddlers inside the wiki files (TW control panel → Plugins → install/import) and are not affected by the ticks above. Enable, disable or remove them from the TW control panel.`,"settings.wikiPlugins.disabled":`Disabled`,"settings.wikiPlugins.disabledTitle":`This plugin was disabled in the TW control panel`,"settings.themes.title":`Themes (bundled themes)`,"settings.themes.hint":`"Loaded" = themes available in TW (multi-select; the dependency chain comes along, e.g. heavier pulls in snowwhite+vanilla); "Active" = the theme you see (single choice, added to the loaded set automatically). TW restarts on apply.`,"settings.themes.colLoad":`Loaded`,"settings.themes.colActive":`Active`,"settings.themes.colTheme":`Theme`,"settings.themes.apply":`Apply themes (restart TW)`,"settings.themes.loadTitle":`Load this theme`,"settings.themes.activeTitle":`Make this the active theme`,"settings.themes.applied":`Themes applied, TW restarted`,"settings.langs.title":`Languages (bundled official language packs)`,"settings.langs.hint":`Tick to enable a language plugin and restart TW; for Chinese pick zh-Hans (simplified) or zh-CN.`,"settings.langs.apply":`Apply languages (restart TW)`,"settings.langs.applied":`Languages applied, TW restarted`,"settings.catalog.applyFailed":`Apply failed: {message}`,"settings.seeds.title":`Initialisation (one-time seeds)`,"settings.seeds.hint":`These are the tiddlers and settings the plugin seeds into the wiki so that it can work with dsh. "Send to agent button" and "TW front-end API base URL" are required: they are written automatically at startup (only when missing, never overwriting your edits). The rest are optional — not written by default and never forced. Click Re-initialise when you want them, and De-initialise to take them back out.`,"settings.seeds.fetchFailed":`request failed`,"settings.seeds.present":`Present`,"settings.seeds.missing":`Missing`,"settings.seeds.updateChip":`⬆ Update available`,"settings.seeds.updateTitle":`The built-in content changed after this wiki was seeded — click Re-initialise to take it`,"settings.seeds.modifiedChip":`✏️ Edited locally`,"settings.seeds.modifiedTitle":`This one is your content: re-initialising will overwrite it`,"settings.seeds.updateToBuiltin":`Update to built-in version`,"settings.seeds.reinit":`Re-initialise`,"settings.seeds.rewriteTitle":`Force-rewrite the built-in content of "{title}" (overwrites the current tiddler)`,"settings.seeds.overwriteModified":`"{title}" has local edits and updating will overwrite them.`,"settings.seeds.overwriteUnknown":`Cannot tell whether "{title}" was edited (old-style marker); updating may overwrite your changes.`,"settings.seeds.overwriteConfirm":`{warning}Overwrite with the built-in version?`,"settings.seeds.running":`Working…`,"settings.seeds.reinitFailed":`Re-initialise failed: {message}`,"settings.seeds.reinitDone":`Re-initialised "{title}"`,"settings.seeds.remove":`De-initialise`,"settings.seeds.removeTitle":`Remove the tiddlers and markers written by "{title}" (back to the never-seeded state)`,"settings.seeds.removeConfirm":`De-initialise "{title}"? The tiddlers it wrote (including its one-time marker) will be deleted; you can bring them back later with Re-initialise.`,"settings.seeds.removing":`Removing…`,"settings.seeds.removeFailed":`De-initialise failed: {message}`,"settings.seeds.removeDone":`De-initialised "{title}"`,"settings.seeds.statusLine":`{total} items, {present} ready; {removable} removable`,"settings.seeds.loadStatusFailed":`Could not load the initialisation status: {message}`,"settings.seeds.runAll":`Re-initialise all`,"settings.seeds.runAllTitle":`Force-rewrite every one-time seed (optional seeds included; overwrites the current tiddlers and settings)`,"settings.seeds.allReinitDone":`All seeds re-initialised`,"settings.seeds.removeAll":`De-initialise all`,"settings.seeds.removeAllTitle":`Remove the tiddlers and markers written by every optional seed (required items are kept)`,"settings.seeds.removeAllConfirm":`De-initialise all optional seeds? Every tiddler they wrote (including their one-time markers) will be deleted. Required items (the send-to-agent button and the TW front-end API base URL) are kept.`,"settings.seeds.allRemoved":`All optional seeds de-initialised`}},{zh:{"config.title":`常规配置`,"config.token.showHide":`显示 / 隐藏`,"config.num.empty":`不能为空`,"config.num.nan":`请输入数字`,"config.num.integer":`必须是整数`,"config.num.belowMin":`不能小于 {min}`,"config.num.aboveMax":`不能大于 {max}`,"config.num.invalidHint":`⚠️ {message}(保存会被拒绝)`,"config.note.tag":`快速笔记默认 tag`,"config.note.workspaceMark":`新建笔记自动标工作区(ws/<项目名> 标签 + workspace 字段,取自当前会话工作目录)`,"config.git.autoCommit":`自动 commit(防抖)`,"config.git.debounceMs":`自动 commit 防抖(ms;范围 0–3600000)`,"config.git.remote":"git 远端(**空=自动用该库所在仓库的 `origin`**;填了则以填的为准。保存后即时生效,但**清空不会删除已配置的 origin**,需要时请用 git 命令处理)","config.git.branch":`git 分支(**只在仓库首次初始化时生效**;已有仓库请用 git 命令改分支——上面的状态行显示的是真实分支)`,"config.startup.readyTimeoutMs":`TW 启动就绪等待(ms;默认 60000,范围 5000–600000,超时上限为其 3 倍,对下次启动/重启生效)`,"config.ui.showQuickNote":`显示「知识库」按钮里的「快速笔记」入口`,"config.ui.showQuickNoteDock":`显示聊天输入框上方的「快速笔记」快捷按钮`,"config.ui.quickNoteMode":`点击「快速笔记」的打开方式`,"config.ui.quickNoteModeNative":`原生编辑器:直接弹出 TW 原生编辑页(新建/恢复草稿)`,"config.ui.quickNoteModeCard":`Markdown 卡片:弹出现有快速笔记卡片(CodeMirror 编辑器)`,"config.ui.multiWikiSidebarHint":`侧边栏入口:多库模式下每个知识库各占一行、各用自己的「显示名」(在「知识库列表」里改),不再是统一的一个名称,所以这里没有对应配置项。`,"config.ui.sidebarLabel":`侧边栏 TW 入口显示名称`,"config.ui.showPanelStatus":`显示「知识库」按钮里的 TW 面板/重载入口与状态行`,"config.ui.showSyncButton":`显示「知识库」按钮里的「同步」入口与 git 状态点`,"config.ui.followDshTheme":`嵌入式 TW 跟随 DSH 深浅主题(暗色时自动切深色 palette,不写回 wiki)`,"config.ui.darkPalette":`暗色时 TW palette(tiddler 标题)`,"config.ui.tabLabel":`会话顶部「知识库」Tab 名称`,"config.ui.showSessionTab":`显示会话顶部「知识库」Tab(本会话相关 wiki 笔记汇总)`,"config.ui.showRightbarTab":`在 DSH 右侧边栏提供 TiddlyWiki 入口/Tab(与聊天并排)`,"config.ui.sendToAgent.enabled":`启用「发送给 Agent」(TW 笔记 → DSH 会话注入)`,"config.ui.sendToAgent.endpoint":`TW 端请求基址(空=自动取当前 DSH origin)`,"config.ui.sendToAgent.token":`共享 token(非空时路由校验 x-send-to-agent-token 头;已设置时显示为 ********,原样保存=不改,清空=删除)`,"config.ui.allArticles.pageSize":`「所有文章」每页条数(1–200)`,"config.wechat.title":`可选功能:微信公众号发布`,"config.wechat.hint":`把 wiki 笔记一键发到公众号草稿箱(可选点发表)。**需要额外安装**:opencli 与 Browser Bridge 浏览器扩展,并让浏览器登录 mp.weixin.qq.com;adapter 在本仓库 tools/wechat/,安装与排错见 docs/wechat-publish-setup.md。不安装/不开启它,插件其他功能完全不受影响。开启后:注入提示词会多一条「发布前先读发布元数据规范」的约定,并在启动时把「发布元数据规范」与「微信公众号发布指南」(安装/换机还原步骤,等于仓库 docs/wechat-publish-setup.md)两篇文档写进 wiki(同名不覆盖)。`,"config.wechat.enabled":`启用微信公众号发布(默认关;需先按 docs/wechat-publish-setup.md 安装 opencli + 浏览器扩展)`,"config.wechat.command":`opencli 命令(默认 opencli;用别名或绝对路径时填这里。仅在启用微信发布时生效)`,"config.wechat.adapter":`发布适配器(仅在启用微信发布时生效)`,"config.wechat.adapterDefault":`publish-note(默认):图文排版,封面单图`,"config.wechat.adapterImgs":`publish-note-imgs:正文内嵌图全部上传 CDN(需先重跑 install-wechat-adapters.mjs)`,"config.wechat.token":`发布 token(非空时 /wechat/* 校验 x-wechat-publish-token 头,强烈建议设置,否则任何能打开本页的人都能替你发文;已设置时显示为 ********,原样保存=不改,清空=删除。仅在启用微信发布时生效)`,"config.wechat.dsn":`渲染基址 dsn(adapter 回连 DSH 用,形如 http://127.0.0.1:<端口>/dsh-tiddlywiki;留空=按请求自动推导。仅在启用微信发布时生效)`,"config.prompt.title":`系统提示词(注入每个会话)`,"config.prompt.hint":`插件把自己的约定(同步纪律 / 标签约定 / 链接格式等)注入每个会话的系统提示词。保存后**无需重启 dsh web**:section 会即时重新注册,当前会话从下一步起就使用新文本。`,"config.prompt.enabled":`注入 TiddlyWiki 提示词(关闭后本插件不再注入任何文本)`,"config.prompt.mode":`内置文本形态`,"config.prompt.modeSlim":`精简(默认):只保留工具 schema 表达不了的约定`,"config.prompt.modeFull":`完整:额外附一份由工具注册表实时生成的参数索引`,"config.prompt.extra":`附加说明(永远追加在末尾,可放团队/个人规范)`,"config.prompt.override":`整段替换(非空时取代上面的内置文本,附加说明仍会追加)`,"config.prompt.preview":`预览注入文本(按表单当前值)`,"config.prompt.previewTitle":`按表单当前值渲染注入文本(不用先保存);点「保存配置」后这就是实际注入的内容`,"config.prompt.fetchFailed":`获取失败`,"config.prompt.previewDisabled":`(已关闭:不会注入任何提示词)`,"config.prompt.previewHeader":`# 形态 {mode} · {length} 字符{dirty}
24
24
 
25
- {text}`,"config.prompt.previewDirty":`(含未保存的修改,保存后才真正注入)`,"config.prompt.readFailed":`读取提示词失败:{message}`,"config.bridge.enabled":`启用「本地剪藏桥」(书签小工具后端监听 127.0.0.1 端口,保存后立即生效)`,"config.bridge.port":`剪藏桥端口(整数 1–65535;改端口需重启 dsh web 生效)`,"config.bridge.token":`剪藏桥 token(非空时校验书签的 x-clip-token 头;强烈建议设置。已设置时显示为 ********,原样保存=不改,清空=删除)`,"config.bridge.tag":`剪藏笔记默认 tag`,"config.bridge.wiki":`剪藏写入的知识库(不指定 = 写进知识库列表里带 ★ 的那个库;多库时可指定具体的库)`,"config.clipWiki.followDefault":`(跟随默认的那个库)`,"config.clipWiki.defaultSuffix":`{label}(默认)`,"config.clipWiki.option":`{label}({id}){suffix}`,"config.clipWiki.notRunning":` · 未运行`,"config.clipWiki.notInListWithDefault":`{current}(不在清单里,保存后写进 {label})`,"config.clipWiki.notInList":`{current}(不在清单里)`,"config.save":`保存配置`,"config.invalidFields":`有 {count} 个字段填得不对(见字段旁的红色提示),未保存`,"config.noChanges":`没有改动`,"config.saved":`配置已保存`,"config.saveFailed":`保存失败:{message}`},en:{"config.title":`General settings`,"config.token.showHide":`Show / hide`,"config.num.empty":`Cannot be empty`,"config.num.nan":`Enter a number`,"config.num.integer":`Must be an integer`,"config.num.belowMin":`Cannot be less than {min}`,"config.num.aboveMax":`Cannot be greater than {max}`,"config.num.invalidHint":`⚠️ {message} (save will be refused)`,"config.note.tag":`Default tag for quick notes`,"config.note.workspaceMark":`Tag new notes with their workspace (ws/<project> tag + workspace field, taken from the session working directory)`,"config.git.autoCommit":`Auto-commit (debounced)`,"config.git.debounceMs":`Auto-commit debounce (ms; range 0–3600000)`,"config.git.remote":`Git remote (empty = local only; takes effect right after saving, but **clearing it does NOT delete a configured origin** — use git commands for that)`,"config.git.branch":`Git branch (**only used when the repository is first initialised**; for an existing repository change the branch with git commands — the status row above shows the real branch)`,"config.startup.readyTimeoutMs":`TW startup readiness wait (ms; default 60000, range 5000–600000, hard limit 3× that, applies to the next start/restart)`,"config.ui.showQuickNote":`Show the Quick note entry in the Knowledge base button`,"config.ui.showQuickNoteDock":`Show the Quick note shortcut above the chat input`,"config.ui.quickNoteMode":`What clicking Quick note opens`,"config.ui.quickNoteModeNative":`Native editor: opens the TW edit page directly (new or restored draft)`,"config.ui.quickNoteModeCard":`Markdown card: opens the quick-note card (CodeMirror editor)`,"config.ui.multiWikiSidebarHint":`Sidebar entry: in multi-wiki mode every knowledge base gets its own row and its own display name (edited in the knowledge-base list), so there is no single name to configure here.`,"config.ui.sidebarLabel":`Sidebar TW entry display name`,"config.ui.showPanelStatus":`Show the TW panel / reload entry and status row in the Knowledge base button`,"config.ui.showSyncButton":`Show the Sync entry and git status dot in the Knowledge base button`,"config.ui.followDshTheme":`Make the embedded TW follow the DSH light/dark theme (switch palette in dark mode, never written back to the wiki)`,"config.ui.darkPalette":`TW palette in dark mode (tiddler title)`,"config.ui.tabLabel":`Name of the Knowledge base tab above the conversation`,"config.ui.showSessionTab":`Show the Knowledge base tab above the conversation (wiki notes related to this session)`,"config.ui.showRightbarTab":`Offer a TiddlyWiki entry/tab in the DSH right sidebar (next to the chat)`,"config.ui.sendToAgent.enabled":`Enable Send to agent (TW note → inject into the DSH conversation)`,"config.ui.sendToAgent.endpoint":`TW-side request base URL (empty = use the current DSH origin)`,"config.ui.sendToAgent.token":`Shared token (when non-empty the route checks the x-send-to-agent-token header; shown as ******** once set — saving it unchanged keeps it, clearing it deletes it)`,"config.ui.allArticles.pageSize":`Items per page in All articles (1–200)`,"config.wechat.title":`Optional feature: publishing to WeChat official accounts`,"config.wechat.hint":`Publish wiki notes to the official-account draft box in one click (publishing itself stays optional). **Extra installation required**: opencli and the Browser Bridge browser extension, plus a browser signed in to mp.weixin.qq.com; the adapter lives in tools/wechat/ of this repository, see docs/wechat-publish-setup.md for installation and troubleshooting. Not installing or not enabling it leaves every other feature untouched. Once enabled: the injected prompt gains a "read the publishing metadata spec first" convention, and two documents — the publishing metadata spec and the WeChat publishing guide (install / restore-on-a-new-machine steps, i.e. docs/wechat-publish-setup.md) — are written into the wiki at startup (existing files are never overwritten).`,"config.wechat.enabled":`Enable WeChat official-account publishing (off by default; install opencli + the browser extension as described in docs/wechat-publish-setup.md first)`,"config.wechat.command":`opencli command (default opencli; put an alias or absolute path here. Only used when WeChat publishing is enabled)`,"config.wechat.adapter":`Publishing adapter (only used when WeChat publishing is enabled)`,"config.wechat.adapterDefault":`publish-note (default): laid-out text with a single cover image`,"config.wechat.adapterImgs":`publish-note-imgs: every inline image is uploaded to a CDN (re-run install-wechat-adapters.mjs first)`,"config.wechat.token":`Publishing token (when non-empty /wechat/* checks the x-wechat-publish-token header; strongly recommended, otherwise anyone who can open this page can publish as you. Shown as ******** once set — saving it unchanged keeps it, clearing it deletes it. Only used when WeChat publishing is enabled)`,"config.wechat.dsn":`Render base dsn (for the adapter to call back into DSH, e.g. http://127.0.0.1:<port>/dsh-tiddlywiki; empty = derived from the request. Only used when WeChat publishing is enabled)`,"config.prompt.title":`System prompt (injected into every session)`,"config.prompt.hint":`The plugin injects its own conventions (sync discipline, tag rules, link format and so on) into every session system prompt. Saving needs **no dsh web restart**: the section is re-registered immediately and the current session uses the new text from its next step.`,"config.prompt.enabled":`Inject the TiddlyWiki prompt (when off the plugin injects no text at all)`,"config.prompt.mode":`Built-in text form`,"config.prompt.modeSlim":`Slim (default): keeps only the conventions the tool schemas cannot express`,"config.prompt.modeFull":`Full: adds a parameter index generated live from the tool registry`,"config.prompt.extra":`Extra notes (always appended at the end; good for team or personal rules)`,"config.prompt.override":`Full replacement (when non-empty it replaces the built-in text above; extra notes are still appended)`,"config.prompt.preview":`Preview the injected text (from the current form values)`,"config.prompt.previewTitle":`Render the injected text from the current form values (no need to save first); after Save this is exactly what gets injected`,"config.prompt.fetchFailed":`request failed`,"config.prompt.previewDisabled":`(disabled: no prompt will be injected)`,"config.prompt.previewHeader":`# form {mode} · {length} characters{dirty}
25
+ {text}`,"config.prompt.previewDirty":`(含未保存的修改,保存后才真正注入)`,"config.prompt.readFailed":`读取提示词失败:{message}`,"config.bridge.enabled":`启用「本地剪藏桥」(书签小工具后端监听 127.0.0.1 端口,保存后立即生效)`,"config.bridge.port":`剪藏桥端口(整数 1–65535;改端口需重启 dsh web 生效)`,"config.bridge.token":`剪藏桥 token(非空时校验书签的 x-clip-token 头;强烈建议设置。已设置时显示为 ********,原样保存=不改,清空=删除)`,"config.bridge.tag":`剪藏笔记默认 tag`,"config.bridge.wiki":`剪藏写入的知识库(不指定 = 写进知识库列表里带 ★ 的那个库;多库时可指定具体的库)`,"config.clipWiki.followDefault":`(跟随默认的那个库)`,"config.clipWiki.defaultSuffix":`{label}(默认)`,"config.clipWiki.option":`{label}({id}){suffix}`,"config.clipWiki.notRunning":` · 未运行`,"config.clipWiki.notInListWithDefault":`{current}(不在清单里,保存后写进 {label})`,"config.clipWiki.notInList":`{current}(不在清单里)`,"config.save":`保存配置`,"config.invalidFields":`有 {count} 个字段填得不对(见字段旁的红色提示),未保存`,"config.noChanges":`没有改动`,"config.saved":`配置已保存`,"config.saveFailed":`保存失败:{message}`},en:{"config.title":`General settings`,"config.token.showHide":`Show / hide`,"config.num.empty":`Cannot be empty`,"config.num.nan":`Enter a number`,"config.num.integer":`Must be an integer`,"config.num.belowMin":`Cannot be less than {min}`,"config.num.aboveMax":`Cannot be greater than {max}`,"config.num.invalidHint":`⚠️ {message} (save will be refused)`,"config.note.tag":`Default tag for quick notes`,"config.note.workspaceMark":`Tag new notes with their workspace (ws/<project> tag + workspace field, taken from the session working directory)`,"config.git.autoCommit":`Auto-commit (debounced)`,"config.git.debounceMs":`Auto-commit debounce (ms; range 0–3600000)`,"config.git.remote":"Git remote (**empty = use the `origin` of the repository this wiki lives in**; a value here overrides it. Takes effect right after saving, but **clearing it does NOT delete a configured origin** — use git commands for that)","config.git.branch":`Git branch (**only used when the repository is first initialised**; for an existing repository change the branch with git commands — the status row above shows the real branch)`,"config.startup.readyTimeoutMs":`TW startup readiness wait (ms; default 60000, range 5000–600000, hard limit 3× that, applies to the next start/restart)`,"config.ui.showQuickNote":`Show the Quick note entry in the Knowledge base button`,"config.ui.showQuickNoteDock":`Show the Quick note shortcut above the chat input`,"config.ui.quickNoteMode":`What clicking Quick note opens`,"config.ui.quickNoteModeNative":`Native editor: opens the TW edit page directly (new or restored draft)`,"config.ui.quickNoteModeCard":`Markdown card: opens the quick-note card (CodeMirror editor)`,"config.ui.multiWikiSidebarHint":`Sidebar entry: in multi-wiki mode every knowledge base gets its own row and its own display name (edited in the knowledge-base list), so there is no single name to configure here.`,"config.ui.sidebarLabel":`Sidebar TW entry display name`,"config.ui.showPanelStatus":`Show the TW panel / reload entry and status row in the Knowledge base button`,"config.ui.showSyncButton":`Show the Sync entry and git status dot in the Knowledge base button`,"config.ui.followDshTheme":`Make the embedded TW follow the DSH light/dark theme (switch palette in dark mode, never written back to the wiki)`,"config.ui.darkPalette":`TW palette in dark mode (tiddler title)`,"config.ui.tabLabel":`Name of the Knowledge base tab above the conversation`,"config.ui.showSessionTab":`Show the Knowledge base tab above the conversation (wiki notes related to this session)`,"config.ui.showRightbarTab":`Offer a TiddlyWiki entry/tab in the DSH right sidebar (next to the chat)`,"config.ui.sendToAgent.enabled":`Enable Send to agent (TW note → inject into the DSH conversation)`,"config.ui.sendToAgent.endpoint":`TW-side request base URL (empty = use the current DSH origin)`,"config.ui.sendToAgent.token":`Shared token (when non-empty the route checks the x-send-to-agent-token header; shown as ******** once set — saving it unchanged keeps it, clearing it deletes it)`,"config.ui.allArticles.pageSize":`Items per page in All articles (1–200)`,"config.wechat.title":`Optional feature: publishing to WeChat official accounts`,"config.wechat.hint":`Publish wiki notes to the official-account draft box in one click (publishing itself stays optional). **Extra installation required**: opencli and the Browser Bridge browser extension, plus a browser signed in to mp.weixin.qq.com; the adapter lives in tools/wechat/ of this repository, see docs/wechat-publish-setup.md for installation and troubleshooting. Not installing or not enabling it leaves every other feature untouched. Once enabled: the injected prompt gains a "read the publishing metadata spec first" convention, and two documents — the publishing metadata spec and the WeChat publishing guide (install / restore-on-a-new-machine steps, i.e. docs/wechat-publish-setup.md) — are written into the wiki at startup (existing files are never overwritten).`,"config.wechat.enabled":`Enable WeChat official-account publishing (off by default; install opencli + the browser extension as described in docs/wechat-publish-setup.md first)`,"config.wechat.command":`opencli command (default opencli; put an alias or absolute path here. Only used when WeChat publishing is enabled)`,"config.wechat.adapter":`Publishing adapter (only used when WeChat publishing is enabled)`,"config.wechat.adapterDefault":`publish-note (default): laid-out text with a single cover image`,"config.wechat.adapterImgs":`publish-note-imgs: every inline image is uploaded to a CDN (re-run install-wechat-adapters.mjs first)`,"config.wechat.token":`Publishing token (when non-empty /wechat/* checks the x-wechat-publish-token header; strongly recommended, otherwise anyone who can open this page can publish as you. Shown as ******** once set — saving it unchanged keeps it, clearing it deletes it. Only used when WeChat publishing is enabled)`,"config.wechat.dsn":`Render base dsn (for the adapter to call back into DSH, e.g. http://127.0.0.1:<port>/dsh-tiddlywiki; empty = derived from the request. Only used when WeChat publishing is enabled)`,"config.prompt.title":`System prompt (injected into every session)`,"config.prompt.hint":`The plugin injects its own conventions (sync discipline, tag rules, link format and so on) into every session system prompt. Saving needs **no dsh web restart**: the section is re-registered immediately and the current session uses the new text from its next step.`,"config.prompt.enabled":`Inject the TiddlyWiki prompt (when off the plugin injects no text at all)`,"config.prompt.mode":`Built-in text form`,"config.prompt.modeSlim":`Slim (default): keeps only the conventions the tool schemas cannot express`,"config.prompt.modeFull":`Full: adds a parameter index generated live from the tool registry`,"config.prompt.extra":`Extra notes (always appended at the end; good for team or personal rules)`,"config.prompt.override":`Full replacement (when non-empty it replaces the built-in text above; extra notes are still appended)`,"config.prompt.preview":`Preview the injected text (from the current form values)`,"config.prompt.previewTitle":`Render the injected text from the current form values (no need to save first); after Save this is exactly what gets injected`,"config.prompt.fetchFailed":`request failed`,"config.prompt.previewDisabled":`(disabled: no prompt will be injected)`,"config.prompt.previewHeader":`# form {mode} · {length} characters{dirty}
26
26
 
27
27
  {text}`,"config.prompt.previewDirty":` (includes unsaved edits; only saved values are really injected)`,"config.prompt.readFailed":`Could not read the prompt: {message}`,"config.bridge.enabled":`Enable the local clip bridge (bookmarklet backend listening on a 127.0.0.1 port; effective immediately after saving)`,"config.bridge.port":`Clip bridge port (integer 1–65535; changing it needs a dsh web restart)`,"config.bridge.token":`Clip bridge token (when non-empty the bookmarklet x-clip-token header is checked; strongly recommended. Shown as ******** once set — saving it unchanged keeps it, clearing it deletes it)`,"config.bridge.tag":`Default tag for clipped notes`,"config.bridge.wiki":`Knowledge base that clips are written to (unspecified = the one marked ★ in the knowledge-base list; in multi-wiki mode you can name a specific one)`,"config.clipWiki.followDefault":`(follow whichever wiki is the default)`,"config.clipWiki.defaultSuffix":`{label} (default)`,"config.clipWiki.option":`{label} ({id}){suffix}`,"config.clipWiki.notRunning":` · not running`,"config.clipWiki.notInListWithDefault":`{current} (not in the list; saving writes to {label})`,"config.clipWiki.notInList":`{current} (not in the list)`,"config.save":`Save settings`,"config.invalidFields":`{count} fields are filled in incorrectly (see the red hint next to them); nothing was saved`,"config.noChanges":`No changes`,"config.saved":`Settings saved`,"config.saveFailed":`Save failed: {message}`}},{zh:{},en:{}},{zh:{"frame.syncRestarted":`,TW 已重启`,"frame.syncNotRestarted":`,TW 未自动重启`,"frame.rightbarTitle":`TiddlyWiki 知识库`,"frame.rightbarDescription":`在右侧边栏打开 TiddlyWiki 编辑器(与聊天并排)`,"frame.settingsSection":`TiddlyWiki 知识库`,"frame.syncTooltip":`同步知识库`,"frame.gitUnavailable":`git 仓库不可用`,"frame.branch":`分支 {branch}`,"frame.ahead":`领先 {n}`,"frame.behind":`落后 {n}`,"frame.dirty":`有 {n} 个未提交改动`,"frame.lastSync":`上次同步 {time}`,"frame.syncing":`同步进行中…`,"frame.syncDone":`同步完成:{message}`,"frame.syncFailed":`同步失败:{message}`,"frame.tabLabelDefault":`知识库`,"frame.twUnavailable":`TiddlyWiki 服务不可用`,"frame.twStarting":`TiddlyWiki 服务正在启动…`,"frame.retry":`重试`,"frame.restarting":`重启中…`,"frame.loadingWiki":`正在载入知识库「{label}」…`,"frame.statusUnreachable":`无法访问 /dsh-tiddlywiki/status`,"frame.noEditorUrl":`服务未返回编辑器地址`,"frame.statusError":`服务状态:{status}`},en:{"frame.syncRestarted":`, TiddlyWiki restarted`,"frame.syncNotRestarted":`, TiddlyWiki was not restarted automatically`,"frame.rightbarTitle":`TiddlyWiki knowledge base`,"frame.rightbarDescription":`Open the TiddlyWiki editor in the right sidebar, next to the chat`,"frame.settingsSection":`TiddlyWiki knowledge base`,"frame.syncTooltip":`Sync knowledge base`,"frame.gitUnavailable":`git repository unavailable`,"frame.branch":`branch {branch}`,"frame.ahead":`{n} ahead`,"frame.behind":`{n} behind`,"frame.dirty":`{n} uncommitted change(s)`,"frame.lastSync":`last synced {time}`,"frame.syncing":`Syncing…`,"frame.syncDone":`Sync finished: {message}`,"frame.syncFailed":`Sync failed: {message}`,"frame.tabLabelDefault":`Knowledge base`,"frame.twUnavailable":`TiddlyWiki service unavailable`,"frame.twStarting":`TiddlyWiki service is starting…`,"frame.retry":`Retry`,"frame.restarting":`Restarting…`,"frame.loadingWiki":`Loading knowledge base "{label}"…`,"frame.statusUnreachable":`Cannot reach /dsh-tiddlywiki/status`,"frame.noEditorUrl":`The service returned no editor address`,"frame.statusError":`Service status: {status}`}}],u={zh:Object.assign({},...l.map(e=>e.zh)),en:Object.assign({},...l.map(e=>e.en))},d=`dsh-tiddlywiki:lang`;function f(e){if(typeof e!=`string`)return`zh`;let t=e.trim().toLowerCase();return t.startsWith(`en`)?`en`:(t.startsWith(`zh`),`zh`)}function p(){try{let e=globalThis.localStorage?.getItem(d);return e==null?void 0:f(e)}catch{return}}let m=p()??`zh`;function h(){return m}function g(e){let t=f(e),n=t!==m;m=t;try{globalThis.localStorage?.setItem(d,t)}catch{}return n}function _(e,t){let n=u[m],r=u.zh,i=n?.[e]??r?.[e]??e;return t===void 0?i:i.replace(/\{(\w+)\}/g,(e,n)=>{let r=t[n];return r===void 0?e:String(r)})}const v=`
28
28
  /* ── sidebar entry ───────────────────────────────────────────── */