dsh-tiddlywiki 0.16.21 → 0.16.23

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.
@@ -1,92 +1,96 @@
1
- /**
2
- * Generated from the wiki home tiddlers (do not hand-edit the constants).
3
- * Source: 🏠 主页.tid, 所有标签.tid, 标签笔记.tid
4
- *
5
- * The "首页" tiddlers that the plugin's system prompt promises (待办四象限 +
6
- * 所有标签统计 + 标签笔记): seeded into fresh wikis by seedHomeIndex, so new
7
- * users get the same home page instead of an empty wiki. 🏠 主页 is the
8
- * default home (the seed also ensures $:/DefaultTiddlers → [[🏠 主页]]).
9
- *
10
- * @module dsh-tiddlywiki/host/seed-home
11
- */
12
- import type { TiddlyWebClient } from './tw-api.ts'
13
-
14
- /** One-time marker: presence means "the home was offered once — hands off". */
15
- export const HOME_INDEX_MARKER_TITLE = '$:/plugins/dsh-tiddlywiki/seed-home-index'
16
-
17
- /** The $:/DefaultTiddlers body so 🏠 主页 opens by default in fresh wikis. */
18
- export const HOME_DEFAULT_TIDDLERS = "[[🏠 主页]]"
19
-
20
- export interface HomeIndexItem {
21
- title: string
22
- tags: string[]
23
- type: string
24
- text: string
25
- }
26
-
27
- /** The home tiddlers, exactly as seeded (user-owned afterwards). */
28
- export const HOME_INDEX_ITEMS: HomeIndexItem[] = [{"title":"🏠 主页","tags":["索引","TableOfContents"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n\\define quadrant-board()\n<div style=\"display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:8px;\">\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:8px 12px; background:linear-gradient(135deg,#e74c3c1a,transparent);\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🔴 重要 · 紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q1]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q1]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q1]!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</div>\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:8px 12px; background:linear-gradient(135deg,#3498db1a,transparent);\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🔵 重要 · 不紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q2]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q2]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q2]!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</div>\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:8px 12px; background:linear-gradient(135deg,#f39c121a,transparent);\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🟠 紧急 · 不重要 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q3]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q3]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q3]!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</div>\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:8px 12px; background:linear-gradient(135deg,#95a5a61a,transparent);\">\n<div style=\"font-weight:700; margin-bottom:6px;\">⚪ 不重要 · 不紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q4]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q4]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q4]!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</div>\n</div>\n\\end\n\n<$set name=\"today\" value=<<now \"YYYY0MM0DD\">>>\n\n!! 🏠 主页\n\n<div class=\"tc-message-box\">待办看板与知识库入口。</div>\n\n<div style=\"display:flex; gap:8px; flex-wrap:wrap; margin:8px 0;\">\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"padding:6px 16px; border:1px solid rgba(128,128,128,0.35); border-radius:8px; font-weight:600;\">\n<$action-navigate $to=\"所有标签\"/>\n🏷 所有标签\n</$button>\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"padding:6px 16px; border:1px solid rgba(128,128,128,0.35); border-radius:8px; font-weight:600;\">\n<$action-navigate $to=\"所有文章\"/>\n📚 所有文章\n</$button>\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"padding:6px 16px; border:1px solid rgba(128,128,128,0.35); border-radius:8px; font-weight:600;\">\n<$action-navigate $to=\"主题汇总·示例\"/>\n🗂 主题汇总\n</$button>\n</div>\n\n!! ✍️ 快速记笔记(完整编辑器)\n\n<div class=\"tc-message-box\">直接在首页写笔记:填标题、用工具栏写正文(支持 Markdown:**加粗**、*斜体*、# 标题、- 列表、> 引用 等)、加标签,点「💾 保存」即创建新笔记(默认 Markdown,标题留空用当前时间)。勾选「同时加入待办」并选象限,可一并进入下方四象限看板。</div>\n\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:10px 12px; margin:10px 0;\">\n\n<div style=\"display:flex; gap:6px; align-items:center; margin-bottom:6px;\">\n<$edit-text tiddler=\"$:/state/home-note/title\" tag=\"input\" placeholder=\"标题(留空用当前时间)\" style=\"flex:1; min-width:200px; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\"/>\n</div>\n\n<$edit-text tiddler=\"$:/state/home-note/text\" tag=\"textarea\" class=\"tc-edit-texteditor\" autoHeight=\"yes\" minHeight=\"150px\" placeholder=\"正文:支持 **加粗**、*斜体*、# 标题、- 列表、> 引用 等 Markdown 语法\" style=\"width:100%; box-sizing:border-box; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<$button class=\"tc-btn-invisible\" tooltip=\"加粗\" style=\"padding:2px 8px; font-weight:700;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"**\" suffix=\"**\" trimSelection=\"yes\"/>B</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"斜体\" style=\"padding:2px 8px; font-style:italic;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"*\" suffix=\"*\" trimSelection=\"yes\"/>I</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"删除线\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"~~\" suffix=\"~~\" trimSelection=\"yes\"/>S</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"标题\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"#\" count=\"1\"/>H</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"无序列表\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"-\" count=\"1\"/>•</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"有序列表\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"1.\" count=\"1\"/>1.</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"引用\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\">\" count=\"1\"/>❝</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"行内代码\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"`\" suffix=\"`\" trimSelection=\"yes\"/>&lt;/&gt;</$button>\n</$edit-text>\n\n<div style=\"display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-top:6px;\">\n<$edit-text tiddler=\"$:/state/home-note/tags\" tag=\"input\" placeholder=\"标签(逗号分隔,可选)\" style=\"flex:1; min-width:160px; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\"/>\n<$checkbox tiddler=\"$:/state/home-note/todo\" field=\"text\" checked=\"yes\" unchecked=\"no\"> 同时加入待办</$checkbox>\n<$select tiddler=\"$:/state/home-note/quadrant\" default=\"q2\" style=\"padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<option value=\"q1\">Q1 重要·紧急</option>\n<option value=\"q2\">Q2 重要·不紧急</option>\n<option value=\"q3\">Q3 紧急·不重要</option>\n<option value=\"q4\">Q4 不重要·不紧急</option>\n</$select>\n</div>\n\n<div style=\"display:flex; gap:6px; align-items:center; margin-top:8px; flex-wrap:wrap;\">\n<$button class=\"tc-btn-invisible\" style=\"padding:6px 16px; border-radius:6px; border:1px solid rgba(128,128,128,0.35); font-weight:600; background:rgba(128,128,128,0.06);\">\n<$list filter=\"[{$:/state/home-note/title}!is[blank]] [{$:/state/home-note/text}!is[blank]]\">\n<$action-createtiddler\n$basetitle={{{ [{$:/state/home-note/title}!is[blank]then{$:/state/home-note/title}] ~[<now \"YYYY-MM-DD-HHmm\">] }}}\ntext={{{ [{$:/state/home-note/text}] }}}\ntags={{{ [{$:/state/home-note/tags}split[,]split[,]trim[]] [{$:/state/home-note/todo}match[yes]then[[todo]]] +[join[ ]] }}}\nq={{{ [{$:/state/home-note/todo}match[yes]then{$:/state/home-note/quadrant}!is[blank]] ~[{$:/state/home-note/todo}match[yes]then[q2]] }}}\ntype=\"text/markdown\"\n$savetitle=\"$:/state/home-note/last-created\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/title\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/text\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/tags\" text=\"\"/>\n</$list>\n💾 保存\n</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"清空草稿\" style=\"padding:6px 12px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<$action-setfield $tiddler=\"$:/state/home-note/title\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/text\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/tags\" text=\"\"/>\n🗑 清空\n</$button>\n<$list filter=\"[{$:/state/home-note/last-created}!is[blank]]\">\n<span style=\"color:#2e7d32; font-size:0.9em;\">✅ 已保存:<$link to={{{ [{$:/state/home-note/last-created}] }}}>{{{$:/state/home-note/last-created}}}</$link></span>\n</$list>\n</div>\n\n</div>\n\n!! ✅ 待办 · 四象限\n\n<div class=\"tc-message-box\">在上方「快速记笔记」勾选「同时加入待办」即建任务(默认 Q2 重要·不紧急);也可以给任意笔记打上 <code>todo</code> 标签收集到下方。点任务左侧方框即完成(自动加 <code>done</code> 标签并从看板消失)。给任意笔记打上 <code>todo</code> 标签也会被收集到下方「未分类」,补填 <code>q</code> 字段即进入象限。</div>\n\n<div style=\"margin:6px 0; color:#555;\">📅 今日到期 <b>{{{[tag[todo]!tag[done]field:due<today>count[]]}}}</b> 件 · ⏰ 已逾期 <b>{{{[tag[todo]!tag[done]get[due]compare:date:lt<today>count[]]}}}</b> 件</div>\n\n<<quadrant-board>>\n\n<$list filter=\"[tag[todo]!tag[done]!has[q]count[]!match[0]]\">\n<div style=\"margin-top:10px; border:1px dashed rgba(128,128,128,0.35); border-radius:10px; padding:8px 12px;\">\n<div style=\"font-weight:700; margin-bottom:6px;\">📥 未分类待办 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]!has[q]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]!has[q]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n</div>\n</$list>\n</div>\n</$list>\n\n</$set>"},{"title":"所有标签","tags":["索引","TableOfContents"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n\\define tag-count() [all[tiddlers]!is[system]!tag[agent-written]tag<currentTiddler>count[]]\n\\define tag-list() [all[tiddlers]!is[system]!tag[agent-written]tags[]!prefix[$:/tags/]!match[索引]]\n\n\\define agent-notes-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]count[]]\n\\define agent-notes-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]count[]]\n\\define agent-tags-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]tags[]!prefix[$:/tags/]!match[索引]!match[agent-written]!match[human-edited]]\n\\define agent-tags-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]tags[]!prefix[$:/tags/]!match[索引]!match[agent-written]!match[human-edited]]\n\\define agent-count-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]tag<currentTiddler>count[]]\n\\define agent-count-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]tag<currentTiddler>count[]]\n\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"margin:6px 0; padding:4px 10px; border:1px solid rgba(128,128,128,0.3); border-radius:6px; font-size:0.9em;\">\n<$action-navigate $to=\"🏠 主页\"/>\n← 回主页\n</$button>\n\n!! 🏷 所有标签\n\n<div class=\"tc-message-box\">按笔记数量从多到少排序,仅统计人类笔记(Agent 撰写的笔记已排除,见下方「🤖 Agent 撰写的标签」)。点击标签,查看包含该标签的所有笔记。</div>\n\n<div style=\"margin-top:12px;\">\n<$list filter=\"[subfilter<tag-list>] +[!sortsub:number<tag-count>]\">\n<$set name=\"count\" value={{{ [subfilter<tag-count>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n</div>\n\n!! 🤖 Agent 撰写的标签\n\n<div class=\"tc-message-box\">以下标签来自带有 <code>agent-written</code> 标签(由 Agent 撰写)的笔记,与上方主列表分开统计。若某篇 Agent 笔记又被人类编辑过,请给它补打 <code>human-edited</code> 标签,即归入下方「Agent + 人工」档。</div>\n\n<div style=\"font-weight:700; margin:8px 0 4px;\">🦾 纯 Agent <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[subfilter<agent-notes-pure>]}}} 篇</span></div>\n<div style=\"margin-left:10px;\">\n<$list filter=\"[subfilter<agent-tags-pure>] +[!sortsub:number<agent-count-pure>]\">\n<$set name=\"count\" value={{{ [subfilter<agent-count-pure>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n<$list filter=\"[subfilter<agent-tags-pure>!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无纯 Agent 笔记)</div></$list>\n</div>\n\n<div style=\"font-weight:700; margin:10px 0 4px;\">🤝 Agent + 人工 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[subfilter<agent-notes-mixed>]}}} 篇</span></div>\n<div style=\"margin-left:10px;\">\n<$list filter=\"[subfilter<agent-tags-mixed>] +[!sortsub:number<agent-count-mixed>]\">\n<$set name=\"count\" value={{{ [subfilter<agent-count-mixed>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n<$list filter=\"[subfilter<agent-tags-mixed>!count[]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无「Agent + 人工」笔记)</div></$list>\n</div>\n"},{"title":"标签笔记","tags":["索引"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n<$set name=\"sel\" value={{{ [{$:/state/tag}] }}}>\n\n!! 标签:<<sel>>\n\n<div class=\"tc-message-box\">包含标签 <strong><<sel>></strong> 的所有笔记(自动收集,按最近修改排序)。</div>\n\n<ul>\n<$list filter=\"[all[tiddlers]!is[system]!has[draft.of]tag<sel>] +[!sort[modified]]\">\n<li><$link to=<<currentTiddler>>><$view field=\"title\"/></$link><span style=\"color:#aaa; font-size:0.85em;\"> · <$view field=\"modified\" format=\"relativedate\"/></span></li>\n</$list>\n</ul>\n\n</$set>\n"}]
29
-
30
- /**
31
- * Seed the home/index tiddlers exactly once per wiki (mirrors the doc-note
32
- * one-shot policy). Also writes $:/DefaultTiddlers → [[🏠 主页]] so the
33
- * new home opens by default. With `force` the tiddlers are overwritten with the
34
- * built-in content and the marker is (re)written — the settings page uses this
35
- * for "重新初始化". Returns whether anything was written this call. Never throws.
36
- */
37
- export async function seedHomeIndex(client: TiddlyWebClient, opts?: { force?: boolean }): Promise<boolean> {
38
- const force = opts?.force === true
39
- if (!force) {
40
- const marker = await client.get(HOME_INDEX_MARKER_TITLE).catch(() => undefined)
41
- if (marker !== undefined) return false
42
- }
43
- let wrote = false
44
- for (const item of HOME_INDEX_ITEMS) {
45
- const existing = await client.get(item.title).catch(() => undefined)
46
- if (force || existing === undefined) {
47
- await client.put({ title: item.title, text: item.text, type: item.type, tags: item.tags })
48
- wrote = true
49
- }
50
- }
51
- // Ensure the default home page is 🏠 主页. A fresh wiki's $:/DefaultTiddlers is
52
- // the core shadow "GettingStarted" (or absent), so a first seed writes it;
53
- // a user-customised DefaultTiddlers is left alone unless force.
54
- const dt = await client.get('$:/DefaultTiddlers').catch(() => undefined)
55
- const dtText = typeof dt?.text === 'string' ? dt.text.trim() : ''
56
- if (force || dt === undefined || dtText === 'GettingStarted' || dtText === '[[GettingStarted]]') {
57
- await client.put({ title: '$:/DefaultTiddlers', text: HOME_DEFAULT_TIDDLERS, type: 'text/vnd.tiddlywiki', tags: [] })
58
- wrote = true
59
- }
60
- await client
61
- .put({ title: HOME_INDEX_MARKER_TITLE, text: 'seeded-once', type: 'text/plain', tags: [] })
62
- .catch(() => undefined)
63
- return wrote
64
- }
65
-
66
- /**
67
- * Un-seed (反初始化): remove the home tiddlers and their marker, restoring the
68
- * wiki's default home only when it still points at the seeded 🏠 主页
69
- * (a user-customised $:/DefaultTiddlers is left alone). Deletion is idempotent —
70
- * a tiddler already gone is not listed. Never throws.
71
- */
72
- export async function unseedHomeIndex(client: TiddlyWebClient): Promise<{ removed: string[] }> {
73
- const removed: string[] = []
74
- for (const item of HOME_INDEX_ITEMS) {
75
- const t = await client.get(item.title).catch(() => undefined)
76
- if (t !== undefined) {
77
- await client.delete(item.title)
78
- removed.push(item.title)
79
- }
80
- }
81
- const marker = await client.get(HOME_INDEX_MARKER_TITLE).catch(() => undefined)
82
- if (marker !== undefined) {
83
- await client.delete(HOME_INDEX_MARKER_TITLE)
84
- removed.push(HOME_INDEX_MARKER_TITLE)
85
- }
86
- const dt = await client.get('$:/DefaultTiddlers').catch(() => undefined)
87
- if (dt !== undefined && typeof dt.text === 'string' && dt.text.trim() === "[[🏠 主页]]") {
88
- await client.put({ title: '$:/DefaultTiddlers', text: '[[GettingStarted]]', type: 'text/vnd.tiddlywiki', tags: [] })
89
- removed.push('$:/DefaultTiddlers')
90
- }
91
- return { removed }
92
- }
1
+ /**
2
+ * Generated from the wiki home tiddlers (do not hand-edit the constants).
3
+ * Source: 🏠 主页.tid, 所有标签.tid, 标签笔记.tid
4
+ *
5
+ * Sanitized with --strip-private: the seed home is the GENERIC home (without
6
+ * the wiki owner's personal 主题页 tabs / private entry buttons), plus the
7
+ *「📚 插件文档」tabs strip (tag dsh-docs) so seeded docs are one click away.
8
+ *
9
+ * The "首页" tiddlers that the plugin's system prompt promises (待办四象限 +
10
+ * 所有标签统计 + 标签笔记): seeded into fresh wikis by seedHomeIndex, so new
11
+ * users get the same home page instead of an empty wiki. 🏠 主页 is the
12
+ * default home (the seed also ensures $:/DefaultTiddlers → [[🏠 主页]]).
13
+ *
14
+ * @module dsh-tiddlywiki/host/seed-home
15
+ */
16
+ import type { TiddlyWebClient } from './tw-api.ts'
17
+
18
+ /** One-time marker: presence means "the home was offered once — hands off". */
19
+ export const HOME_INDEX_MARKER_TITLE = '$:/plugins/dsh-tiddlywiki/seed-home-index'
20
+
21
+ /** The $:/DefaultTiddlers body so 🏠 主页 opens by default in fresh wikis. */
22
+ export const HOME_DEFAULT_TIDDLERS = "[[🏠 主页]]"
23
+
24
+ export interface HomeIndexItem {
25
+ title: string
26
+ tags: string[]
27
+ type: string
28
+ text: string
29
+ }
30
+
31
+ /** The home tiddlers, exactly as seeded (user-owned afterwards). */
32
+ export const HOME_INDEX_ITEMS: HomeIndexItem[] = [{"title":"🏠 主页","tags":["索引","TableOfContents"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n\\define quadrant-board()\n<div style=\"display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:8px;\">\n<$droppable class=\"tc-quadrant tc-quadrant-q1\" effect=\"move\"\nstyle.border=\"1px solid rgba(128,128,128,0.22)\"\nstyle.border-radius=\"10px\"\nstyle.padding=\"8px 12px\"\nstyle.background=\"linear-gradient(135deg,#e74c3c1a,transparent)\"\nactions=\"\"\"<$action-setfield $tiddler=<<actionTiddler>> $field=\"q\" $value=\"q1\"/>\"\"\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🔴 重要 · 紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q1]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q1]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1; cursor:grab;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q1]count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</$droppable>\n<$droppable class=\"tc-quadrant tc-quadrant-q2\" effect=\"move\"\nstyle.border=\"1px solid rgba(128,128,128,0.22)\"\nstyle.border-radius=\"10px\"\nstyle.padding=\"8px 12px\"\nstyle.background=\"linear-gradient(135deg,#3498db1a,transparent)\"\nactions=\"\"\"<$action-setfield $tiddler=<<actionTiddler>> $field=\"q\" $value=\"q2\"/>\"\"\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🔵 重要 · 不紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q2]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q2]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1; cursor:grab;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q2]count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</$droppable>\n<$droppable class=\"tc-quadrant tc-quadrant-q3\" effect=\"move\"\nstyle.border=\"1px solid rgba(128,128,128,0.22)\"\nstyle.border-radius=\"10px\"\nstyle.padding=\"8px 12px\"\nstyle.background=\"linear-gradient(135deg,#f39c121a,transparent)\"\nactions=\"\"\"<$action-setfield $tiddler=<<actionTiddler>> $field=\"q\" $value=\"q3\"/>\"\"\">\n<div style=\"font-weight:700; margin-bottom:6px;\">🟠 紧急 · 不重要 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q3]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q3]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1; cursor:grab;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q3]count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</$droppable>\n<$droppable class=\"tc-quadrant tc-quadrant-q4\" effect=\"move\"\nstyle.border=\"1px solid rgba(128,128,128,0.22)\"\nstyle.border-radius=\"10px\"\nstyle.padding=\"8px 12px\"\nstyle.background=\"linear-gradient(135deg,#95a5a61a,transparent)\"\nactions=\"\"\"<$action-setfield $tiddler=<<actionTiddler>> $field=\"q\" $value=\"q4\"/>\"\"\">\n<div style=\"font-weight:700; margin-bottom:6px;\">⚪ 不重要 · 不紧急 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]field:q[q4]count[]]}}} 件</span></div>\n<$list filter=\"[tag[todo]!tag[done]field:q[q4]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1; cursor:grab;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n<$list filter=\"[<currentTiddler>get[due]!is[blank]]\"><span style=\"color:#888; font-size:0.8em;\"><$view field=\"due\" format=\"date\" template=\"MM-DD\"/></span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]field:q[q4]count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无)</div></$list>\n</$droppable>\n</div>\n\\end\n\n<$set name=\"today\" value=<<now \"YYYY0MM0DD\">>>\n\n!! 🏠 主页\n\n<div class=\"tc-message-box\">待办看板与知识库入口。</div>\n\n<div style=\"display:flex; gap:8px; flex-wrap:wrap; margin:8px 0;\">\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"padding:6px 16px; border:1px solid rgba(128,128,128,0.35); border-radius:8px; font-weight:600;\">\n<$action-navigate $to=\"所有标签\"/>\n🏷 所有标签\n</$button>\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"padding:6px 16px; border:1px solid rgba(128,128,128,0.35); border-radius:8px; font-weight:600;\">\n<$action-navigate $to=\"所有文章\"/>\n📚 所有文章\n</$button>\n</div>\n\n!! 📚 插件文档\n\n<div class=\"tc-message-box\">这里收纳插件初始化时 seed 进来的说明 / 教程 / 模板。给新文档打上 <code>dsh-docs</code> 标签即自动出现在本栏;不需要可自由删除(删除后不会自动恢复)。</div>\n\n<<tabs \"[tag[dsh-docs]!is[system]]\" \"dsh-tiddlywiki 插件说明\">>\n\n!! ✍️ 快速记笔记(完整编辑器)\n\n<div class=\"tc-message-box\">直接在首页写笔记:填标题、用工具栏写正文(支持 Markdown:**加粗**、*斜体*、# 标题、- 列表、> 引用 等)、加标签,点「💾 保存」即创建新笔记(默认 Markdown,标题留空用当前时间)。勾选「同时加入待办」并选象限,可一并进入下方四象限看板。</div>\n\n<div style=\"border:1px solid rgba(128,128,128,0.22); border-radius:10px; padding:10px 12px; margin:10px 0;\">\n\n<div style=\"display:flex; gap:6px; align-items:center; margin-bottom:6px;\">\n<$edit-text tiddler=\"$:/state/home-note/title\" tag=\"input\" placeholder=\"标题(留空用当前时间)\" style=\"flex:1; min-width:200px; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\"/>\n</div>\n\n<$edit-text tiddler=\"$:/state/home-note/text\" tag=\"textarea\" class=\"tc-edit-texteditor\" autoHeight=\"yes\" minHeight=\"150px\" placeholder=\"正文:支持 **加粗**、*斜体*、# 标题、- 列表、> 引用 等 Markdown 语法\" style=\"width:100%; box-sizing:border-box; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<$button class=\"tc-btn-invisible\" tooltip=\"加粗\" style=\"padding:2px 8px; font-weight:700;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"**\" suffix=\"**\" trimSelection=\"yes\"/>B</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"斜体\" style=\"padding:2px 8px; font-style:italic;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"*\" suffix=\"*\" trimSelection=\"yes\"/>I</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"删除线\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"~~\" suffix=\"~~\" trimSelection=\"yes\"/>S</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"标题\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"#\" count=\"1\"/>H</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"无序列表\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"-\" count=\"1\"/>•</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"有序列表\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\"1.\" count=\"1\"/>1.</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"引用\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"prefix-lines\" character=\">\" count=\"1\"/>❝</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"行内代码\" style=\"padding:2px 8px;\"><$action-sendmessage $message=\"tm-edit-text-operation\" $param=\"wrap-selection\" prefix=\"`\" suffix=\"`\" trimSelection=\"yes\"/>&lt;/&gt;</$button>\n</$edit-text>\n\n<div style=\"display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-top:6px;\">\n<$edit-text tiddler=\"$:/state/home-note/tags\" tag=\"input\" placeholder=\"标签(逗号分隔,可选)\" style=\"flex:1; min-width:160px; padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\"/>\n<$checkbox tiddler=\"$:/state/home-note/todo\" field=\"text\" checked=\"yes\" unchecked=\"no\"> 同时加入待办</$checkbox>\n<$select tiddler=\"$:/state/home-note/quadrant\" default=\"q2\" style=\"padding:6px 10px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<option value=\"q1\">Q1 重要·紧急</option>\n<option value=\"q2\">Q2 重要·不紧急</option>\n<option value=\"q3\">Q3 紧急·不重要</option>\n<option value=\"q4\">Q4 不重要·不紧急</option>\n</$select>\n</div>\n\n<div style=\"display:flex; gap:6px; align-items:center; margin-top:8px; flex-wrap:wrap;\">\n<$button class=\"tc-btn-invisible\" style=\"padding:6px 16px; border-radius:6px; border:1px solid rgba(128,128,128,0.35); font-weight:600; background:rgba(128,128,128,0.06);\">\n<$list filter=\"[{$:/state/home-note/title}!is[blank]] [{$:/state/home-note/text}!is[blank]]\">\n<$action-createtiddler\n$basetitle={{{ [{$:/state/home-note/title}!is[blank]then{$:/state/home-note/title}] ~[<now \"YYYY-MM-DD-HHmm\">] }}}\ntext={{{ [{$:/state/home-note/text}] }}}\ntags={{{ [{$:/state/home-note/tags}split[,]split[,]trim[]] [{$:/state/home-note/todo}match[yes]then[todo]] +[join[ ]] }}}\nq={{{ [{$:/state/home-note/todo}match[yes]then{$:/state/home-note/quadrant}!is[blank]] ~[{$:/state/home-note/todo}match[yes]then[q2]] }}}\ntype=\"text/markdown\"\n$savetitle=\"$:/state/home-note/last-created\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/title\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/text\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/tags\" text=\"\"/>\n</$list>\n💾 保存\n</$button>\n<$button class=\"tc-btn-invisible\" tooltip=\"清空草稿\" style=\"padding:6px 12px; border-radius:6px; border:1px solid rgba(128,128,128,0.3);\">\n<$action-setfield $tiddler=\"$:/state/home-note/title\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/text\" text=\"\"/>\n<$action-setfield $tiddler=\"$:/state/home-note/tags\" text=\"\"/>\n🗑 清空\n</$button>\n<$list filter=\"[{$:/state/home-note/last-created}!is[blank]]\">\n<span style=\"color:#2e7d32; font-size:0.9em;\">✅ 已保存:<$link to={{{ [{$:/state/home-note/last-created}] }}}>{{{$:/state/home-note/last-created}}}</$link></span>\n</$list>\n</div>\n\n</div>\n\n!! ✅ 待办 · 四象限\n\n<div class=\"tc-message-box\">在上方「快速记笔记」勾选「同时加入待办」即建任务(默认 Q2 重要·不紧急);也可以给任意笔记打上 <code>todo</code> 标签收集到下方。点任务左侧方框即完成(自动加 <code>done</code> 标签并从看板消失)。下方「未分类待办」可直接拖动到上方任一象限,拖入即自动写入 <code>q</code> 字段完成分类(象限之间也可互相拖动调整);把象限中的待办拖回「未分类」可取消分类。</div>\n\n<div style=\"margin:6px 0; color:#555;\">📅 今日到期 <b>{{{[tag[todo]!tag[done]field:due<today>count[]]}}}</b> 件 · ⏰ 已逾期 <b>{{{[tag[todo]!tag[done]get[due]compare:date:lt<today>count[]]}}}</b> 件</div>\n\n<<quadrant-board>>\n\n<div style=\"margin-top:10px; border:1px dashed rgba(128,128,128,0.35); border-radius:10px; padding:8px 12px;\">\n<div style=\"font-weight:700; margin-bottom:6px;\">📥 未分类待办 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[tag[todo]!tag[done]!has[q]count[]]}}} 件</span> <span style=\"color:#aaa; font-weight:400; font-size:0.78em;\">· 拖到上方象限自动分类</span></div>\n<$droppable class=\"tc-todo-inbox\" effect=\"move\" actions=\"\"\"<$action-deletefield $tiddler=<<actionTiddler>> $field=\"q\"/>\"\"\">\n<$list filter=\"[tag[todo]!tag[done]!has[q]sort[modified]]\">\n<div style=\"display:flex; gap:6px; align-items:baseline; padding:3px 0; border-bottom:1px dashed rgba(128,128,128,0.15);\">\n<$checkbox tiddler=<<currentTiddler>> tag=\"done\"/>\n<$link to=<<currentTiddler>> style=\"flex:1; cursor:grab;\"><$view field=\"title\"/></$link>\n<$list filter=\"[<currentTiddler>get[due]compare:date:lt<today>]\"><span style=\"color:#c0392b; font-size:0.78em;\">逾期</span></$list>\n</div>\n</$list>\n<$list filter=\"[tag[todo]!tag[done]!has[q]count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无 · 把象限中的待办拖回这里可取消分类)</div></$list>\n</$droppable>\n</div>\n\n</$set>\n"},{"title":"所有标签","tags":["索引","TableOfContents"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n\\define tag-count() [all[tiddlers]!is[system]!tag[agent-written]tag<currentTiddler>count[]]\n\\define tag-list() [all[tiddlers]!is[system]!tag[agent-written]tags[]!prefix[$:/tags/]!match[索引]]\n\n\\define agent-notes-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]count[]]\n\\define agent-notes-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]count[]]\n\\define agent-tags-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]tags[]!prefix[$:/tags/]!match[索引]!match[agent-written]!match[human-edited]]\n\\define agent-tags-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]tags[]!prefix[$:/tags/]!match[索引]!match[agent-written]!match[human-edited]]\n\\define agent-count-pure() [all[tiddlers]!is[system]tag[agent-written]!tag[human-edited]tag<currentTiddler>count[]]\n\\define agent-count-mixed() [all[tiddlers]!is[system]tag[agent-written]tag[human-edited]tag<currentTiddler>count[]]\n\n<$button class=\"tc-btn-invisible tc-tiddlylink\" style=\"margin:6px 0; padding:4px 10px; border:1px solid rgba(128,128,128,0.3); border-radius:6px; font-size:0.9em;\">\n<$action-navigate $to=\"🏠 主页\"/>\n← 回主页\n</$button>\n\n!! 🏷 所有标签\n\n<div class=\"tc-message-box\">按笔记数量从多到少排序,仅统计人类笔记(Agent 撰写的笔记已排除,见下方「🤖 Agent 撰写的标签」)。点击标签,查看包含该标签的所有笔记。</div>\n\n<div style=\"margin-top:12px;\">\n<$list filter=\"[subfilter<tag-list>] +[!sortsub:number<tag-count>]\">\n<$set name=\"count\" value={{{ [subfilter<tag-count>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n</div>\n\n!! 🤖 Agent 撰写的标签\n\n<div class=\"tc-message-box\">以下标签来自带有 <code>agent-written</code> 标签(由 Agent 撰写)的笔记,与上方主列表分开统计。若某篇 Agent 笔记又被人类编辑过,请给它补打 <code>human-edited</code> 标签,即归入下方「Agent + 人工」档。</div>\n\n<div style=\"font-weight:700; margin:8px 0 4px;\">🦾 纯 Agent <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[subfilter<agent-notes-pure>]}}} 篇</span></div>\n<div style=\"margin-left:10px;\">\n<$list filter=\"[subfilter<agent-tags-pure>] +[!sortsub:number<agent-count-pure>]\">\n<$set name=\"count\" value={{{ [subfilter<agent-count-pure>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n<$list filter=\"[subfilter<agent-tags-pure>count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无纯 Agent 笔记)</div></$list>\n</div>\n\n<div style=\"font-weight:700; margin:10px 0 4px;\">🤝 Agent + 人工 <span style=\"color:#888; font-weight:400; font-size:0.82em;\">{{{[subfilter<agent-notes-mixed>]}}} 篇</span></div>\n<div style=\"margin-left:10px;\">\n<$list filter=\"[subfilter<agent-tags-mixed>] +[!sortsub:number<agent-count-mixed>]\">\n<$set name=\"count\" value={{{ [subfilter<agent-count-mixed>] }}}>\n<div style=\"padding:7px 2px; border-bottom:1px solid rgba(128,128,128,0.15);\">\n<$button set=\"$:/state/tag\" setTo=<<currentTiddler>> class=\"tc-btn-invisible tc-tiddlylink\" style=\"width:100%; text-align:left;\">\n<$action-navigate $to=\"标签笔记\"/>\n<span style=\"font-weight:600; font-size:1.05em;\"><<currentTiddler>></span>\n<span style=\"color:#888; font-size:0.85em; margin-left:8px;\"><<count>> 篇</span>\n</$button>\n</div>\n</$set>\n</$list>\n<$list filter=\"[subfilter<agent-tags-mixed>count[]match[0]]\"><div style=\"color:#aaa; font-size:0.85em;\">(暂无「Agent + 人工」笔记)</div></$list>\n</div>\n"},{"title":"标签笔记","tags":["索引"],"type":"text/vnd.tiddlywiki","text":"\\whitespace trim\n\n<$set name=\"sel\" value={{{ [{$:/state/tag}] }}}>\n\n!! 标签:<<sel>>\n\n<div class=\"tc-message-box\">包含标签 <strong><<sel>></strong> 的所有笔记(自动收集,按最近修改排序)。</div>\n\n<ul>\n<$list filter=\"[all[tiddlers]!is[system]!has[draft.of]tag<sel>] +[!sort[modified]]\">\n<li><$link to=<<currentTiddler>>><$view field=\"title\"/></$link><span style=\"color:#aaa; font-size:0.85em;\"> · <$view field=\"modified\" format=\"relativedate\"/></span></li>\n</$list>\n</ul>\n\n</$set>\n"}]
33
+
34
+ /**
35
+ * Seed the home/index tiddlers exactly once per wiki (mirrors the doc-note
36
+ * one-shot policy). Also writes $:/DefaultTiddlers → [[🏠 主页]] so the
37
+ * new home opens by default. With `force` the tiddlers are overwritten with the
38
+ * built-in content and the marker is (re)written — the settings page uses this
39
+ * for "重新初始化". Returns whether anything was written this call. Never throws.
40
+ */
41
+ export async function seedHomeIndex(client: TiddlyWebClient, opts?: { force?: boolean }): Promise<boolean> {
42
+ const force = opts?.force === true
43
+ if (!force) {
44
+ const marker = await client.get(HOME_INDEX_MARKER_TITLE).catch(() => undefined)
45
+ if (marker !== undefined) return false
46
+ }
47
+ let wrote = false
48
+ for (const item of HOME_INDEX_ITEMS) {
49
+ const existing = await client.get(item.title).catch(() => undefined)
50
+ if (force || existing === undefined) {
51
+ await client.put({ title: item.title, text: item.text, type: item.type, tags: item.tags })
52
+ wrote = true
53
+ }
54
+ }
55
+ // Ensure the default home page is 🏠 主页. A fresh wiki's $:/DefaultTiddlers is
56
+ // the core shadow "GettingStarted" (or absent), so a first seed writes it;
57
+ // a user-customised DefaultTiddlers is left alone unless force.
58
+ const dt = await client.get('$:/DefaultTiddlers').catch(() => undefined)
59
+ const dtText = typeof dt?.text === 'string' ? dt.text.trim() : ''
60
+ if (force || dt === undefined || dtText === 'GettingStarted' || dtText === '[[GettingStarted]]') {
61
+ await client.put({ title: '$:/DefaultTiddlers', text: HOME_DEFAULT_TIDDLERS, type: 'text/vnd.tiddlywiki', tags: [] })
62
+ wrote = true
63
+ }
64
+ await client
65
+ .put({ title: HOME_INDEX_MARKER_TITLE, text: 'seeded-once', type: 'text/plain', tags: [] })
66
+ .catch(() => undefined)
67
+ return wrote
68
+ }
69
+
70
+ /**
71
+ * Un-seed (反初始化): remove the home tiddlers and their marker, restoring the
72
+ * wiki's default home only when it still points at the seeded 🏠 主页
73
+ * (a user-customised $:/DefaultTiddlers is left alone). Deletion is idempotent —
74
+ * a tiddler already gone is not listed. Never throws.
75
+ */
76
+ export async function unseedHomeIndex(client: TiddlyWebClient): Promise<{ removed: string[] }> {
77
+ const removed: string[] = []
78
+ for (const item of HOME_INDEX_ITEMS) {
79
+ const t = await client.get(item.title).catch(() => undefined)
80
+ if (t !== undefined) {
81
+ await client.delete(item.title)
82
+ removed.push(item.title)
83
+ }
84
+ }
85
+ const marker = await client.get(HOME_INDEX_MARKER_TITLE).catch(() => undefined)
86
+ if (marker !== undefined) {
87
+ await client.delete(HOME_INDEX_MARKER_TITLE)
88
+ removed.push(HOME_INDEX_MARKER_TITLE)
89
+ }
90
+ const dt = await client.get('$:/DefaultTiddlers').catch(() => undefined)
91
+ if (dt !== undefined && typeof dt.text === 'string' && dt.text.trim() === "[[🏠 主页]]") {
92
+ await client.put({ title: '$:/DefaultTiddlers', text: '[[GettingStarted]]', type: 'text/vnd.tiddlywiki', tags: [] })
93
+ removed.push('$:/DefaultTiddlers')
94
+ }
95
+ return { removed }
96
+ }
@@ -18,6 +18,12 @@ export const DOC_NOTE_TITLE = 'dsh-tiddlywiki 插件说明'
18
18
  /** Tag that makes the note easy to find via `tiddlywiki_search tag=docs`. */
19
19
  export const DOC_NOTE_TAG = 'docs'
20
20
 
21
+ /**
22
+ * Shared tag that collects every plugin-seeded doc into the seeded home's
23
+ *「📚 插件文档」tabs strip (see seed-starter-docs.ts DSH_DOCS_TAG).
24
+ */
25
+ export const DOC_NOTE_DSH_DOCS_TAG = 'dsh-docs'
26
+
21
27
  /** One-time marker: its presence means "the note was offered once — hands off". */
22
28
  export const SEED_MARKER_TITLE = '$:/plugins/dsh-tiddlywiki/seed-doc-note'
23
29
 
@@ -50,6 +56,7 @@ export const DOC_NOTE_TEXT = `! dsh-tiddlywiki 插件说明
50
56
  !! 说明
51
57
 
52
58
  * 本笔记由插件在**首次启动**时自动写入(一次性:只写一次)。删除后重启 dsh web **不会自动恢复**——它从此归你所有。
59
+ * 本笔记带 \`dsh-docs\` 标签,会出现在首页「📚 插件文档」栏(与「示例与文档」seed 的教程/模板一起),不需要可自由删除。
53
60
  * 更多细节见插件仓库 README。`
54
61
 
55
62
  /**
@@ -74,7 +81,7 @@ export async function seedDocNote(client: TiddlyWebClient, opts?: { force?: bool
74
81
  title: DOC_NOTE_TITLE,
75
82
  text: DOC_NOTE_TEXT,
76
83
  type: 'text/vnd.tiddlywiki',
77
- tags: [DOC_NOTE_TAG],
84
+ tags: [DOC_NOTE_TAG, DOC_NOTE_DSH_DOCS_TAG],
78
85
  })
79
86
  wrote = true
80
87
  }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * The "示例与文档" starter seed (v0.16.22): the generic docs / templates /
3
+ * example pages that give a fresh wiki a working "文档中心" out of the box —
4
+ * 主题汇总页·模板 (blank template) + 教程:按主题/标签做汇总页 (how-to) + three
5
+ * runnable 主题页 examples (日志 / 决策记录 / 排障).
6
+ *
7
+ * Sanitized: every tiddler carries NO personal data — the tutorial's
8
+ * 配套产物清单 points only at the tiddlers this seed actually provides, and
9
+ * the example pages auto-collect by tag (text verbatim from the author's wiki,
10
+ * they were already generic). Every item gets the shared `dsh-docs` tag so the
11
+ * seeded home's「📚 插件文档」tabs strip collects them automatically.
12
+ *
13
+ * Tier: STARTER — seeded automatically on first install (safe-skip: any
14
+ * same-named tiddler already present is never overwritten) and removable via
15
+ *「反初始化」from the settings page (ONE-SHOT marker-gated, like doc-note).
16
+ *
17
+ * @module dsh-tiddlywiki/host/seed-starter-docs
18
+ */
19
+ import type { TiddlyWebClient } from './tw-api.ts'
20
+
21
+ /** One-time marker: presence means "the docs were offered once — hands off". */
22
+ export const STARTER_DOCS_MARKER_TITLE = '$:/plugins/dsh-tiddlywiki/seed-starter-docs'
23
+
24
+ /** Shared tag that collects every plugin-seeded doc into the home docs tab. */
25
+ export const DSH_DOCS_TAG = 'dsh-docs'
26
+
27
+ export interface StarterDocItem {
28
+ title: string
29
+ tags: string[]
30
+ type: string
31
+ text: string
32
+ }
33
+
34
+ /** The docs, exactly as seeded (user-owned afterwards, freely deletable). */
35
+ export const STARTER_DOCS_ITEMS: StarterDocItem[] = [
36
+ {
37
+ title: '主题汇总页·模板',
38
+ tags: ['索引', 'dsh-docs'],
39
+ type: 'text/vnd.tiddlywiki',
40
+ text: `\\whitespace trim
41
+
42
+ !! 📌 主题汇总页
43
+
44
+ <div style="color:#888; font-size:0.85em; border:1px dashed rgba(128,128,128,0.35); border-radius:8px; padding:6px 10px; margin-bottom:8px;">【模板】复制本页 → 改名(如「XX主题汇总」)→ 把下面两处 <code>主题A</code> 替换成你的标签名 → 保存。给笔记打上该标签即自动收录,本页无需维护。</div>
45
+
46
+ <div class="tc-message-box">自动收集带 <code>主题A</code> 标签的笔记,按最近修改排序,共 <strong>{{{[tag[主题A]!is[system]!has[draft.of]count[]]}}}</strong> 篇。</div>
47
+
48
+ <<list-links "[tag[主题A]!is[system]!has[draft.of]] +[!sort[modified]]">>
49
+
50
+ ---
51
+
52
+ ### 可选:自定义样式的 <$list> 版(想更花哨时用它替换上面的 list-links)
53
+
54
+ <ul>
55
+ <$list filter="[tag[主题A]!is[system]!has[draft.of]] +[!sort[modified]]">
56
+ <li><$link to=<<currentTiddler>>><$view field="title"/></$link><span style="color:#aaa; font-size:0.85em;"> · <$view field="modified" format="relativedate"/></span></li>
57
+ </$list>
58
+ </ul>
59
+
60
+ ### 可选:把本页收进「一页多主题」tabs
61
+
62
+ 给本页打上 <code>主题页</code> 标签、并加一个 <code>caption</code> 字段(按钮文字),然后在总览页写:<code>&lt;&lt;tabs "[tag[主题页]!is[system]]"&gt;&gt;</code>。详见 [[教程:按主题/标签做汇总页]]。
63
+ `,
64
+ },
65
+ {
66
+ title: '教程:按主题/标签做汇总页',
67
+ tags: ['教程', 'dsh-docs'],
68
+ type: 'text/markdown',
69
+ text: `# 教程:按主题/标签做汇总页
70
+
71
+ > 适用:本 wiki 的 TiddlyWiki 5.3.x 内核。⚠️ 网上大量教程是 5.1/5.2 时代写的,其中 \`<<tabs "筛选器" "标签">>\` 和 \`<<count "筛选器">>\` 两种写法在本版本已**改版/移除**,照抄会报错,注意甄别。
72
+
73
+ ## 核心思路(一句话)
74
+
75
+ 「汇总页」不是 TW 的特殊功能,而是:**一个普通笔记 + 正文里一段筛选器(filter)**。渲染时 TW 实时从整个 wiki 挑出符合条件的笔记列出来。**新笔记只要打上对应标签,汇总页自动出现,零维护**——不用像手工目录那样每次手动更新。
76
+
77
+ ## 方法一:零代码,直接用内置标签页
78
+
79
+ - 打开任意笔记,点正文底部的**标签链接**;
80
+ - 或侧边栏「标签」(标签云)里点某个标签。
81
+ - TW 会自动生成该标签的页面,列出所有带此标签的笔记。
82
+ - 优点:一行代码都不用写;缺点:不能加说明文字、不能自定义排序/样式,也做不了「多主题合一」。
83
+
84
+ ## 方法二:一页一主题(最常用)
85
+
86
+ 新建一个笔记(wikitext),正文写:
87
+
88
+ \`\`\`wikitext
89
+ !! 📔 日志主题汇总
90
+ <div class="tc-message-box">自动收集带 <code>日志</code> 标签的笔记,共 <strong>{{{[tag[日志]!is[system]!has[draft.of]count[]]}}}</strong> 篇,按最近修改排序。</div>
91
+
92
+ <<list-links "[tag[日志]!is[system]!has[draft.of]] +[!sort[modified]]">>
93
+ \`\`\`
94
+
95
+ 各片段含义:
96
+
97
+ - \`[tag[日志]]\`:挑出所有带「日志」标签的笔记;
98
+ - \`!is[system]\`:排除 \`$:/\` 系统页;
99
+ - \`!has[draft.of]\`:排除未保存的草稿副本;
100
+ - \`+[!sort[modified]]\`:按修改时间**倒序**(\`sort[modified]\` 为正序);
101
+ - \`{{{[...count[]]}}}\`:筛选器计数(旧版 \`<<count>>\` 宏已移除,这是 5.3 新写法)。
102
+
103
+ 想自定义每行样式(带相对时间、复选框等),用你更熟悉的 \`<$list>\` 写法:
104
+
105
+ \`\`\`wikitext
106
+ <ul>
107
+ <$list filter="[tag[日志]!is[system]!has[draft.of]] +[!sort[modified]]">
108
+ <li><$link to=<<currentTiddler>>><$view field="title"/></$link><span style="color:#aaa; font-size:0.85em;"> · <$view field="modified" format="relativedate"/></span></li>
109
+ </$list>
110
+ </ul>
111
+ \`\`\`
112
+
113
+ ## 方法三:一页多主题(Dashboard,5.3 新版 tabs)
114
+
115
+ 5.3 的 \`tabs\` 宏签名:\`<<tabs "选中标签页的筛选器" "默认选中项">>\`。思路分两步:
116
+
117
+ 1. **每个主题各建一个汇总页**(就是方法二那种),全部打上同一个标签(本插件 seed 的示例用 \`主题页\`);要自定义按钮文字,就给该页加一个 \`caption\` 字段(如 \`📔 日志\`)。
118
+ 2. **建一个总览页**,正文只写一行:
119
+
120
+ \`\`\`wikitext
121
+ <<tabs "[tag[主题页]!is[system]]" "主题页·日志">>
122
+ \`\`\`
123
+
124
+ 效果:页面上方一排按钮,点哪个就内嵌显示哪个主题的汇总。第二个参数是默认展开的页(可省略,省略则初始不展开)。
125
+
126
+ > 老教程的 \`<<tabs "筛选器A" "标签A" "筛选器B" "标签B">>\` 在 5.3 已失效,别用。
127
+
128
+ 本插件已 seed 了可直接运行的示例:[主题页·日志]、[主题页·决策记录]、[主题页·排障](都带 \`主题页\` 标签),复制改造即可。
129
+
130
+ ## 筛选器速查表(背熟这几行就够用)
131
+
132
+ | 想要 | 写法 |
133
+ | --- | --- |
134
+ | 某标签下的笔记 | \`[tag[主题]]\` |
135
+ | 排除系统页 / 草稿 | \`[tag[主题]!is[system]!has[draft.of]]\` |
136
+ | 修改时间倒序 / 正序 | \`+[!sort[modified]]\` / \`+[sort[modified]]\` |
137
+ | 按标题排序 | \`+[sort[title]]\` |
138
+ | 交集(同时有两个标签) | \`[tag[A]+tag[B]]\` |
139
+ | 并集(有任一标签) | \`[tag[A]] [tag[B]]\` |
140
+ | 差集(有 A 无 B) | \`[tag[A]-tag[B]]\` |
141
+ | 排除某标签 | \`-[tag[排除项]]\` |
142
+ | 限定时间段 | \`[tag[主题]modified[2026-09]]\` |
143
+ | 计数 | \`{{{[tag[主题]!is[system]count[]]}}}\`(或 \`<$count filter="[tag[主题]]"/>\`) |
144
+ | 整个 wiki 的非系统非草稿 | \`all[tiddlers]!is[system]!has[draft.of]\` |
145
+
146
+ ## 进阶玩法
147
+
148
+ 1. **按字段筛选**:\`[tag[todo]get[due]compare:date:lt<today>]\` 可列出「到期日早于今天」的笔记(主页的逾期看板就是这么写的)。
149
+ 2. **树状目录**:\`<<toc tag:"主题">>\` 显示层级目录,适合一个主题下还有子主题的情况。
150
+ 3. **模板复用**:复制 [主题汇总页·模板] 改标题和标签即可,不用每次重写。
151
+ 4. **打开直达**:把 \`$:/DefaultTiddlers\` 改成 \`[[主题页·日志]]\`,启动即打开汇总页(当前默认是 [🏠 主页])。
152
+ 5. **导航收录**:给汇总页打 \`索引\` 标签,它就会从「全部笔记 / 所有文章」里消失、只作为导航页存在;再在 [🏠 主页] 的按钮区加一个入口按钮即可。
153
+ 6. **标签整理**:控制台 → 工具 → 标签管理器,可重命名/合并标签,改名后所有笔记自动跟随,汇总页筛选器无需改动(筛选器按标签名匹配,自动跟随改名)。
154
+
155
+ ## 配套产物清单(插件 seed 提供了什么)
156
+
157
+ - [主题页·日志]、[主题页·决策记录]、[主题页·排障] —— 单主题汇总页实例(各自可独立打开,也可作为「一页多主题」tabs 的标签页)
158
+ - [主题汇总页·模板] —— 空白模板,复制即用
159
+ - 本教程 —— 就是这一页
160
+
161
+ 以上都来自「示例与文档」seed(tag \`dsh-docs\`),不需要可自由删除,删除后不会自动恢复。
162
+ `,
163
+ },
164
+ {
165
+ title: '主题页·日志',
166
+ tags: ['主题页', '索引', 'dsh-docs'],
167
+ type: 'text/vnd.tiddlywiki',
168
+ text: `\\whitespace trim
169
+
170
+ !! 📔 日志主题汇总
171
+
172
+ <div class="tc-message-box">自动收集带 <code>日志</code> 标签的笔记,按最近修改排序,共 <strong>{{{[tag[日志]!is[system]!has[draft.of]count[]]}}}</strong> 篇。给笔记打上「日志」标签即自动收录,本页无需维护(做法见 [[教程:按主题/标签做汇总页]])。</div>
173
+
174
+ <<list-links "[tag[日志]!is[system]!has[draft.of]] +[!sort[modified]]">>
175
+ `,
176
+ },
177
+ {
178
+ title: '主题页·决策记录',
179
+ tags: ['主题页', '索引', 'dsh-docs'],
180
+ type: 'text/vnd.tiddlywiki',
181
+ text: `\\whitespace trim
182
+
183
+ !! 📌 决策记录主题汇总
184
+
185
+ <div class="tc-message-box">自动收集带 <code>决策记录</code> 标签的笔记,按最近修改排序,共 <strong>{{{[tag[决策记录]!is[system]!has[draft.of]count[]]}}}</strong> 篇。给笔记打上「决策记录」标签即自动收录,本页无需维护(做法见 [[教程:按主题/标签做汇总页]])。</div>
186
+
187
+ <<list-links "[tag[决策记录]!is[system]!has[draft.of]] +[!sort[modified]]">>
188
+ `,
189
+ },
190
+ {
191
+ title: '主题页·排障',
192
+ tags: ['主题页', '索引', 'dsh-docs'],
193
+ type: 'text/vnd.tiddlywiki',
194
+ text: `\\whitespace trim
195
+
196
+ !! 🔧 排障主题汇总
197
+
198
+ <div class="tc-message-box">自动收集带 <code>troubleshooting</code> 标签的笔记,按最近修改排序,共 <strong>{{{[tag[troubleshooting]!is[system]!has[draft.of]count[]]}}}</strong> 篇。给笔记打上「troubleshooting」标签即自动收录,本页无需维护(做法见 [[教程:按主题/标签做汇总页]])。</div>
199
+
200
+ <<list-links "[tag[troubleshooting]!is[system]!has[draft.of]] +[!sort[modified]]">>
201
+ `,
202
+ },
203
+ ]
204
+
205
+ /**
206
+ * Seed the starter docs once per wiki (safe-skip: same-named tiddlers already
207
+ * present are NEVER overwritten — user data stays user data). Marker-gated
208
+ * ONE-SHOT; with `opts.force` the tiddlers are (re)written and the marker
209
+ * (re)recorded — the settings page uses this for "重新初始化".
210
+ * Returns whether anything was written this call. Never throws.
211
+ */
212
+ export async function seedStarterDocs(client: TiddlyWebClient, opts?: { force?: boolean }): Promise<boolean> {
213
+ const force = opts?.force === true
214
+ if (!force) {
215
+ const marker = await client.get(STARTER_DOCS_MARKER_TITLE).catch(() => undefined)
216
+ if (marker !== undefined) return false
217
+ }
218
+ let wrote = false
219
+ for (const item of STARTER_DOCS_ITEMS) {
220
+ const existing = await client.get(item.title).catch(() => undefined)
221
+ if (force || existing === undefined) {
222
+ await client.put({ title: item.title, text: item.text, type: item.type, tags: item.tags })
223
+ wrote = true
224
+ }
225
+ }
226
+ await client
227
+ .put({ title: STARTER_DOCS_MARKER_TITLE, text: 'seeded-once', type: 'text/plain', tags: [] })
228
+ .catch(() => undefined)
229
+ return wrote
230
+ }
231
+
232
+ /**
233
+ * Un-seed (反初始化): remove the starter docs and their marker. Deletion is
234
+ * idempotent — a tiddler already gone is not listed. Never throws.
235
+ */
236
+ export async function unseedStarterDocs(client: TiddlyWebClient): Promise<{ removed: string[] }> {
237
+ const removed: string[] = []
238
+ for (const item of STARTER_DOCS_ITEMS) {
239
+ const t = await client.get(item.title).catch(() => undefined)
240
+ if (t !== undefined) {
241
+ await client.delete(item.title)
242
+ removed.push(item.title)
243
+ }
244
+ }
245
+ const marker = await client.get(STARTER_DOCS_MARKER_TITLE).catch(() => undefined)
246
+ if (marker !== undefined) {
247
+ await client.delete(STARTER_DOCS_MARKER_TITLE)
248
+ removed.push(STARTER_DOCS_MARKER_TITLE)
249
+ }
250
+ return { removed }
251
+ }