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.
package/package.json CHANGED
@@ -1,86 +1,86 @@
1
- {
2
- "name": "dsh-tiddlywiki",
3
- "description": "TiddlyWiki 5 as the DSH persistent knowledge base: tiddlywiki_* agent tools (search with filters/recent/tags/batch/rename + git sync & conflict resolve), a full TiddlyWiki editor embedded in the GUI center column (same-origin proxy, works over Tailscale/LAN/domain), a quick-note card with draft auto-save & recent-notes picker behind a single knowledge FAB, and git-based sync with auto-commit. Mounts via the official dsh plugin system — no DSH source changes.",
4
- "version": "0.16.21",
5
- "type": "module",
6
- "keywords": [
7
- "dsh",
8
- "dsh-plugin",
9
- "tiddlywiki",
10
- "knowledge-base",
11
- "note-taking",
12
- "notes",
13
- "wiki",
14
- "git-sync",
15
- "agent-tools",
16
- "plugin"
17
- ],
18
- "author": {
19
- "name": "bbqisbbq",
20
- "url": "https://github.com/bbqisbbq"
21
- },
22
- "main": "lib/index.js",
23
- "exports": {
24
- ".": "./lib/index.js",
25
- "./client": "./lib/client.js",
26
- "./package.json": "./package.json"
27
- },
28
- "dsh": {
29
- "bundle": {
30
- "patch": "./cordis.patch.yml"
31
- },
32
- "client": {
33
- "inject": [
34
- "slots"
35
- ],
36
- "platform": "web"
37
- }
38
- },
39
- "files": [
40
- "lib/**/*.js",
41
- "lib/**/*.js.map",
42
- "src",
43
- "docs",
44
- "cordis.patch.yml",
45
- "LICENSE",
46
- "README.md"
47
- ],
48
- "license": "MIT",
49
- "homepage": "https://github.com/bbqisbbq/dsh-tiddlywiki#readme",
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/bbqisbbq/dsh-tiddlywiki.git"
53
- },
54
- "bugs": {
55
- "url": "https://github.com/bbqisbbq/dsh-tiddlywiki/issues"
56
- },
57
- "engines": {
58
- "node": ">=22"
59
- },
60
- "dependencies": {
61
- "tiddlywiki": "^5.4.1"
62
- },
63
- "devDependencies": {
64
- "@codemirror/commands": "^6.11.0",
65
- "@codemirror/lang-markdown": "^6.5.2",
66
- "@codemirror/language": "^6.12.4",
67
- "@codemirror/state": "^6.7.2",
68
- "@codemirror/view": "^6.43.10",
69
- "@lezer/highlight": "^1.2.3",
70
- "@types/node": "^22.20.1",
71
- "@types/react": "^19.1.0",
72
- "react": "^19.1.0",
73
- "tsdown": "0.22.2",
74
- "tsx": "^4.19.2",
75
- "typescript": "~5.7.2",
76
- "unrun": "*"
77
- },
78
- "scripts": {
79
- "build": "node scripts/clean-lib.mjs && npm run build:host && npm run build:client",
80
- "build:host": "tsdown -c tsdown.host.config.ts",
81
- "build:client": "tsdown -c tsdown.client.config.ts && node scripts/wrap-client.mjs",
82
- "watch": "tsdown -c tsdown.host.config.ts --watch",
83
- "typecheck": "tsc --noEmit",
84
- "selftest": "node scripts/selftest.mjs"
85
- }
86
- }
1
+ {
2
+ "name": "dsh-tiddlywiki",
3
+ "description": "TiddlyWiki 5 as the DSH persistent knowledge base: tiddlywiki_* agent tools (search with filters/recent/tags/batch/rename + git sync & conflict resolve), a full TiddlyWiki editor embedded in the GUI center column (same-origin proxy, works over Tailscale/LAN/domain), a quick-note card with draft auto-save & recent-notes picker behind a single knowledge FAB, and git-based sync with auto-commit. Mounts via the official dsh plugin system — no DSH source changes.",
4
+ "version": "0.16.23",
5
+ "type": "module",
6
+ "keywords": [
7
+ "dsh",
8
+ "dsh-plugin",
9
+ "tiddlywiki",
10
+ "knowledge-base",
11
+ "note-taking",
12
+ "notes",
13
+ "wiki",
14
+ "git-sync",
15
+ "agent-tools",
16
+ "plugin"
17
+ ],
18
+ "author": {
19
+ "name": "bbqisbbq",
20
+ "url": "https://github.com/bbqisbbq"
21
+ },
22
+ "main": "lib/index.js",
23
+ "exports": {
24
+ ".": "./lib/index.js",
25
+ "./client": "./lib/client.js",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "dsh": {
29
+ "bundle": {
30
+ "patch": "./cordis.patch.yml"
31
+ },
32
+ "client": {
33
+ "inject": [
34
+ "slots"
35
+ ],
36
+ "platform": "web"
37
+ }
38
+ },
39
+ "files": [
40
+ "lib/**/*.js",
41
+ "lib/**/*.js.map",
42
+ "src",
43
+ "docs",
44
+ "cordis.patch.yml",
45
+ "LICENSE",
46
+ "README.md"
47
+ ],
48
+ "license": "MIT",
49
+ "homepage": "https://github.com/bbqisbbq/dsh-tiddlywiki#readme",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/bbqisbbq/dsh-tiddlywiki.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/bbqisbbq/dsh-tiddlywiki/issues"
56
+ },
57
+ "engines": {
58
+ "node": ">=22"
59
+ },
60
+ "dependencies": {
61
+ "tiddlywiki": "^5.4.1"
62
+ },
63
+ "devDependencies": {
64
+ "@codemirror/commands": "^6.11.0",
65
+ "@codemirror/lang-markdown": "^6.5.2",
66
+ "@codemirror/language": "^6.12.4",
67
+ "@codemirror/state": "^6.7.2",
68
+ "@codemirror/view": "^6.43.10",
69
+ "@lezer/highlight": "^1.2.3",
70
+ "@types/node": "^22.20.1",
71
+ "@types/react": "^19.1.0",
72
+ "react": "^19.1.0",
73
+ "tsdown": "0.22.2",
74
+ "tsx": "^4.19.2",
75
+ "typescript": "~5.7.2",
76
+ "unrun": "*"
77
+ },
78
+ "scripts": {
79
+ "build": "node scripts/clean-lib.mjs && npm run build:host && npm run build:client",
80
+ "build:host": "tsdown -c tsdown.host.config.ts",
81
+ "build:client": "tsdown -c tsdown.client.config.ts && node scripts/wrap-client.mjs",
82
+ "watch": "tsdown -c tsdown.host.config.ts --watch",
83
+ "typecheck": "tsc --noEmit",
84
+ "selftest": "node scripts/selftest.mjs"
85
+ }
86
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * DSH Better Sidebar (dsh-better-sidebar) TiddlyWiki tab type (v0.16.23).
3
+ *
4
+ * dsh-better-sidebar exposes a client-side registry service on the cordis
5
+ * context as `ctx.betterSidebar` (registerTab / registerFileViewer / openTab /
6
+ * closeTab …). This module registers a TW tab type there: the sidebar's + menu
7
+ * (and any caller of `openTab({ type: 'dsh-tiddlywiki' })`) opens the
8
+ * SAME-ORIGIN TW proxy iframe — the same shared machinery the center panel and
9
+ * the native rightbar tab use (tw-frame.ts).
10
+ *
11
+ * Mutual exclusion (one TW client at a time) rides the shared
12
+ * `dsh-panel-activate` protocol: when this tab becomes visible the center
13
+ * overlay / rightbar tab close; when another TW surface activates, this tab
14
+ * closes itself through the service (closeTab). Wiki links in the reply
15
+ * stream route here while the tab is visible (tw-frame.ts' live-frame
16
+ * registry → panel.ts).
17
+ *
18
+ * The integration is optional: the caller reads `ctx.get('betterSidebar')`
19
+ * and skips silently when the plugin is not installed (older DSH / other web
20
+ * profiles). Registering a tab also gives every better-sidebar user an
21
+ * enable/disable switch for it in the Side card settings page — that gate is
22
+ * the plugin's own, independent of our `ui.showBetterSidebarTab` config.
23
+ *
24
+ * @module dsh-tiddlywiki/client/better-sidebar-tab
25
+ */
26
+ import * as React from 'react'
27
+ import {
28
+ ACTIVATE_EVENT,
29
+ createTwFrameController,
30
+ getTabLabel,
31
+ TwTabIcon,
32
+ type TwFrameController,
33
+ warmTabLabel,
34
+ } from './tw-frame.ts'
35
+
36
+ /** The tab type this package owns in the better-sidebar registry. */
37
+ export const TW_BETTER_SIDEBAR_ID = 'dsh-tiddlywiki'
38
+ /** Activation-event name for THIS surface (distinct from center 'dsh-tiddlywiki' / rightbar). */
39
+ const BETTER_SIDEBAR_PANEL_NAME = 'dsh-tiddlywiki/bettersidebar'
40
+
41
+ /** Structural faces over the better-sidebar contract (no @deepseek-ai imports). */
42
+
43
+ export interface BetterSidebarTabProps {
44
+ ctx: { get?(name: string): unknown }
45
+ scope: { sessionId?: string; cwd?: string }
46
+ tab: { id: string; type: string }
47
+ /** Whether this tab is the active one AND the panel is open (live views pause otherwise). */
48
+ visible: boolean
49
+ }
50
+
51
+ /** Structural face over the better-sidebar registry service (no @deepseek-ai imports). */
52
+ export interface BetterSidebarFace {
53
+ registerTab(descriptor: {
54
+ id: string
55
+ title: string | (() => string)
56
+ icon?: unknown
57
+ single?: boolean
58
+ component: (props: BetterSidebarTabProps) => unknown
59
+ }): () => void
60
+ closeTab(tabId: string, scope?: unknown): void
61
+ }
62
+
63
+ /**
64
+ * The tab body: a thin React wrapper that mounts the TW iframe into a
65
+ * plain-DOM host, like the rightbar tab body. `visible` pauses/resumes the
66
+ * frame (lazy-loads on the first show); the `dsh-panel-activate` protocol
67
+ * keeps exactly one TW client on screen.
68
+ */
69
+ export function TwBetterSidebarTabBody(props: BetterSidebarTabProps): React.ReactElement {
70
+ const { ctx, scope, tab } = props
71
+ // 老版本 better-sidebar 可能不传 visible(缺失按「已可见」处理——tab 渲染在其
72
+ // 面板内即视为在屏)。
73
+ const visible = props.visible !== false
74
+ const hostRef = React.useRef<HTMLDivElement | null>(null)
75
+ const controllerRef = React.useRef<TwFrameController | null>(null)
76
+
77
+ React.useEffect(() => {
78
+ const host = hostRef.current
79
+ if (host === null) return
80
+ const ac = new AbortController()
81
+ const controller = createTwFrameController(host, ac.signal)
82
+ controllerRef.current = controller
83
+ return () => {
84
+ controller.dispose()
85
+ ac.abort()
86
+ controllerRef.current = null
87
+ }
88
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- one controller per tab (id stable; single-instance type).
89
+ }, [tab.id])
90
+
91
+ React.useEffect(() => {
92
+ controllerRef.current?.setVisible(visible)
93
+ }, [visible])
94
+
95
+ // When this tab becomes visible, close the center overlay / rightbar tab.
96
+ // When any OTHER TW surface activates, close this tab (one TW client).
97
+ React.useEffect(() => {
98
+ if (!visible) return
99
+ document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: BETTER_SIDEBAR_PANEL_NAME }))
100
+ const onActivate = (event: Event): void => {
101
+ const detail = (event as CustomEvent).detail
102
+ if (detail !== BETTER_SIDEBAR_PANEL_NAME) {
103
+ const service = ctx.get?.('betterSidebar') as BetterSidebarFace | undefined
104
+ service?.closeTab(tab.id, scope)
105
+ }
106
+ }
107
+ document.addEventListener(ACTIVATE_EVENT, onActivate)
108
+ return () => document.removeEventListener(ACTIVATE_EVENT, onActivate)
109
+ }, [visible, tab.id, scope, ctx])
110
+
111
+ return React.createElement('div', { ref: hostRef, className: 'dsh-tw-rightbar-tab', 'data-dsh-tw-bettersidebar': '' })
112
+ }
113
+
114
+ /**
115
+ * Register the TW tab type in a live better-sidebar service for the caller's
116
+ * lifetime; the returned disposer unregisters it. Call only when
117
+ * `ctx.get('betterSidebar')` actually returned a service.
118
+ */
119
+ export function mountBetterSidebarTab(service: BetterSidebarFace): (() => void) | undefined {
120
+ try {
121
+ const remove = service.registerTab({
122
+ id: TW_BETTER_SIDEBAR_ID,
123
+ title: (): string => getTabLabel(),
124
+ icon: (size: number) => TwTabIcon({ size }),
125
+ // Single instance: opening the tab focuses the existing one.
126
+ single: true,
127
+ component: (props: BetterSidebarTabProps) => TwBetterSidebarTabBody(props),
128
+ })
129
+ // Warm the + menu label from the live config (ui.tabLabel).
130
+ warmTabLabel()
131
+ return remove
132
+ } catch (error) {
133
+ console.error('[dsh-tiddlywiki] better-sidebar tab mount failed:', error)
134
+ return undefined
135
+ }
136
+ }
@@ -25,6 +25,7 @@ import { disposeEditorPopup } from './editor-popup.ts'
25
25
  import { SettingsSection } from './settings-page.ts'
26
26
  import { registerToolViews, installWikiLinkInterceptor } from './tool-views.ts'
27
27
  import { mountRightbarTab, type RightbarSlotsFace } from './rightbar-tab.ts'
28
+ import { mountBetterSidebarTab, type BetterSidebarFace } from './better-sidebar-tab.ts'
28
29
 
29
30
  /** Client plugin name. */
30
31
  export const name = 'dsh-tiddlywiki/client'
@@ -127,6 +128,35 @@ export function apply(ctx: ClientContextFace): void {
127
128
  // 右侧栏集成失败只影响该功能本身,绝不让整个插件挂掉。
128
129
  console.error('[dsh-tiddlywiki] rightbar mount failed:', error)
129
130
  }
131
+ try {
132
+ // DSH Better Sidebar(dsh-better-sidebar 插件)集成:可选挂载——仅当该
133
+ // 插件的 client 半部提供了 betterSidebar 服务时才启用(未安装 / 老版本
134
+ // DSH 静默跳过,插件其余功能不受影响)。注册 TW tab 类型(+ 菜单可开);
135
+ // 由 ui.showBetterSidebarTab 控制(默认开)。better-sidebar 的 Side
136
+ // 设置页也会为已注册 tab 自动提供它自己的启用开关。
137
+ let bsRetryTimer: number | undefined
138
+ const tryMountBetterSidebar = (attempt: number): void => {
139
+ const service = ctx.get?.('betterSidebar') as BetterSidebarFace | undefined
140
+ if (service === undefined) {
141
+ // better-sidebar 插件可能在本次 apply 之后才就绪:有限重试几次即可。
142
+ if (attempt < 6 && !clientDisposed) {
143
+ bsRetryTimer = window.setTimeout(() => tryMountBetterSidebar(attempt + 1), 500 * (attempt + 1))
144
+ }
145
+ return
146
+ }
147
+ void fetchUiConfig().then((cfg) => {
148
+ if (clientDisposed) return
149
+ if (!cfg.showBetterSidebarTab) return
150
+ const removeBs = mountBetterSidebarTab(service)
151
+ if (removeBs !== undefined) disposers.push(removeBs)
152
+ })
153
+ }
154
+ tryMountBetterSidebar(0)
155
+ disposers.push(() => { if (bsRetryTimer !== undefined) window.clearTimeout(bsRetryTimer) })
156
+ } catch (error) {
157
+ // Better Sidebar 集成失败只影响该功能本身,绝不让整个插件挂掉。
158
+ console.error('[dsh-tiddlywiki] better-sidebar mount failed:', error)
159
+ }
130
160
  try {
131
161
  // Reply-stream native tool cards: keyed `tool.call.toolview` slots for
132
162
  // every tiddlywiki_* tool (additive — our keys are unclaimed).
@@ -23,7 +23,7 @@
23
23
  import type { PanelState } from './state.ts'
24
24
  import { ENTRY_SELECTOR } from './sidebar-entry.ts'
25
25
  import { attachThemeSync, setThemeSyncConfig } from './theme-sync.ts'
26
- import { openTiddlerInRightbar } from './rightbar-tab.ts'
26
+ import { openTiddlerInLiveTab } from './tw-frame.ts'
27
27
 
28
28
  export const PANEL_RELOAD_EVENT = 'dsh-tw-panel-reload'
29
29
 
@@ -317,9 +317,10 @@ export function mountPanel(state: PanelState): () => void {
317
317
  const detail = (event as CustomEvent).detail as { title?: unknown } | undefined
318
318
  const title = typeof detail?.title === 'string' && detail.title.length > 0 ? detail.title : ''
319
319
  if (title.length === 0) return
320
- // 右侧栏的 TW tab 可见时,链接直接在那里打开(与聊天并排);否则退回
321
- // 中央面板。互斥由 rightbar-tab 的 dsh-panel-activate 协议保证。
322
- if (openTiddlerInRightbar(title)) return
320
+ // 侧边栏(rightbar / better-sidebar)的 TW tab 可见时,链接直接在那里
321
+ // 打开(与聊天并排);否则退回中央面板。互斥由 tw-frame.ts 共享的
322
+ // dsh-panel-activate 协议保证。
323
+ if (openTiddlerInLiveTab(title)) return
323
324
  pendingHash = `#${encodeURIComponent(title)}`
324
325
  state.openPanel()
325
326
  applyPendingHash()