dsh-tiddlywiki 0.16.11 → 0.16.13
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/README.md +2 -0
- package/lib/client.bundle.js +26 -84
- package/lib/client.js +26 -84
- package/lib/index.js +300 -477
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/editor-popup.ts +21 -12
- package/src/client/endpoints.ts +10 -0
- package/src/client/index.ts +0 -4
- package/src/client/knowledge-fab.ts +14 -8
- package/src/client/note-widget.ts +28 -9
- package/src/client/panel.ts +11 -6
- package/src/client/quick-note-dock.ts +1 -4
- package/src/client/session-summary.ts +29 -1
- package/src/client/settings-page.ts +7 -2
- package/src/client/sidebar-entry.ts +2 -1
- package/src/client/styles.ts +0 -58
- package/src/client/sync-button.ts +5 -3
- package/src/client/ui-config.ts +1 -1
- package/src/host/admin.ts +2 -24
- package/src/host/http.ts +57 -0
- package/src/host/routes.ts +25 -92
- package/src/host/seeds.ts +114 -167
- package/src/host/session-summary.ts +35 -15
- package/src/host/tools.ts +41 -33
- package/src/index.ts +20 -6
package/src/host/tools.ts
CHANGED
|
@@ -115,6 +115,14 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
115
115
|
const disposers: Array<() => void> = []
|
|
116
116
|
const register = (tool: unknown): void => { disposers.push(ctx.tools.register(tool)) }
|
|
117
117
|
|
|
118
|
+
/** Every read/write tool needs a live TW client — shared guard for the 8
|
|
119
|
+
* wiki-facing tools (git tools operate on the repo path instead). */
|
|
120
|
+
const requireWiki = (): TiddlyWebClient => {
|
|
121
|
+
const wiki = deps.wiki()
|
|
122
|
+
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
123
|
+
return wiki
|
|
124
|
+
}
|
|
125
|
+
|
|
118
126
|
// ── tiddlywiki_search ────────────────────────────────────────────────────
|
|
119
127
|
register(defineTool({
|
|
120
128
|
name: 'tiddlywiki_search',
|
|
@@ -148,8 +156,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
148
156
|
},
|
|
149
157
|
},
|
|
150
158
|
execute: async (args: { query: string; tags?: string[]; tag?: string; since?: string; type?: string; limit?: number }): Promise<SearchResult> => {
|
|
151
|
-
const wiki =
|
|
152
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
159
|
+
const wiki = requireWiki()
|
|
153
160
|
const { items, total } = await wiki.search(args.query, {
|
|
154
161
|
tags: args.tags,
|
|
155
162
|
tag: args.tag,
|
|
@@ -190,8 +197,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
190
197
|
},
|
|
191
198
|
},
|
|
192
199
|
execute: async (args: { limit?: number; since?: string }): Promise<RecentResult> => {
|
|
193
|
-
const wiki =
|
|
194
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
200
|
+
const wiki = requireWiki()
|
|
195
201
|
const items = await wiki.recent(args.limit ?? 15, args.since)
|
|
196
202
|
return {
|
|
197
203
|
since: args.since ?? null,
|
|
@@ -215,8 +221,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
215
221
|
},
|
|
216
222
|
},
|
|
217
223
|
execute: async (): Promise<TagListResult> => {
|
|
218
|
-
const wiki =
|
|
219
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
224
|
+
const wiki = requireWiki()
|
|
220
225
|
const tags = await wiki.listTags()
|
|
221
226
|
return { count: tags.length, tags }
|
|
222
227
|
},
|
|
@@ -244,8 +249,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
244
249
|
},
|
|
245
250
|
},
|
|
246
251
|
execute: async (args: { title: string }): Promise<GetResult> => {
|
|
247
|
-
const wiki =
|
|
248
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
252
|
+
const wiki = requireWiki()
|
|
249
253
|
const t = await wiki.get(args.title)
|
|
250
254
|
if (t === undefined) return { notFound: true, title: args.title, text: '', tags: [], fields: {}, modified: null }
|
|
251
255
|
return { notFound: false, title: t.title, text: t.text ?? '', tags: t.tags ?? [], fields: pickFields(t), modified: typeof t.modified === 'string' ? t.modified : null }
|
|
@@ -275,8 +279,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
275
279
|
},
|
|
276
280
|
},
|
|
277
281
|
execute: async (args: { title: string; text: string; tags?: string[]; fields?: Record<string, unknown> }): Promise<PutResult> => {
|
|
278
|
-
const wiki =
|
|
279
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
282
|
+
const wiki = requireWiki()
|
|
280
283
|
const existing = await wiki.get(args.title).catch(() => undefined)
|
|
281
284
|
const tags = finalTagsForWrite(args.title, existing, Array.isArray(args.tags) ? args.tags.filter((t) => typeof t === 'string' && t.trim().length > 0) : [])
|
|
282
285
|
const tiddler: Tiddler = { title: args.title, text: args.text }
|
|
@@ -320,8 +323,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
320
323
|
},
|
|
321
324
|
},
|
|
322
325
|
execute: async (args: { items: Array<{ title: string; text: string; tags?: string[]; fields?: Record<string, unknown> }>; overwrite?: boolean }): Promise<BatchResult> => {
|
|
323
|
-
const wiki =
|
|
324
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
326
|
+
const wiki = requireWiki()
|
|
325
327
|
const list = Array.isArray(args.items) ? args.items : []
|
|
326
328
|
if (list.length === 0) return { ok: true, written: 0, skipped: 0, items: [] }
|
|
327
329
|
const overwrite = args.overwrite !== false
|
|
@@ -369,8 +371,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
369
371
|
},
|
|
370
372
|
},
|
|
371
373
|
execute: async (args: { oldTitle: string; newTitle: string; updateRefs?: boolean }): Promise<RenameResult> => {
|
|
372
|
-
const wiki =
|
|
373
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
374
|
+
const wiki = requireWiki()
|
|
374
375
|
const { oldTitle, newTitle } = args
|
|
375
376
|
if (oldTitle === newTitle) return { ok: true, from: oldTitle, to: newTitle, refsUpdated: 0, refsTiddlers: 0 }
|
|
376
377
|
const existing = await wiki.get(oldTitle)
|
|
@@ -417,8 +418,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
417
418
|
render: (_args, value: DeleteResult) => [{ type: 'text', text: `已删除 tiddler「${value.title}」。` }],
|
|
418
419
|
},
|
|
419
420
|
execute: async (args: { title: string }): Promise<DeleteResult> => {
|
|
420
|
-
const wiki =
|
|
421
|
-
if (wiki === undefined) throw new Error('TiddlyWiki 服务未运行(tiddlywiki_status 可查)')
|
|
421
|
+
const wiki = requireWiki()
|
|
422
422
|
await wiki.delete(args.title)
|
|
423
423
|
deps.autoCommit()
|
|
424
424
|
return { ok: true, title: args.title }
|
|
@@ -497,15 +497,7 @@ export function registerTiddlywikiTools(ctx: ToolsCtx, deps: ToolsDeps): Array<(
|
|
|
497
497
|
lines.push(` ${value.message}`)
|
|
498
498
|
if (value.files !== undefined && value.files.length > 0) lines.push(`涉及文件: ${value.files.join(', ')}`)
|
|
499
499
|
if (value.commit !== undefined) lines.push(`本地 commit: ${value.commit}`)
|
|
500
|
-
if (value.status !== undefined) {
|
|
501
|
-
const s = value.status
|
|
502
|
-
const bits = [`分支 ${s.branch}`]
|
|
503
|
-
if (s.ahead !== undefined) bits.push(`领先 ${s.ahead}`)
|
|
504
|
-
if (s.behind !== undefined) bits.push(`落后 ${s.behind}`)
|
|
505
|
-
if (s.dirty) bits.push(`工作区有 ${s.dirtyFiles.length} 个未提交改动`)
|
|
506
|
-
if (s.lastCommit !== undefined) bits.push(`最近提交 ${s.lastCommit}`)
|
|
507
|
-
lines.push(`状态: ${bits.join(' · ')}`)
|
|
508
|
-
}
|
|
500
|
+
if (value.status !== undefined) lines.push(`状态: ${gitStatusBits(value.status)}`)
|
|
509
501
|
return [{ type: 'text', text: lines.join('\n') }]
|
|
510
502
|
},
|
|
511
503
|
},
|
|
@@ -576,7 +568,7 @@ interface SyncResult {
|
|
|
576
568
|
changed?: boolean
|
|
577
569
|
restarted?: boolean
|
|
578
570
|
restartError?: string
|
|
579
|
-
status?:
|
|
571
|
+
status?: GitStatusView
|
|
580
572
|
}
|
|
581
573
|
interface ResolveResult {
|
|
582
574
|
ok: boolean
|
|
@@ -585,7 +577,28 @@ interface ResolveResult {
|
|
|
585
577
|
files?: string[]
|
|
586
578
|
commit?: string
|
|
587
579
|
hint?: string
|
|
588
|
-
status?:
|
|
580
|
+
status?: GitStatusView
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/** Shape of deps.git.status() as surfaced to the model (shared by renders). */
|
|
584
|
+
interface GitStatusView {
|
|
585
|
+
branch: string
|
|
586
|
+
dirty: boolean
|
|
587
|
+
dirtyFiles: string[]
|
|
588
|
+
remote: string
|
|
589
|
+
lastCommit?: string
|
|
590
|
+
ahead?: number
|
|
591
|
+
behind?: number
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** One-line 状态 summary: 分支 … 领先 … 落后 … 工作区未提交 … 最近提交. */
|
|
595
|
+
function gitStatusBits(s: GitStatusView): string {
|
|
596
|
+
const bits = [`分支 ${s.branch}`]
|
|
597
|
+
if (s.ahead !== undefined) bits.push(`领先 ${s.ahead}`)
|
|
598
|
+
if (s.behind !== undefined) bits.push(`落后 ${s.behind}`)
|
|
599
|
+
if (s.dirty) bits.push(`工作区有 ${s.dirtyFiles.length} 个未提交改动`)
|
|
600
|
+
if (s.lastCommit !== undefined) bits.push(`最近提交 ${s.lastCommit}`)
|
|
601
|
+
return bits.join(' · ')
|
|
589
602
|
}
|
|
590
603
|
|
|
591
604
|
function renderSync(value: SyncResult): Array<{ type: 'text'; text: string }> {
|
|
@@ -605,13 +618,8 @@ function renderSync(value: SyncResult): Array<{ type: 'text'; text: string }> {
|
|
|
605
618
|
}
|
|
606
619
|
if (value.restartError !== undefined) lines.push(`TW 重启失败: ${value.restartError}`)
|
|
607
620
|
if (value.status !== undefined) {
|
|
621
|
+
lines.push(`状态: ${gitStatusBits(value.status)}`)
|
|
608
622
|
const s = value.status
|
|
609
|
-
const bits = [`分支 ${s.branch}`]
|
|
610
|
-
if (s.ahead !== undefined) bits.push(`领先 ${s.ahead}`)
|
|
611
|
-
if (s.behind !== undefined) bits.push(`落后 ${s.behind}`)
|
|
612
|
-
if (s.dirty) bits.push(`工作区有 ${s.dirtyFiles.length} 个未提交改动`)
|
|
613
|
-
if (s.lastCommit !== undefined) bits.push(`最近提交 ${s.lastCommit}`)
|
|
614
|
-
lines.push(`状态: ${bits.join(' · ')}`)
|
|
615
623
|
if (s.dirty && s.dirtyFiles.length > 0) lines.push(` 未提交: ${s.dirtyFiles.join(', ')}`)
|
|
616
624
|
}
|
|
617
625
|
return [{ type: 'text', text: lines.join('\n') }]
|
package/src/index.ts
CHANGED
|
@@ -57,14 +57,18 @@ export type { GitStatusView } from './host/git.ts'
|
|
|
57
57
|
export type { Tiddler } from './host/tw-api.ts'
|
|
58
58
|
export type { WikiServerOptions, WikiStatusView } from './host/wiki.ts'
|
|
59
59
|
|
|
60
|
-
/** Plugin config (design doc §13). Defaults are applied in apply().
|
|
60
|
+
/** Plugin config (design doc §13). Defaults are applied in apply().
|
|
61
|
+
* Mirrors PluginConfigShape (src/host/config.ts) — the cordis `config:` block;
|
|
62
|
+
* keep the two shapes in lockstep when adding a config field. */
|
|
61
63
|
export interface TiddlywikiConfig {
|
|
62
64
|
wikiRoot?: string
|
|
63
65
|
wiki?: string
|
|
64
66
|
port?: number
|
|
65
67
|
git?: { autoCommit?: boolean; debounceMs?: number; remote?: string; branch?: string }
|
|
66
68
|
note?: { tag?: string }
|
|
67
|
-
ui?: { showQuickNote?: boolean; showQuickNoteDock?: boolean; sidebarLabel?: string; showPanelStatus?: boolean; showSyncButton?: boolean; followDshTheme?: boolean; darkPalette?: string; tabLabel?: string; showSessionTab?: boolean }
|
|
69
|
+
ui?: { showQuickNote?: boolean; showQuickNoteDock?: boolean; sidebarLabel?: string; showPanelStatus?: boolean; showSyncButton?: boolean; followDshTheme?: boolean; darkPalette?: string; tabLabel?: string; showSessionTab?: boolean; sendToAgent?: { enabled?: boolean; endpoint?: string; token?: string }; allArticles?: { pageSize?: number } }
|
|
70
|
+
/** 启动时自动启用的 TW 语言代码(如 "zh-Hans"),也受配置 tiddler 覆盖。 */
|
|
71
|
+
uiLanguage?: string
|
|
68
72
|
auth?: { username?: string; password?: string }
|
|
69
73
|
}
|
|
70
74
|
|
|
@@ -85,7 +89,8 @@ interface ResolvedConfig {
|
|
|
85
89
|
port: number
|
|
86
90
|
git: { autoCommit: boolean; debounceMs: number; remote: string; branch: string }
|
|
87
91
|
note: { tag: string }
|
|
88
|
-
ui: { showQuickNote: boolean; showQuickNoteDock: boolean; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; sendToAgent: { enabled: boolean } }
|
|
92
|
+
ui: { showQuickNote: boolean; showQuickNoteDock: boolean; sidebarLabel: string; showPanelStatus: boolean; showSyncButton: boolean; followDshTheme: boolean; darkPalette: string; tabLabel: string; showSessionTab: boolean; sendToAgent: { enabled: boolean; endpoint?: string; token?: string }; allArticles: { pageSize: number } }
|
|
93
|
+
uiLanguage: string
|
|
89
94
|
auth: { username?: string; password?: string }
|
|
90
95
|
}
|
|
91
96
|
|
|
@@ -95,7 +100,8 @@ const DEFAULTS: ResolvedConfig = {
|
|
|
95
100
|
port: 0,
|
|
96
101
|
git: { autoCommit: true, debounceMs: 60_000, remote: '', branch: 'main' },
|
|
97
102
|
note: { tag: 'inbox' },
|
|
98
|
-
ui: { showQuickNote: true, showQuickNoteDock: true, sidebarLabel: 'TiddlyWiki', showPanelStatus: true, showSyncButton: true, followDshTheme: true, darkPalette: DARK_PALETTE_DEFAULT, tabLabel: '知识库', showSessionTab: true, sendToAgent: { enabled: true } },
|
|
103
|
+
ui: { showQuickNote: true, showQuickNoteDock: true, sidebarLabel: 'TiddlyWiki', showPanelStatus: true, showSyncButton: true, followDshTheme: true, darkPalette: DARK_PALETTE_DEFAULT, tabLabel: '知识库', showSessionTab: true, sendToAgent: { enabled: true }, allArticles: { pageSize: 10 } },
|
|
104
|
+
uiLanguage: '',
|
|
99
105
|
auth: { username: '', password: '' },
|
|
100
106
|
}
|
|
101
107
|
|
|
@@ -228,7 +234,15 @@ export function apply(ctx: HostCtx, rawConfig: TiddlywikiConfig = {}): void {
|
|
|
228
234
|
port: rawConfig.port ?? DEFAULTS.port,
|
|
229
235
|
git: { ...DEFAULTS.git, ...(rawConfig.git ?? {}) },
|
|
230
236
|
note: { ...DEFAULTS.note, ...(rawConfig.note ?? {}) },
|
|
231
|
-
ui: {
|
|
237
|
+
ui: {
|
|
238
|
+
...DEFAULTS.ui,
|
|
239
|
+
...(rawConfig.ui ?? {}),
|
|
240
|
+
// Merge nested ui.* groups explicitly so defaults stay required (a plain
|
|
241
|
+
// spread of the lax cordis shape would widen them to optional).
|
|
242
|
+
sendToAgent: { ...DEFAULTS.ui.sendToAgent, ...(rawConfig.ui?.sendToAgent ?? {}) },
|
|
243
|
+
allArticles: { ...DEFAULTS.ui.allArticles, ...(rawConfig.ui?.allArticles ?? {}) },
|
|
244
|
+
},
|
|
245
|
+
uiLanguage: typeof rawConfig.uiLanguage === 'string' ? rawConfig.uiLanguage.trim() : DEFAULTS.uiLanguage,
|
|
232
246
|
auth: { ...DEFAULTS.auth, ...(rawConfig.auth ?? {}) },
|
|
233
247
|
}
|
|
234
248
|
const wikiPath = join(config.wikiRoot, config.wiki)
|
|
@@ -237,7 +251,7 @@ export function apply(ctx: HostCtx, rawConfig: TiddlywikiConfig = {}): void {
|
|
|
237
251
|
// Runtime-editable config (settings page): the cordis `config:` block is the
|
|
238
252
|
// BASE; a config tiddler ($:/plugins/dsh-tiddlywiki/config) written by the
|
|
239
253
|
// settings page overlays it. Effective values come from configStore.get().
|
|
240
|
-
const configStore = new ConfigStore({ note: config.note, git: config.git, ui: config.ui } satisfies PluginConfigShape)
|
|
254
|
+
const configStore = new ConfigStore({ note: config.note, git: config.git, ui: config.ui, uiLanguage: config.uiLanguage } satisfies PluginConfigShape)
|
|
241
255
|
const eff = (): PluginConfigShape => configStore.get()
|
|
242
256
|
const effectiveNoteTag = (): string => {
|
|
243
257
|
const tag = eff().note?.tag
|