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.
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Generated from the wiki's custom stylesheet tiddlers (do not hand-edit the
3
+ * constants). Source: 编辑器美化 CSS.css, 标题与按钮区分开.css, 侧边栏窄屏自动隐藏.css, 批注弹窗样式.css, menubar 顶栏加高样式.css
4
+ *
5
+ * The「自定义样式」optional seed: the generic UI stylesheets the wiki owner
6
+ * curated (编辑器美化 / 标题与按钮区分开 / 侧边栏窄屏自动隐藏 / 批注弹窗 /
7
+ * menubar 顶栏加高). Only the functional tag $:/tags/Stylesheet is kept —
8
+ * wiki-local tags (自定义 / agent-written …) are NOT seeded, and none of the
9
+ * sheets carry personal data. Seeded ONE-SHOT (marker-gated, never overwrites
10
+ * user edits) + force 重新初始化 + remove 反初始化, like the other optional seeds.
11
+ *
12
+ * @module dsh-tiddlywiki/host/seed-ui-styles
13
+ */
14
+ import type { TiddlyWebClient } from './tw-api.ts'
15
+
16
+ /** One-time marker: presence means "the styles were offered once — hands off". */
17
+ export const UI_STYLES_MARKER_TITLE = '$:/plugins/dsh-tiddlywiki/seed-ui-styles'
18
+
19
+ export interface UiStyleItem {
20
+ title: string
21
+ tags: string[]
22
+ type: string
23
+ text: string
24
+ }
25
+
26
+ /** The stylesheets, exactly as seeded (user-owned afterwards). */
27
+ export const UI_STYLE_ITEMS: UiStyleItem[] = [{"title":"编辑器美化 CSS","tags":["$:/tags/Stylesheet"],"type":"text/css","text":"/* ===== 编辑器美化(TiddlyWiki 5.4 + CodeMirror)===== */\n\n/* 字体 / 字号 / 行高 */\n.tc-editor .CodeMirror {\n font-family: \"Fira Code VF\", Consolas, \"Courier New\", monospace;\n font-size: 14px;\n line-height: 1.7;\n}\n\n/* 编辑区内边距(呼吸感) */\n.tc-editor .CodeMirror-lines {\n padding: 12px 14px;\n}\n\n/* 光标颜色 */\n.tc-editor .CodeMirror-cursor {\n border-left: 2px solid #2e80ff !important;\n}\n\n/* 当前行高亮 */\n.tc-editor .CodeMirror-activeline-background {\n background: rgba(46, 128, 255, 0.08);\n}\n\n/* 行号 */\n.tc-editor .CodeMirror-linenumber {\n color: #9aa0a6;\n padding-right: 10px;\n}\n\n/* 选区配色 */\n.tc-editor .CodeMirror ::selection {\n background: rgba(46, 128, 255, 0.22);\n}\n\n/* 工具栏按钮:圆角 + 间距 */\n.tc-editor-toolbar button {\n border-radius: 6px;\n margin: 0 2px 2px 0;\n}\n\n/* 编辑页标题输入框:vanilla 默认 2.35em 过大,缩小字号与内边距 */\n.tc-tiddler-frame input.tc-edit-texteditor.tc-titlebar,\n.tc-tiddler-frame .tc-titlebar.tc-edit-texteditor {\n font-size: 1.2em !important;\n line-height: 1.35em !important;\n padding: 4px 8px !important;\n}\n\n/* 查看模式标题:vanilla 默认 2.35em 过大,调小一些 */\n.tc-tiddler-frame .tc-tiddler-title .tc-titlebar,\n.tc-tiddler-frame .tc-tiddler-title h2.tc-title {\n font-size: 1.3em !important;\n line-height: 1.1em !important;\n}\n\n/* 侧边栏站点标题(sidebar 顶部的 wiki 站名):vanilla 默认 2.35em 过大,调小 */\n.tc-sidebar .tc-site-title {\n font-size: 1.5em !important;\n line-height: 1.3em !important;\n}\n"},{"title":"标题与按钮区分开","tags":["$:/tags/Stylesheet"],"type":"text/css","text":".tc-titlebar h2 {\n\tdisplay: table-header-group;\n\tword-wrap:break-word;\n\tword-break:break-all;\n}\n"},{"title":"侧边栏窄屏自动隐藏.css","tags":["$:/tags/Stylesheet"],"type":"text/css","text":"/* ===== 侧边栏窄屏自动隐藏 =====\n 视口(TW 面板/iframe 宽度)< 960px 时自动完全隐藏右侧 TiddlyWiki 侧边栏,\n 正文占满整行;窗口变宽 >= 960px 后自动恢复。\n 断点 959px 对齐主题默认 sidebarbreakpoint=960px(vanilla/snowwhite/starlight)。\n 想改断点:改下面媒体查询里的数值即可。\n 想恢复默认:删除本 tiddler。 */\n\n@media (max-width: 959px) {\n\n\t/* 侧边栏整栏隐藏(含站点标题、各 sidebar 板块) */\n\t.tc-sidebar-scrollable {\n\t\tdisplay: none !important;\n\t}\n\n\t/* 右上角「显示/隐藏侧边栏」chevron 按钮一并隐藏:\n\t 窄屏下侧边栏已被 CSS 隐藏,此时按钮点击只会改 $:/state/sidebar 状态、\n\t 界面却看不到变化,反而误导,故隐藏 */\n\t.tc-hide-sidebar-btn,\n\t.tc-show-sidebar-btn {\n\t\tdisplay: none !important;\n\t}\n\n}\n"},{"title":"批注弹窗样式","tags":["$:/tags/Stylesheet"],"type":"text/css","text":"/* 批注功能弹窗美化(dsh-ann-*) */\n.dsh-ann-popup {\n\tborder-radius: 12px;\n\tpadding: 14px 16px;\n\tmax-width: 520px;\n\twidth: max-content;\n\tmin-width: 300px;\n\tbox-shadow: 0 10px 30px rgba(0,0,0,.22);\n\tborder: 1px solid rgba(127,127,127,.25);\n}\n.dsh-ann-popup .dsh-ann-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 10px;\n\tfont-weight: 700;\n\tfont-size: 1.02em;\n\tmargin-bottom: 8px;\n}\n.dsh-ann-icon-btn {\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tfont-size: 1em;\n\tline-height: 1;\n\tpadding: 2px 8px;\n\tborder-radius: 6px;\n\topacity: .55;\n}\n.dsh-ann-icon-btn:hover { opacity: 1; background: rgba(127,127,127,.15); }\n.dsh-ann-sub { font-size: .88em; margin: 4px 0; }\n.dsh-ann-quote {\n\tbackground: rgba(127,127,127,.14);\n\tpadding: 2px 8px;\n\tborder-radius: 6px;\n\tfont-style: italic;\n}\n.dsh-ann-chip {\n\tdisplay: inline-block;\n\twidth: 12px;\n\theight: 12px;\n\tborder-radius: 50%;\n\tmargin: 0 4px 0 8px;\n\tborder: 1px solid rgba(0,0,0,.18);\n\tvertical-align: -1px;\n}\n.dsh-ann-label { font-size: .9em; margin: 10px 0 4px; }\n.dsh-ann-input {\n\twidth: 100%;\n\tborder-radius: 8px;\n\tborder: 1px solid rgba(127,127,127,.35);\n\tpadding: 6px 9px;\n\tfont-size: .95em;\n\tresize: vertical;\n}\n.dsh-ann-input:focus {\n\toutline: none;\n\tborder-color: #4a90d9;\n\tbox-shadow: 0 0 0 2px rgba(74,144,217,.22);\n}\n.dsh-ann-actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-top: 12px;\n}\n.dsh-ann-btn {\n\tdisplay: inline-block;\n\tborder-radius: 8px;\n\tpadding: 5px 14px;\n\tcursor: pointer;\n\tborder: 1px solid rgba(127,127,127,.35);\n\tbackground: rgba(127,127,127,.08);\n\tfont-size: .9em;\n\ttext-decoration: none !important;\n}\n.dsh-ann-btn:hover { background: rgba(127,127,127,.18); }\n.dsh-ann-btn-primary {\n\tbackground: #4a90d9;\n\tborder-color: #4a90d9;\n\tcolor: #fff !important;\n}\n.dsh-ann-btn-primary:hover { background: #3a80c9; }\n.dsh-ann-colors {\n\tdisplay: flex;\n\tgap: 10px;\n\tmargin: 10px 0 12px;\n}\n.dsh-ann-swatch {\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tborder: 2px solid rgba(0,0,0,.14);\n\tcursor: pointer;\n\tpadding: 0;\n\ttransition: transform .12s ease, box-shadow .12s ease;\n}\n.dsh-ann-swatch:hover {\n\ttransform: scale(1.18);\n\tbox-shadow: 0 2px 8px rgba(0,0,0,.28);\n}\n.dsh-ann-sel { font-size: .88em; margin-top: 4px; }\n"},{"title":"menubar 顶栏加高样式","tags":["$:/tags/Stylesheet"],"type":"text/css","text":"/* ==== menubar 顶栏加高 ====\n 默认顶栏约 28px(菜单项 padding 0.5em + line-height 1)。\n 想调高度:改 min-height 数值即可(如 40 / 48 / 56px)。\n 想恢复默认:删除本 tiddler。\n flex 布局让菜单项在加高的栏内垂直居中;窄屏汉堡展开时保持纵向堆叠。 */\n\nnav.tc-menubar ul.tc-menubar-list {\n\tdisplay: flex;\n\talign-items: center;\n\tbox-sizing: border-box;\n\tmin-height: 44px;\n}\n\nnav.tc-menubar .tc-menubar-narrow ul.tc-menubar-list {\n\tflex-direction: column;\n\talign-items: stretch;\n}\n"}]
28
+
29
+ /**
30
+ * Seed the custom stylesheet tiddlers once per wiki (mirrors the one-shot
31
+ * policy). With opts.force the tiddlers are overwritten with the built-in
32
+ * content and the marker (re)written — the settings page uses this for
33
+ * "重新初始化". Returns whether anything was written this call. Never throws.
34
+ */
35
+ export async function seedUiStyles(client: TiddlyWebClient, opts?: { force?: boolean }): Promise<boolean> {
36
+ const force = opts?.force === true
37
+ if (!force) {
38
+ const marker = await client.get(UI_STYLES_MARKER_TITLE).catch(() => undefined)
39
+ if (marker !== undefined) return false
40
+ }
41
+ let wrote = false
42
+ for (const item of UI_STYLE_ITEMS) {
43
+ const existing = await client.get(item.title).catch(() => undefined)
44
+ if (force || existing === undefined) {
45
+ await client.put({ title: item.title, text: item.text, type: item.type, tags: item.tags })
46
+ wrote = true
47
+ }
48
+ }
49
+ await client
50
+ .put({ title: UI_STYLES_MARKER_TITLE, text: 'seeded-once', type: 'text/plain', tags: [] })
51
+ .catch(() => undefined)
52
+ return wrote
53
+ }
54
+
55
+ /**
56
+ * Un-seed (反初始化): remove the stylesheet tiddlers and their marker.
57
+ * Deletion is idempotent — a tiddler already gone is not listed. Never throws.
58
+ */
59
+ export async function unseedUiStyles(client: TiddlyWebClient): Promise<{ removed: string[] }> {
60
+ const removed: string[] = []
61
+ for (const item of UI_STYLE_ITEMS) {
62
+ const t = await client.get(item.title).catch(() => undefined)
63
+ if (t !== undefined) {
64
+ await client.delete(item.title)
65
+ removed.push(item.title)
66
+ }
67
+ }
68
+ const marker = await client.get(UI_STYLES_MARKER_TITLE).catch(() => undefined)
69
+ if (marker !== undefined) {
70
+ await client.delete(UI_STYLES_MARKER_TITLE)
71
+ removed.push(UI_STYLES_MARKER_TITLE)
72
+ }
73
+ return { removed }
74
+ }
package/src/host/seeds.ts CHANGED
@@ -2,32 +2,39 @@
2
2
  * Unified seed registry (design: every one-time "与 dsh 联动需要 wiki 预置"
3
3
  * item is a SeedDef here).
4
4
  *
5
- * Two tiers (v0.15.0):
5
+ * Three tiers (v0.16.22):
6
6
  * - CORE seeds (`core: true`) are functionally required by the plugin's
7
- * own features — the startup path seeds exactly these (non-force).
8
- * - OPTIONAL seeds (`core: false`) are nice-to-have content (说明笔记 /
9
- * 首页 / 所有文章 / menubar 顶栏主题自适应) — they are NEVER auto-seeded;
10
- * the user opts in from the settings page「初始化」section (重新初始化)
11
- * and can opt out again with 反初始化 (remove).
7
+ * own features — the startup path seeds exactly these (non-force) and
8
+ * they can never be 反初始化'd.
9
+ * - STARTER seeds (`startup: true`, removable) are docs / examples that
10
+ * give a fresh wiki a working「文档中心」out of the box — the startup path
11
+ * ALSO seeds them on first install (safe-skip: same-named tiddlers are
12
+ * never overwritten), and the user can 反初始化 them anytime.
13
+ * - OPTIONAL seeds (`core: false`, `startup: false`) are nice-to-have
14
+ * content (首页 / 所有文章 / 自定义样式 / menubar 顶栏主题自适应) — they are
15
+ * NEVER auto-seeded; the user opts in from the settings page「初始化」section
16
+ * (重新初始化) and can opt out again with 反初始化 (remove).
12
17
  *
13
18
  * Each seed owns:
14
19
  * - `check` — current state (present / missing / needs-update) for the UI;
15
20
  * - `run(force)` — non-force keeps the ONE-SHOT / user-owned semantics
16
21
  * (write only when missing, never overwrite), force (re)writes the
17
22
  * built-in content and (re)records the marker;
18
- * - `remove` — optional seeds only: delete the seeded tiddlers + markers,
19
- * returning the wiki to the "never seeded" state.
23
+ * - `remove` — optional + starter seeds only: delete the seeded tiddlers +
24
+ * markers, returning the wiki to the "never seeded" state.
20
25
  *
21
- * Registry: doc-note / send-to-agent / render-route / home-index /
22
- * all-articles / menubar-theme / tw-web-host.
26
+ * Registry: doc-note / starter-docs / send-to-agent / render-route /
27
+ * home-index / all-articles / ui-styles / menubar-theme / tw-web-host.
23
28
  *
24
29
  * @module dsh-tiddlywiki/host/seeds
25
30
  */
26
31
  import type { TiddlyWebClient } from './tw-api.ts'
27
32
  import { seedDocNote, unseedDocNote, DOC_NOTE_TITLE } from './seed-notes.ts'
33
+ import { seedStarterDocs, unseedStarterDocs, STARTER_DOCS_ITEMS, STARTER_DOCS_MARKER_TITLE } from './seed-starter-docs.ts'
28
34
  import { seedSendToAgent, SEND_TO_AGENT_PLUGIN_TITLE } from './seed-send-to-agent.ts'
29
35
  import { seedHomeIndex, unseedHomeIndex, HOME_INDEX_ITEMS } from './seed-home.ts'
30
36
  import { seedAllArticles, unseedAllArticles, ALL_ARTICLES_TITLE } from './seed-all-articles.ts'
37
+ import { seedUiStyles, unseedUiStyles, UI_STYLE_ITEMS } from './seed-ui-styles.ts'
31
38
  import { seedMenubarTheme, unseedMenubarTheme, MENUBAR_THEME_TIDDLER } from './seed-menubar-theme.ts'
32
39
  import { seedRenderRoute, RENDER_PLUGIN_TITLE } from './seed-render.ts'
33
40
  import { TW_WEB_HOST_TIDDLER, TW_WEB_HOST_DEFAULT } from './config.ts'
@@ -70,13 +77,19 @@ export interface SeedDef {
70
77
  title: string
71
78
  description: string
72
79
  /**
73
- * Core seeds are seeded automatically on startup (功能必需). Optional
74
- * seeds are manual-only from the settings page — never forced on users.
80
+ * Core seeds are seeded automatically on startup (功能必需) and can never
81
+ * be 反初始化'd — removing them would break a plugin feature.
75
82
  */
76
83
  core: boolean
84
+ /**
85
+ * STARTER tier (v0.16.22): docs / examples that the startup path ALSO seeds
86
+ * on first install (safe-skip: same-named tiddlers never overwritten), but
87
+ * which stay removable via「反初始化」. Meaningful only when `core` is false.
88
+ */
89
+ startup?: boolean
77
90
  check(ctx: SeedContext): Promise<SeedStatus>
78
91
  run(ctx: SeedContext, force: boolean): Promise<SeedRunResult>
79
- /** Optional seeds only: delete the seeded tiddlers + markers (反初始化). */
92
+ /** Non-core seeds only: delete the seeded tiddlers + markers (反初始化). */
80
93
  remove?(ctx: SeedContext): Promise<SeedRunResult>
81
94
  }
82
95
 
@@ -99,6 +112,8 @@ interface SeedMeta {
99
112
  title: string
100
113
  description: string
101
114
  core: boolean
115
+ /** STARTER tier: also auto-seeded on first install (removable). */
116
+ startup?: boolean
102
117
  }
103
118
 
104
119
  type SeedWriter = (client: TiddlyWebClient, opts?: { force?: boolean }) => Promise<boolean>
@@ -122,7 +137,7 @@ function defineSeed(meta: SeedMeta, impl: {
122
137
  run?: (ctx: SeedContext, force: boolean) => Promise<SeedRunResult>
123
138
  unseed?: SeedUnseeder
124
139
  }): SeedDef {
125
- const { id, title, description, core } = meta
140
+ const { id, title, description, core, startup } = meta
126
141
  const removable = !core
127
142
  const check: SeedDef['check'] = impl.check ?? (async (ctx) => {
128
143
  const present = await presentOf(ctx, impl.presentTitle ?? '')
@@ -143,15 +158,29 @@ function defineSeed(meta: SeedMeta, impl: {
143
158
  return { id, ok: false, wrote: false, error: err instanceof Error ? err.message : String(err) }
144
159
  }
145
160
  }
146
- return { id, title, description, core, check, run, ...(remove === undefined ? {} : { remove }) }
161
+ return { id, title, description, core, ...(startup === undefined ? {} : { startup }), check, run, ...(remove === undefined ? {} : { remove }) }
147
162
  }
148
163
 
149
164
  /** The full registry, in display order. */
150
165
  export const SEED_DEFS: SeedDef[] = [
151
166
  defineSeed(
152
- { id: 'doc-note', title: '插件说明笔记', description: '「dsh-tiddlywiki 插件说明」——入门说明笔记(可选,设置页「初始化」手动写入;ONE-SHOT,用户可改可删)。', core: false },
167
+ { id: 'doc-note', title: '插件说明笔记', description: '「dsh-tiddlywiki 插件说明」——入门说明笔记(首次安装默认写入;ONE-SHOT,用户可改可删,标记 dsh-docs 自动进首页「📚 插件文档」栏)。', core: false, startup: true },
153
168
  { presentTitle: DOC_NOTE_TITLE, write: seedDocNote, unseed: unseedDocNote },
154
169
  ),
170
+ defineSeed(
171
+ { id: 'starter-docs', title: '示例与文档(汇总模板 / 教程 / 主题页示例)', description: '新手文档中心起步包:主题汇总页·模板、教程(按主题/标签做汇总页)、三个可直接运行的示例主题页(日志 / 决策记录 / 排障)。全部打 dsh-docs 标签,自动出现在首页「📚 插件文档」栏;纯示例无个人数据,同名 tiddler 已存在则安全跳过,不会覆盖。首次安装默认写入,可反初始化。', core: false, startup: true },
172
+ {
173
+ check: async (ctx) => {
174
+ const missing: string[] = []
175
+ for (const item of STARTER_DOCS_ITEMS) {
176
+ if (!(await presentOf(ctx, item.title))) missing.push(item.title)
177
+ }
178
+ return { id: 'starter-docs', title: '示例与文档(汇总模板 / 教程 / 主题页示例)', description: '新手文档中心起步包:主题汇总页·模板、教程(按主题/标签做汇总页)、三个可直接运行的示例主题页(日志 / 决策记录 / 排障)。全部打 dsh-docs 标签,自动出现在首页「📚 插件文档」栏;纯示例无个人数据,同名 tiddler 已存在则安全跳过,不会覆盖。首次安装默认写入,可反初始化。', present: missing.length === 0, removable: true, detail: missing.length === 0 ? '已存在' : `缺失:${missing.join('、')}` }
179
+ },
180
+ write: seedStarterDocs,
181
+ unseed: unseedStarterDocs,
182
+ },
183
+ ),
155
184
  defineSeed(
156
185
  { id: 'send-to-agent', title: '「发送给 Agent」按钮', description: 'TW 笔记工具栏「发送给 Agent」按钮插件($:/plugins/dsh/send-to-agent)——把笔记一键注入 DSH 会话。', core: true },
157
186
  { presentTitle: SEND_TO_AGENT_PLUGIN_TITLE, write: seedSendToAgent },
@@ -178,6 +207,20 @@ export const SEED_DEFS: SeedDef[] = [
178
207
  { id: 'all-articles', title: '所有文章(两列分页总览)', description: '「所有文章」——全部条目分两列(🤖 Agent 撰写 / 👤 人工·人类)各自分页展示。每页条数取插件设置 ui.allArticles.pageSize(默认 10)。', core: false },
179
208
  { presentTitle: ALL_ARTICLES_TITLE, write: seedAllArticles, unseed: unseedAllArticles },
180
209
  ),
210
+ defineSeed(
211
+ { id: 'ui-styles', title: '自定义样式(编辑器美化 / 窄屏侧栏 / menubar 加高 / 批注弹窗)', description: '5 张通用样式表(tag $:/tags/Stylesheet):编辑器美化(CodeMirror 字体/光标/行号)、标题与按钮区分开、侧边栏窄屏自动隐藏(<960px)、menubar 顶栏加高、批注弹窗美化。纯样式无个人数据。', core: false },
212
+ {
213
+ check: async (ctx) => {
214
+ const missing: string[] = []
215
+ for (const item of UI_STYLE_ITEMS) {
216
+ if (!(await presentOf(ctx, item.title))) missing.push(item.title)
217
+ }
218
+ return { id: 'ui-styles', title: '自定义样式(编辑器美化 / 窄屏侧栏 / menubar 加高 / 批注弹窗)', description: '5 张通用样式表(tag $:/tags/Stylesheet):编辑器美化(CodeMirror 字体/光标/行号)、标题与按钮区分开、侧边栏窄屏自动隐藏(<960px)、menubar 顶栏加高、批注弹窗美化。纯样式无个人数据。', present: missing.length === 0, removable: true, detail: missing.length === 0 ? '已存在' : `缺失:${missing.join('、')}` }
219
+ },
220
+ write: seedUiStyles,
221
+ unseed: unseedUiStyles,
222
+ },
223
+ ),
181
224
  defineSeed(
182
225
  { id: 'menubar-theme', title: 'menubar 顶栏主题自适应', description: '样式表覆盖($:/plugins/dsh-tiddlywiki/menubar-theme,tag $:/tags/Stylesheet)——把 tiddlywiki/menubar 顶栏从「默认色映射的蓝色」改为跟随当前 palette 的 background/foreground,随 DSH 主题切换($:/palette 翻转)自动换色。', core: false },
183
226
  { presentTitle: MENUBAR_THEME_TIDDLER, write: seedMenubarTheme, unseed: unseedMenubarTheme },
@@ -256,25 +299,28 @@ export async function runSeedById(ctx: SeedContext, id: string | undefined, forc
256
299
  }
257
300
 
258
301
  /**
259
- * Startup path: seed ONLY the core items (功能必需:发送给 Agent 按钮 +
260
- * TW 前端 API 基址), non-force (write only what is missing). Optional seeds
261
- * (说明笔记 / 首页 / 所有文章 / menubar 顶栏主题自适应) are never forced on
262
- * users — they opt in from the settings page「初始化」section.
302
+ * Startup path: seed the CORE items (功能必需:发送给 Agent 按钮 + 原生渲染
303
+ * 路由 + TW 前端 API 基址) AND the STARTER items (首次安装默认:插件说明 +
304
+ * 示例与文档), all non-force (write only what is missing — a same-named
305
+ * tiddler already present is NEVER overwritten, so user data stays user data).
306
+ * Remaining optional seeds (首页 / 所有文章 / 自定义样式 / menubar 顶栏主题自
307
+ * 适应) are never forced on users — they opt in from the settings page
308
+ * 「初始化」section.
263
309
  */
264
310
  export async function runAllSeeds(ctx: SeedContext): Promise<SeedRunResult[]> {
265
311
  const out: SeedRunResult[] = []
266
312
  for (const def of SEED_DEFS) {
267
- if (!def.core) continue
313
+ if (!def.core && def.startup !== true) continue
268
314
  out.push(await def.run(ctx, false))
269
315
  }
270
316
  return out
271
317
  }
272
318
 
273
319
  /**
274
- * 反初始化 (remove): delete one optional seed's seeded tiddlers + markers, or
275
- * all optional seeds when `id` is undefined. Core seeds are functionally
276
- * required and cannot be removed — a direct request for one returns an error
277
- * result (and is skipped when removing all).
320
+ * 反初始化 (remove): delete one non-core seed's (starter 或 optional) seeded
321
+ * tiddlers + markers, or all non-core seeds when `id` is undefined. Core
322
+ * seeds are functionally required and cannot be removed — a direct request
323
+ * for one returns an error result (and is skipped when removing all).
278
324
  */
279
325
  export async function removeSeedById(ctx: SeedContext, id: string | undefined): Promise<SeedRunResult[]> {
280
326
  if (id === undefined) {
package/src/index.ts CHANGED
@@ -45,10 +45,12 @@ export { writeSessionSummary, SESSION_SUMMARY_PREFIX } from './host/routes.ts'
45
45
  export type { SessionQueryFace, SessionSummaryResult } from './host/routes.ts'
46
46
  export { registerAdminRoutes, resolveTwRoot, readWikiInfo, writeWikiInfo, bundledCatalog, ensureLanguage, normalizeThemes } from './host/admin.ts'
47
47
  export { seedDocNote, DOC_NOTE_TITLE, DOC_NOTE_TAG, DOC_NOTE_TEXT } from './host/seed-notes.ts'
48
+ export { seedStarterDocs, STARTER_DOCS_ITEMS, STARTER_DOCS_MARKER_TITLE, DSH_DOCS_TAG } from './host/seed-starter-docs.ts'
48
49
  export { seedSendToAgent, SEND_TO_AGENT_PLUGIN_TITLE, SEND_TO_AGENT_MARKER_TITLE, SEND_TO_AGENT_BUNDLE_TEXT } from './host/seed-send-to-agent.ts'
49
50
  export { seedRenderRoute, RENDER_PLUGIN_TITLE, RENDER_MARKER_TITLE, RENDER_BUNDLE_TEXT } from './host/seed-render.ts'
50
51
  export { seedHomeIndex, HOME_INDEX_ITEMS, HOME_INDEX_MARKER_TITLE, HOME_DEFAULT_TIDDLERS } from './host/seed-home.ts'
51
52
  export { seedAllArticles, ALL_ARTICLES_TITLE, ALL_ARTICLES_MARKER_TITLE, ALL_ARTICLES_TEXT } from './host/seed-all-articles.ts'
53
+ export { seedUiStyles, UI_STYLE_ITEMS, UI_STYLES_MARKER_TITLE } from './host/seed-ui-styles.ts'
52
54
  export { seedMenubarTheme, MENUBAR_THEME_TIDDLER, MENUBAR_THEME_MARKER_TITLE, MENUBAR_THEME_TEXT } from './host/seed-menubar-theme.ts'
53
55
  export { runAllSeeds, checkAllSeeds, runSeedById, removeSeedById, SEED_DEFS, type SeedStatus, type SeedRunResult } from './host/seeds.ts'
54
56
  export { registerTiddlywikiTools } from './host/tools.ts'
@@ -66,7 +68,7 @@ export interface TiddlywikiConfig {
66
68
  port?: number
67
69
  git?: { autoCommit?: boolean; debounceMs?: number; remote?: string; branch?: string }
68
70
  note?: { tag?: string }
69
- ui?: { showQuickNote?: boolean; showQuickNoteDock?: boolean; quickNoteMode?: 'native' | 'card'; sidebarLabel?: string; showPanelStatus?: boolean; showSyncButton?: boolean; followDshTheme?: boolean; darkPalette?: string; tabLabel?: string; showSessionTab?: boolean; showRightbarTab?: boolean; sendToAgent?: { enabled?: boolean; endpoint?: string; token?: string }; allArticles?: { pageSize?: number } }
71
+ ui?: { showQuickNote?: boolean; showQuickNoteDock?: boolean; quickNoteMode?: 'native' | 'card'; sidebarLabel?: string; showPanelStatus?: boolean; showSyncButton?: boolean; followDshTheme?: boolean; darkPalette?: string; tabLabel?: string; showSessionTab?: boolean; showRightbarTab?: boolean; showBetterSidebarTab?: boolean; sendToAgent?: { enabled?: boolean; endpoint?: string; token?: string }; allArticles?: { pageSize?: number } }
70
72
  /** 启动时自动启用的 TW 语言代码(如 "zh-Hans"),也受配置 tiddler 覆盖。 */
71
73
  uiLanguage?: string
72
74
  auth?: { username?: string; password?: string }
@@ -89,7 +91,7 @@ interface ResolvedConfig {
89
91
  port: number
90
92
  git: { autoCommit: boolean; debounceMs: number; remote: string; branch: string }
91
93
  note: { tag: string }
92
- ui: { showQuickNote: boolean; showQuickNoteDock: boolean; quickNoteMode: 'native' | 'card'; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; showRightbarTab: boolean; sendToAgent: { enabled: boolean; endpoint?: string; token?: string }; allArticles: { pageSize: number } }
94
+ ui: { showQuickNote: boolean; showQuickNoteDock: boolean; quickNoteMode: 'native' | 'card'; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; showRightbarTab: boolean; showBetterSidebarTab: boolean; sendToAgent: { enabled: boolean; endpoint?: string; token?: string }; allArticles: { pageSize: number } }
93
95
  uiLanguage: string
94
96
  auth: { username?: string; password?: string }
95
97
  }
@@ -100,7 +102,7 @@ const DEFAULTS: ResolvedConfig = {
100
102
  port: 0,
101
103
  git: { autoCommit: true, debounceMs: 60_000, remote: '', branch: 'main' },
102
104
  note: { tag: 'inbox' },
103
- ui: { showQuickNote: true, showQuickNoteDock: true, quickNoteMode: 'native', sidebarLabel: 'TiddlyWiki', showPanelStatus: true, showSyncButton: true, followDshTheme: true, darkPalette: DARK_PALETTE_DEFAULT, tabLabel: '知识库', showSessionTab: true, showRightbarTab: true, sendToAgent: { enabled: true }, allArticles: { pageSize: 10 } },
105
+ ui: { showQuickNote: true, showQuickNoteDock: true, quickNoteMode: 'native', sidebarLabel: 'TiddlyWiki', showPanelStatus: true, showSyncButton: true, followDshTheme: true, darkPalette: DARK_PALETTE_DEFAULT, tabLabel: '知识库', showSessionTab: true, showRightbarTab: true, showBetterSidebarTab: true, sendToAgent: { enabled: true }, allArticles: { pageSize: 10 } },
104
106
  uiLanguage: '',
105
107
  auth: { username: '', password: '' },
106
108
  }
@@ -259,7 +261,7 @@ export function apply(ctx: HostCtx, rawConfig: TiddlywikiConfig = {}): void {
259
261
  const tag = eff().note?.tag
260
262
  return typeof tag === 'string' && tag.trim().length > 0 ? tag : config.note.tag
261
263
  }
262
- const effectiveUi = (): { showQuickNote: boolean; showQuickNoteDock: boolean; quickNoteMode: 'native' | 'card'; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; showRightbarTab: boolean } => {
264
+ const effectiveUi = (): { showQuickNote: boolean; showQuickNoteDock: boolean; quickNoteMode: 'native' | 'card'; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; showRightbarTab: boolean; showBetterSidebarTab: boolean } => {
263
265
  const ui = eff().ui ?? {}
264
266
  const palette = typeof ui.darkPalette === 'string' && ui.darkPalette.trim().length > 0 ? ui.darkPalette.trim() : DARK_PALETTE_DEFAULT
265
267
  const label = typeof ui.sidebarLabel === 'string' && ui.sidebarLabel.trim().length > 0 ? ui.sidebarLabel.trim() : config.ui.sidebarLabel
@@ -277,6 +279,7 @@ export function apply(ctx: HostCtx, rawConfig: TiddlywikiConfig = {}): void {
277
279
  tabLabel,
278
280
  showSessionTab: ui.showSessionTab !== false,
279
281
  showRightbarTab: ui.showRightbarTab !== false,
282
+ showBetterSidebarTab: ui.showBetterSidebarTab !== false,
280
283
  }
281
284
  }
282
285