dsh-tiddlywiki 0.1.0 → 0.1.2

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,63 +1,79 @@
1
- {
2
- "name": "dsh-tiddlywiki",
3
- "description": "TiddlyWiki 5 as the DSH persistent knowledge base: tiddlywiki_* agent tools (search/get/put/delete + git sync), a full TiddlyWiki editor embedded in the GUI center column, a floating quick-note widget in the chat area, and git-based sync with auto-commit. Mounts via the official dsh plugin system — no DSH source changes.",
4
- "version": "0.1.0",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "exports": {
8
- ".": "./lib/index.js",
9
- "./client": "./lib/client.js",
10
- "./package.json": "./package.json"
11
- },
12
- "dsh": {
13
- "bundle": {
14
- "patch": "./cordis.patch.yml"
15
- },
16
- "client": {
17
- "inject": [
18
- "slots"
19
- ],
20
- "platform": "web"
21
- }
22
- },
23
- "files": [
24
- "lib/**/*.js",
25
- "lib/**/*.js.map",
26
- "src",
27
- "cordis.patch.yml",
28
- "LICENSE",
29
- "README.md"
30
- ],
31
- "license": "MIT",
32
- "homepage": "https://github.com/bbqisbbq/dsh-tiddlywiki#readme",
33
- "repository": {
34
- "type": "git",
35
- "url": "https://github.com/bbqisbbq/dsh-tiddlywiki.git"
36
- },
37
- "bugs": {
38
- "url": "https://github.com/bbqisbbq/dsh-tiddlywiki/issues"
39
- },
40
- "engines": {
41
- "node": ">=22"
42
- },
43
- "dependencies": {
44
- "tiddlywiki": "^5.4.1"
45
- },
46
- "devDependencies": {
47
- "@types/node": "^22.20.1",
48
- "@types/react": "^19.1.0",
49
- "react": "^19.1.0",
50
- "tsdown": "0.22.2",
51
- "tsx": "^4.19.2",
52
- "typescript": "~5.7.2",
53
- "unrun": "*"
54
- },
55
- "scripts": {
56
- "build": "node scripts/clean-lib.mjs && npm run build:host && npm run build:client",
57
- "build:host": "tsdown -c tsdown.host.config.ts",
58
- "build:client": "tsdown -c tsdown.client.config.ts && node scripts/wrap-client.mjs",
59
- "watch": "tsdown -c tsdown.host.config.ts --watch",
60
- "typecheck": "tsc --noEmit",
61
- "selftest": "node scripts/selftest.mjs"
62
- }
63
- }
1
+ {
2
+ "name": "dsh-tiddlywiki",
3
+ "description": "TiddlyWiki 5 as the DSH persistent knowledge base: tiddlywiki_* agent tools (search/get/put/delete + git sync), a full TiddlyWiki editor embedded in the GUI center column, a floating quick-note widget in the chat area, and git-based sync with auto-commit. Mounts via the official dsh plugin system — no DSH source changes.",
4
+ "version": "0.1.2",
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
+ "cordis.patch.yml",
44
+ "LICENSE",
45
+ "README.md"
46
+ ],
47
+ "license": "MIT",
48
+ "homepage": "https://github.com/bbqisbbq/dsh-tiddlywiki#readme",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/bbqisbbq/dsh-tiddlywiki.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/bbqisbbq/dsh-tiddlywiki/issues"
55
+ },
56
+ "engines": {
57
+ "node": ">=22"
58
+ },
59
+ "dependencies": {
60
+ "tiddlywiki": "^5.4.1"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^22.20.1",
64
+ "@types/react": "^19.1.0",
65
+ "react": "^19.1.0",
66
+ "tsdown": "0.22.2",
67
+ "tsx": "^4.19.2",
68
+ "typescript": "~5.7.2",
69
+ "unrun": "*"
70
+ },
71
+ "scripts": {
72
+ "build": "node scripts/clean-lib.mjs && npm run build:host && npm run build:client",
73
+ "build:host": "tsdown -c tsdown.host.config.ts",
74
+ "build:client": "tsdown -c tsdown.client.config.ts && node scripts/wrap-client.mjs",
75
+ "watch": "tsdown -c tsdown.host.config.ts --watch",
76
+ "typecheck": "tsc --noEmit",
77
+ "selftest": "node scripts/selftest.mjs"
78
+ }
79
+ }
@@ -1,121 +1,121 @@
1
- /**
2
- * Floating popup iframe that loads TiddlyWiki's NATIVE editor for a draft
3
- * (quick-note "✏️ 在 TW 中编辑"). A small draggable + resizable overlay with its
4
- * own iframe pointed at `twUrl#<draftTitle>`: the fragment-only navigation
5
- * triggers TW's hashchange, which opens the draft in the story, and because the
6
- * draft tiddler carries `draft.of` the story renders the native EditTemplate.
7
- *
8
- * Independent of the center panel — a separate floating window so the user can
9
- * edit a note without leaving the chat context.
10
- *
11
- * @module dsh-tiddlywiki/client/editor-popup
12
- */
13
-
14
- let root: HTMLDivElement | undefined
15
- let frame: HTMLIFrameElement | undefined
16
- let titleEl: HTMLSpanElement | undefined
17
-
18
- /** Open (create on first use) the popup and load `url` (twUrl#draftTitle). */
19
- export function openEditorPopup(url: string, label: string): void {
20
- ensurePopup()
21
- if (root === undefined || frame === undefined) return
22
- if (titleEl !== undefined) titleEl.textContent = `TiddlyWiki 编辑器 · ${label}`
23
- root.style.display = ''
24
- // Same-base fragment navigation reloads nothing; a changed base (restart on a
25
- // new port) reloads the app and TW still opens the draft from the hash.
26
- frame.src = url
27
- }
28
-
29
- /** Remove the popup DOM entirely (plugin dispose). */
30
- export function disposeEditorPopup(): void {
31
- root?.remove()
32
- root = undefined
33
- frame = undefined
34
- titleEl = undefined
35
- }
36
-
37
- function ensurePopup(): void {
38
- if (root !== undefined && frame !== undefined) return
39
-
40
- root = document.createElement('div')
41
- root.className = 'dsh-tw-editor-popup'
42
- root.style.display = 'none'
43
-
44
- const bar = document.createElement('div')
45
- bar.className = 'dsh-tw-editor-bar'
46
- titleEl = document.createElement('span')
47
- titleEl.className = 'dsh-tw-editor-title'
48
- titleEl.textContent = 'TiddlyWiki 编辑器'
49
- const close = document.createElement('button')
50
- close.type = 'button'
51
- close.className = 'dsh-tw-editor-close'
52
- close.textContent = '✕'
53
- close.title = '关闭'
54
- bar.append(titleEl, close)
55
-
56
- frame = document.createElement('iframe')
57
- frame.className = 'dsh-tw-editor-frame'
58
- frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups')
59
- frame.title = 'TiddlyWiki 编辑器'
60
-
61
- const resize = document.createElement('div')
62
- resize.className = 'dsh-tw-editor-resize'
63
- resize.title = '拖拽调整大小'
64
-
65
- root.append(bar, frame, resize)
66
- document.body.append(root)
67
-
68
- close.addEventListener('click', () => {
69
- if (root !== undefined) root.style.display = 'none'
70
- })
71
-
72
- // Drag by the title bar (un-center by setting explicit left/top + margin 0).
73
- bar.addEventListener('mousedown', (event) => {
74
- if (event.button !== 0 || root === undefined) return
75
- event.preventDefault()
76
- const rect = root.getBoundingClientRect()
77
- const startX = event.clientX
78
- const startY = event.clientY
79
- const baseLeft = rect.left
80
- const baseTop = rect.top
81
- const onMove = (ev: MouseEvent): void => {
82
- if (root === undefined) return
83
- root.style.left = `${baseLeft + ev.clientX - startX}px`
84
- root.style.top = `${baseTop + ev.clientY - startY}px`
85
- root.style.margin = '0'
86
- root.style.right = 'auto'
87
- root.style.bottom = 'auto'
88
- }
89
- const onUp = (): void => {
90
- window.removeEventListener('mousemove', onMove)
91
- window.removeEventListener('mouseup', onUp)
92
- }
93
- window.addEventListener('mousemove', onMove)
94
- window.addEventListener('mouseup', onUp)
95
- })
96
-
97
- // Resize from the bottom-right corner.
98
- resize.addEventListener('mousedown', (event) => {
99
- if (event.button !== 0 || root === undefined) return
100
- event.preventDefault()
101
- event.stopPropagation()
102
- const rect = root.getBoundingClientRect()
103
- const startX = event.clientX
104
- const startY = event.clientY
105
- const baseW = rect.width
106
- const baseH = rect.height
107
- const onMove = (ev: MouseEvent): void => {
108
- if (root === undefined) return
109
- root.style.width = `${Math.max(360, baseW + ev.clientX - startX)}px`
110
- root.style.height = `${Math.max(260, baseH + ev.clientY - startY)}px`
111
- root.style.right = 'auto'
112
- root.style.bottom = 'auto'
113
- }
114
- const onUp = (): void => {
115
- window.removeEventListener('mousemove', onMove)
116
- window.removeEventListener('mouseup', onUp)
117
- }
118
- window.addEventListener('mousemove', onMove)
119
- window.addEventListener('mouseup', onUp)
120
- })
121
- }
1
+ /**
2
+ * Floating popup iframe that loads TiddlyWiki's NATIVE editor for a draft
3
+ * (quick-note "✏️ 在 TW 中编辑"). A small draggable + resizable overlay with its
4
+ * own iframe pointed at `twUrl#<draftTitle>`: the fragment-only navigation
5
+ * triggers TW's hashchange, which opens the draft in the story, and because the
6
+ * draft tiddler carries `draft.of` the story renders the native EditTemplate.
7
+ *
8
+ * Independent of the center panel — a separate floating window so the user can
9
+ * edit a note without leaving the chat context.
10
+ *
11
+ * @module dsh-tiddlywiki/client/editor-popup
12
+ */
13
+
14
+ let root: HTMLDivElement | undefined
15
+ let frame: HTMLIFrameElement | undefined
16
+ let titleEl: HTMLSpanElement | undefined
17
+
18
+ /** Open (create on first use) the popup and load `url` (twUrl#draftTitle). */
19
+ export function openEditorPopup(url: string, label: string): void {
20
+ ensurePopup()
21
+ if (root === undefined || frame === undefined) return
22
+ if (titleEl !== undefined) titleEl.textContent = `TiddlyWiki 编辑器 · ${label}`
23
+ root.style.display = ''
24
+ // Same-base fragment navigation reloads nothing; a changed base (restart on a
25
+ // new port) reloads the app and TW still opens the draft from the hash.
26
+ frame.src = url
27
+ }
28
+
29
+ /** Remove the popup DOM entirely (plugin dispose). */
30
+ export function disposeEditorPopup(): void {
31
+ root?.remove()
32
+ root = undefined
33
+ frame = undefined
34
+ titleEl = undefined
35
+ }
36
+
37
+ function ensurePopup(): void {
38
+ if (root !== undefined && frame !== undefined) return
39
+
40
+ root = document.createElement('div')
41
+ root.className = 'dsh-tw-editor-popup'
42
+ root.style.display = 'none'
43
+
44
+ const bar = document.createElement('div')
45
+ bar.className = 'dsh-tw-editor-bar'
46
+ titleEl = document.createElement('span')
47
+ titleEl.className = 'dsh-tw-editor-title'
48
+ titleEl.textContent = 'TiddlyWiki 编辑器'
49
+ const close = document.createElement('button')
50
+ close.type = 'button'
51
+ close.className = 'dsh-tw-editor-close'
52
+ close.textContent = '✕'
53
+ close.title = '关闭'
54
+ bar.append(titleEl, close)
55
+
56
+ frame = document.createElement('iframe')
57
+ frame.className = 'dsh-tw-editor-frame'
58
+ frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups')
59
+ frame.title = 'TiddlyWiki 编辑器'
60
+
61
+ const resize = document.createElement('div')
62
+ resize.className = 'dsh-tw-editor-resize'
63
+ resize.title = '拖拽调整大小'
64
+
65
+ root.append(bar, frame, resize)
66
+ document.body.append(root)
67
+
68
+ close.addEventListener('click', () => {
69
+ if (root !== undefined) root.style.display = 'none'
70
+ })
71
+
72
+ // Drag by the title bar (un-center by setting explicit left/top + margin 0).
73
+ bar.addEventListener('mousedown', (event) => {
74
+ if (event.button !== 0 || root === undefined) return
75
+ event.preventDefault()
76
+ const rect = root.getBoundingClientRect()
77
+ const startX = event.clientX
78
+ const startY = event.clientY
79
+ const baseLeft = rect.left
80
+ const baseTop = rect.top
81
+ const onMove = (ev: MouseEvent): void => {
82
+ if (root === undefined) return
83
+ root.style.left = `${baseLeft + ev.clientX - startX}px`
84
+ root.style.top = `${baseTop + ev.clientY - startY}px`
85
+ root.style.margin = '0'
86
+ root.style.right = 'auto'
87
+ root.style.bottom = 'auto'
88
+ }
89
+ const onUp = (): void => {
90
+ window.removeEventListener('mousemove', onMove)
91
+ window.removeEventListener('mouseup', onUp)
92
+ }
93
+ window.addEventListener('mousemove', onMove)
94
+ window.addEventListener('mouseup', onUp)
95
+ })
96
+
97
+ // Resize from the bottom-right corner.
98
+ resize.addEventListener('mousedown', (event) => {
99
+ if (event.button !== 0 || root === undefined) return
100
+ event.preventDefault()
101
+ event.stopPropagation()
102
+ const rect = root.getBoundingClientRect()
103
+ const startX = event.clientX
104
+ const startY = event.clientY
105
+ const baseW = rect.width
106
+ const baseH = rect.height
107
+ const onMove = (ev: MouseEvent): void => {
108
+ if (root === undefined) return
109
+ root.style.width = `${Math.max(360, baseW + ev.clientX - startX)}px`
110
+ root.style.height = `${Math.max(260, baseH + ev.clientY - startY)}px`
111
+ root.style.right = 'auto'
112
+ root.style.bottom = 'auto'
113
+ }
114
+ const onUp = (): void => {
115
+ window.removeEventListener('mousemove', onMove)
116
+ window.removeEventListener('mouseup', onUp)
117
+ }
118
+ window.addEventListener('mousemove', onMove)
119
+ window.addEventListener('mouseup', onUp)
120
+ })
121
+ }
@@ -1,76 +1,76 @@
1
- /**
2
- * Browser half entry for dsh-tiddlywiki (design doc §12, D5): injects the
3
- * stylesheet, mounts the sidebar entry, the center-column TiddlyWiki panel,
4
- * the floating quick-note widget, and registers the plugin's settings page
5
- * (config panel, §13) into the shell's Settings.
6
- *
7
- * Failure policy: DOM mounting problems are logged, never thrown — the web
8
- * shell fails the whole boot when a plugin apply throws.
9
- *
10
- * Export shape: `name` / `inject` / `apply`, no default.
11
- *
12
- * @module dsh-tiddlywiki/client
13
- */
14
- import { injectStyles } from './styles.ts'
15
- import { PanelState } from './state.ts'
16
- import { mountSidebarEntry } from './sidebar-entry.ts'
17
- import { mountPanel } from './panel.ts'
18
- import { mountNoteWidget } from './note-widget.ts'
19
- import { disposeEditorPopup } from './editor-popup.ts'
20
- import { SettingsSection } from './settings-page.ts'
21
-
22
- /** Client plugin name. */
23
- export const name = 'dsh-tiddlywiki/client'
24
-
25
- /** Required client services: the slots registry (settings.section seat). */
26
- export const inject: string[] = ['slots']
27
-
28
- /** Effect-hook face the runner provides on the client context. */
29
- interface ClientContextFace {
30
- slots?: {
31
- inject(name: string, register: () => unknown): (() => void) | undefined
32
- register(
33
- opts: { name: string; id: string; order?: number; label?: string | (() => string) },
34
- component: unknown,
35
- ): () => void
36
- }
37
- effect?(fn: () => unknown, label?: string): void
38
- }
39
-
40
- /**
41
- * Client entry: installs styles and mounts the DOM seats + settings page.
42
- * @param ctx - the cordis client context.
43
- */
44
- export function apply(ctx: ClientContextFace): void {
45
- try {
46
- injectStyles()
47
- const state = new PanelState()
48
- const disposers: Array<() => void> = []
49
- try {
50
- disposers.push(mountSidebarEntry(state))
51
- disposers.push(mountPanel(state))
52
- disposers.push(mountNoteWidget())
53
- disposers.push(disposeEditorPopup)
54
- } catch (error) {
55
- // DOM failures degrade the plugin, never the GUI.
56
- console.error('[dsh-tiddlywiki] mount failed:', error)
57
- }
58
- try {
59
- // Settings page → Settings → 「TiddlyWiki 知识库」(config panel §13).
60
- const removeSettings = ctx.slots?.inject('settings.section', () =>
61
- ctx.slots?.register(
62
- { name: 'settings.section', id: 'dsh-tiddlywiki', order: 50, label: 'TiddlyWiki 知识库' },
63
- SettingsSection,
64
- ),
65
- )
66
- if (removeSettings !== undefined) disposers.push(removeSettings)
67
- } catch (error) {
68
- console.error('[dsh-tiddlywiki] settings section failed:', error)
69
- }
70
- ctx.effect?.(() => () => {
71
- for (const dispose of disposers.splice(0)) dispose()
72
- }, 'dsh-tiddlywiki: client mount')
73
- } catch (error) {
74
- console.error('[dsh-tiddlywiki] client half failed to start:', error)
75
- }
76
- }
1
+ /**
2
+ * Browser half entry for dsh-tiddlywiki (design doc §12, D5): injects the
3
+ * stylesheet, mounts the sidebar entry, the center-column TiddlyWiki panel,
4
+ * the floating quick-note widget, and registers the plugin's settings page
5
+ * (config panel, §13) into the shell's Settings.
6
+ *
7
+ * Failure policy: DOM mounting problems are logged, never thrown — the web
8
+ * shell fails the whole boot when a plugin apply throws.
9
+ *
10
+ * Export shape: `name` / `inject` / `apply`, no default.
11
+ *
12
+ * @module dsh-tiddlywiki/client
13
+ */
14
+ import { injectStyles } from './styles.ts'
15
+ import { PanelState } from './state.ts'
16
+ import { mountSidebarEntry } from './sidebar-entry.ts'
17
+ import { mountPanel } from './panel.ts'
18
+ import { mountNoteWidget } from './note-widget.ts'
19
+ import { disposeEditorPopup } from './editor-popup.ts'
20
+ import { SettingsSection } from './settings-page.ts'
21
+
22
+ /** Client plugin name. */
23
+ export const name = 'dsh-tiddlywiki/client'
24
+
25
+ /** Required client services: the slots registry (settings.section seat). */
26
+ export const inject: string[] = ['slots']
27
+
28
+ /** Effect-hook face the runner provides on the client context. */
29
+ interface ClientContextFace {
30
+ slots?: {
31
+ inject(name: string, register: () => unknown): (() => void) | undefined
32
+ register(
33
+ opts: { name: string; id: string; order?: number; label?: string | (() => string) },
34
+ component: unknown,
35
+ ): () => void
36
+ }
37
+ effect?(fn: () => unknown, label?: string): void
38
+ }
39
+
40
+ /**
41
+ * Client entry: installs styles and mounts the DOM seats + settings page.
42
+ * @param ctx - the cordis client context.
43
+ */
44
+ export function apply(ctx: ClientContextFace): void {
45
+ try {
46
+ injectStyles()
47
+ const state = new PanelState()
48
+ const disposers: Array<() => void> = []
49
+ try {
50
+ disposers.push(mountSidebarEntry(state))
51
+ disposers.push(mountPanel(state))
52
+ disposers.push(mountNoteWidget())
53
+ disposers.push(disposeEditorPopup)
54
+ } catch (error) {
55
+ // DOM failures degrade the plugin, never the GUI.
56
+ console.error('[dsh-tiddlywiki] mount failed:', error)
57
+ }
58
+ try {
59
+ // Settings page → Settings → 「TiddlyWiki 知识库」(config panel §13).
60
+ const removeSettings = ctx.slots?.inject('settings.section', () =>
61
+ ctx.slots?.register(
62
+ { name: 'settings.section', id: 'dsh-tiddlywiki', order: 50, label: 'TiddlyWiki 知识库' },
63
+ SettingsSection,
64
+ ),
65
+ )
66
+ if (removeSettings !== undefined) disposers.push(removeSettings)
67
+ } catch (error) {
68
+ console.error('[dsh-tiddlywiki] settings section failed:', error)
69
+ }
70
+ ctx.effect?.(() => () => {
71
+ for (const dispose of disposers.splice(0)) dispose()
72
+ }, 'dsh-tiddlywiki: client mount')
73
+ } catch (error) {
74
+ console.error('[dsh-tiddlywiki] client half failed to start:', error)
75
+ }
76
+ }