dsh-tiddlywiki 0.3.0 → 0.3.1

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,79 +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.3.0",
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
+ {
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.3.1",
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
+ }
@@ -95,9 +95,12 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
95
95
 
96
96
  /* ── floating quick-note widget ────────────────────────────────
97
97
  Positioned ABOVE the shutdown launcher FAB (fixed right:24 bottom:24,
98
- z-index 900, 46px) and BELOW its confirm overlay (z-index 1000). */
98
+ z-index 900, 46px) and BELOW its confirm overlay (z-index 1000).
99
+ Interactive overlays (the open card, the native-editor popup) sit ABOVE the
100
+ passive FAB column (sync/status, z-index 950) so those FABs never cover the
101
+ card's own bottom-right buttons. */
99
102
  .dsh-tw-note {
100
- position: fixed; right: 24px; bottom: 88px; z-index: 950;
103
+ position: fixed; right: 24px; bottom: 88px; z-index: 980;
101
104
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
102
105
  font-family: inherit;
103
106
  }
@@ -108,11 +111,18 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
108
111
  border-radius: 14px; box-shadow: var(--dsw-shadow-lv3, 0 8px 30px rgba(0,0,0,.22));
109
112
  padding: 12px; display: flex; flex-direction: column; gap: 10px;
110
113
  font-size: 13px;
114
+ backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
115
+ animation: dsh-tw-note-in 180ms ease;
111
116
  }
112
117
  .dsh-tw-note-card[hidden] { display: none; }
118
+ @keyframes dsh-tw-note-in {
119
+ from { opacity: 0; transform: translateY(8px) scale(.98); }
120
+ to { opacity: 1; transform: translateY(0) scale(1); }
121
+ }
113
122
  .dsh-tw-note-head {
114
123
  display: flex; align-items: center; gap: 8px;
115
- font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #222);
124
+ font-size: 12px; font-weight: 600; letter-spacing: .2px;
125
+ color: var(--dsw-alias-label-primary, #222);
116
126
  }
117
127
  .dsh-tw-note-head .dsh-tw-note-label { margin-right: auto; display: flex; align-items: center; gap: 6px; }
118
128
  .dsh-tw-note-close {
@@ -196,23 +206,26 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
196
206
  border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
197
207
  background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
198
208
  font: inherit; font-size: 12px; padding: 6px 10px; border-radius: 8px; cursor: pointer;
199
- transition: filter 120ms ease;
209
+ transition: filter 120ms ease, transform 80ms ease;
200
210
  }
201
211
  .dsh-tw-note-upload:hover { filter: brightness(.96); }
212
+ .dsh-tw-note-upload:active { transform: scale(.96); }
202
213
  .dsh-tw-note-save {
203
214
  border: 1px solid transparent; background: var(--dsw-alias-brand-primary, #3e63dd); color: #fff;
204
215
  font: inherit; font-size: 12px; padding: 6px 16px; border-radius: 8px; cursor: pointer;
205
- transition: filter 120ms ease;
216
+ transition: filter 120ms ease, transform 80ms ease;
206
217
  }
207
218
  .dsh-tw-note-save:hover:not(:disabled) { filter: brightness(1.08); }
219
+ .dsh-tw-note-save:active:not(:disabled) { transform: scale(.96); }
208
220
  .dsh-tw-note-save:disabled { opacity: .55; cursor: default; }
209
221
  .dsh-tw-note-edit {
210
222
  border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.18));
211
223
  background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
212
224
  font: inherit; font-size: 12px; padding: 6px 10px; border-radius: 8px; cursor: pointer;
213
- transition: filter 120ms ease;
225
+ transition: filter 120ms ease, transform 80ms ease;
214
226
  }
215
227
  .dsh-tw-note-edit:hover:not(:disabled) { filter: brightness(.96); }
228
+ .dsh-tw-note-edit:active:not(:disabled) { transform: scale(.96); }
216
229
  .dsh-tw-note-edit:disabled { opacity: .55; cursor: default; }
217
230
  /* ── Multi-tag chip editor (quick-note tags) ─────────────────────────────── */
218
231
  .dsh-tw-note-tags { position: relative; flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
@@ -250,7 +263,7 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
250
263
  background: var(--dsw-alias-bg-layer-2, #fff); color: var(--dsw-alias-label-primary, #222);
251
264
  border: 1px solid var(--dsw-alias-border-l2, rgba(0,0,0,.2));
252
265
  border-radius: 12px; box-shadow: 0 14px 44px rgba(0,0,0,.3);
253
- z-index: 980; font-family: inherit; font-size: 13px;
266
+ z-index: 990; font-family: inherit; font-size: 13px;
254
267
  }
255
268
  .dsh-tw-editor-bar {
256
269
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
@@ -33,6 +33,11 @@ const MAX_PROXY_BODY_BYTES = 16 * 1024 * 1024
33
33
  /** Max uploaded file body. */
34
34
  const MAX_UPLOAD_BYTES = 64 * 1024 * 1024
35
35
 
36
+ /** Tiddler type for quick-notes: Markdown, so the uploaded images/links and
37
+ * any Markdown in the note actually render in TW (a type-less tiddler is
38
+ * treated as plain wiki text and shows raw `![..]`/`[..]` instead). */
39
+ const NOTE_TYPE = 'text/markdown'
40
+
36
41
  /** Structural webserver face (a subset of dsh-host-webserver). */
37
42
  export interface WebServerFace {
38
43
  register(route: { kind: 'exact' | 'prefix'; path: string; handler: (req: IncomingMessage, res: ServerResponse) => void }): () => void
@@ -125,10 +130,13 @@ function timestampTitle(date = new Date()): string {
125
130
 
126
131
  /**
127
132
  * Open a tiddler in TW's NATIVE editor: save the tiddler (when text is
128
- * non-empty), reuse or create a DRAFT tiddler carrying `draft.of`/`draft.title`
129
- * (TW's story view renders drafts with the EditTemplate — list.js:
130
- * `isDraft && editTemplate`), and return the draft title so the client can
131
- * navigate the panel iframe to `#<draftTitle>`.
133
+ * non-empty) as Markdown, reuse or create a DRAFT tiddler carrying
134
+ * `draft.of`/`draft.title` (TW's story view renders drafts with the
135
+ * EditTemplate — list.js: `isDraft && editTemplate`), and return the draft
136
+ * title so the client can navigate the panel iframe to `#<draftTitle>`.
137
+ * The draft carries the same `text/markdown` type as the note so saving it in
138
+ * TW keeps Markdown (a draft without a matching type would overwrite the
139
+ * note's type back to plain wiki text).
132
140
  */
133
141
  export async function openInTwEditor(
134
142
  client: TiddlyWebClient,
@@ -137,7 +145,7 @@ export async function openInTwEditor(
137
145
  tags: string[],
138
146
  ): Promise<{ title: string; draftTitle: string }> {
139
147
  if (text.trim().length > 0) {
140
- await client.put({ title, text, tags })
148
+ await client.put({ title, text, tags, type: NOTE_TYPE })
141
149
  }
142
150
  // Draft content: the provided text, else the existing tiddler's content.
143
151
  let draftText = text
@@ -159,7 +167,7 @@ export async function openInTwEditor(
159
167
  /* fall back to a fresh draft */
160
168
  }
161
169
  if (draftTitle === undefined) draftTitle = `Draft of "${title}" ${Date.now()}`
162
- await client.put({ title: draftTitle, text: draftText, 'draft.of': title, 'draft.title': title, type: 'text/vnd.tiddlywiki' })
170
+ await client.put({ title: draftTitle, text: draftText, 'draft.of': title, 'draft.title': title, type: NOTE_TYPE })
163
171
  return { title, draftTitle }
164
172
  }
165
173
 
@@ -206,9 +214,9 @@ export function registerRoutes(ctx: { webServer: WebServerFace }, deps: RouteDep
206
214
  }
207
215
  const title = typeof body.title === 'string' && body.title.trim().length > 0 ? body.title.trim() : timestampTitle()
208
216
  const tags = resolveTags(body, deps.noteDefaults().tag)
209
- await client.put({ title, text, tags })
217
+ await client.put({ title, text, tags, type: NOTE_TYPE })
210
218
  deps.autoCommit()
211
- json(res, { ok: true, title, tag: tags.join(' '), tags, text })
219
+ json(res, { ok: true, title, tag: tags.join(' '), tags, text, type: NOTE_TYPE })
212
220
  } catch (err) {
213
221
  json(res, { ok: false, error: err instanceof Error ? err.message : String(err) }, 500)
214
222
  }
package/src/index.ts CHANGED
@@ -152,7 +152,9 @@ const PROMPT_TEXT = `## TiddlyWiki 持久知识库
152
152
  2. 收工 commit + push:\`tiddlywiki_git_sync action=sync\`(pull → commit → push)。
153
153
  3. 插件会自动防抖 commit(默认 60s),手动同步用上面的工具。
154
154
 
155
- 把 wiki 当作长期记忆与知识沉淀的地方:会议纪要、决策记录、调研笔记、随手的想法都可存成独立 tiddler(tag 建议用 inbox/meeting/decision 等便于检索)。`
155
+ 把 wiki 当作长期记忆与知识沉淀的地方:会议纪要、决策记录、调研笔记、随手的想法都可存成独立 tiddler(tag 建议用 inbox/meeting/decision 等便于检索)。
156
+
157
+ 用本插件自动创建笔记时,除了业务性 tag 外,请把「当前工作区(项目)的名字」也作为标签之一加上去(例如 \`tiddlywiki_put\` 的 tags 里带上当前 workspace 名),这样笔记能按项目归集、检索。`
156
158
 
157
159
  /**
158
160
  * Mount the host half.