dsh-tiddlywiki 0.33.1 → 0.33.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/docs/CHANGELOG.md +6 -0
- package/lib/client.js +1 -1
- package/package.json +1 -1
- package/src/client/tid-preview.ts +76 -31
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
> 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
|
|
6
6
|
|
|
7
|
+
- **v0.33.2**(2026-10-26):**`.tid` 预览仍不生效 —— 这次是"服务还没出现就放弃"**。
|
|
8
|
+
v0.33.1 修好了 `key` 配对,但用户实测仍是纯文本,且 devtools 里 `[class*="dsh-tw-tid"]` 数量为 0(正文组件压根没渲染)。
|
|
9
|
+
根因在插件的**加载顺序**:`documentPreviews` 是另一个插件(宿主的 `dsh-client-ui-sidebar-documentpreview`)用 `ctx.reflect.provide(...)` 提供的,本插件若先加载,`ctx.get(...)` 那一瞬间拿到 `undefined`,v0.32/0.33.0/0.33.1 就**静默 return** 了 —— 界面上看不出差别(宿主用内置纯文本兜底),console 里也一条日志都没有,等于把失败藏起来。
|
|
10
|
+
现在改成**短轮询等它出现**(250ms × 40 ≈ 10s),并给每一步补 `[dsh-tiddlywiki]` 前缀的诊断日志:`ctx.get`/`ctx.slots` 是否存在、第几次尝试注册上元数据、正文是否注册进 keyed 子槽、等不到时的 warn。正文外壳加 `data-dsh-tw-tid` 标记,devtools 里一条 `document.querySelectorAll('[data-dsh-tw-tid]').length` 就能判定我们的组件到底有没有渲染。
|
|
11
|
+
守门同步改判据:不再钉"查一次就返回",改钉 `setTimeout(attempt, 250)` 的轮询、`getter('documentPreviews')` 的取值形态、以及"服务始终没出现"那条可诊断 warn —— 静默跳过从这一版起是**被测出来的**行为,不再是遗漏。
|
|
12
|
+
|
|
7
13
|
- **v0.33.1**(2026-10-26):**`.tid` 预览改为真正生效**(v0.32.0 那一版静默失效:打开 `.tid` 仍显示纯文本)。
|
|
8
14
|
根因是宿主契约里我读错的一处:DSH 的文件预览分「元数据 + keyed 正文」两半,**正文按 `key` 配对** ——
|
|
9
15
|
宿主自己写的是 `ctx.slots.register({ name: sidebar.right.tab.document, key: BODY_ID }, Body)`,而 v0.32.0 写成了 `id:`。
|
package/lib/client.js
CHANGED
|
@@ -962,7 +962,7 @@ html[data-dsh-tw-active] .dshDesktopConversationSurface > :not([data-dsh-tw-view
|
|
|
962
962
|
`),n=t.indexOf(`
|
|
963
963
|
|
|
964
964
|
`),r=n<0?t:t.slice(0,n),i=n<0?``:t.slice(n+2),a=[],o,s=r.trim().length>0;for(let e of r.split(`
|
|
965
|
-
`)){if(e.trim().length===0)continue;let t=/^([^\s:][^:]*):\s?(.*)$/.exec(e);if(t===null){s=!1;continue}let n=(t[1]??``).trim(),r=(t[2]??``).trim();n.length!==0&&(n===`title`?o=r:a.push([n,r]))}return n<0&&(!s||o===void 0&&a.length===0)?{fields:[],text:t}:{...o===void 0?{}:{title:o},fields:a,text:i}}function FS(e){let t=e?.content;if(typeof t==`string`)return t;if(typeof t!=`object`||!t)return``;let n=t;if(typeof n.text==`string`)return n.text;let r=n.pages,i=[];if(Array.isArray(r)){for(let e of r)if(typeof e==`object`&&e){let t=e;i.push({offset:typeof t.offset==`number`?t.offset:0,text:typeof t.text==`string`?t.text:``})}}else if(typeof r==`object`&&r){for(let[e,t]of Object.entries(r))if(typeof t==`object`&&t){let n=t;i.push({offset:Number(e)||0,text:typeof n.text==`string`?n.text:``})}}return i.sort((e,t)=>e.offset-t.offset).map(e=>e.text).join(``)}async function IS(e,t){try{let n=await fetch(De(ne,t),{method:`POST`,headers:{"content-type":`application/json`,"x-requested-with":`TiddlyWiki`},body:JSON.stringify({text:e}),signal:AbortSignal.timeout(15e3)});if(!n.ok)return null;let r=await n.text();return r.trim().length>0?r:null}catch{return null}}function LS(){return function(e){let t=FS(e),n=c.useMemo(()=>PS(t),[t]),[r,i]=c.useState(null),[a,o]=c.useState(!1);c.useEffect(()=>{let e=!0;return o(!1),n.text.trim().length===0?(i(null),()=>{e=!1}):(IS(n.text).then(t=>{e&&(t===null?(o(!0),i(null)):i(t))}),()=>{e=!1})},[n.text]);let s=[];n.title!==void 0&&n.title.length>0&&s.push(c.createElement(`div`,{key:`title`,className:`dsh-tw-tid-title`},`📄 ${n.title}`)),n.fields.length>0&&s.push(c.createElement(`div`,{key:`fields`,className:`dsh-tw-tid-fields`},n.fields.map(([e,t])=>c.createElement(`span`,{key:e,className:`dsh-tw-tid-field`},`${e}: ${t.length>60?`${t.slice(0,60)}…`:t}`))));let l;return l=t.trim().length===0?c.createElement(`div`,{className:`dsh-tw-tid-empty`},S(`frame.tidPreviewWaiting`)):n.text.trim().length===0?c.createElement(`div`,{className:`dsh-tw-tid-empty`},S(`frame.tidPreviewNoBody`)):r===null?c.createElement(`div`,{className:`dsh-tw-tid-raw`},a?c.createElement(`div`,{className:`dsh-tw-tid-note`},S(`frame.tidPreviewFallback`)):null,c.createElement(`pre`,null,n.text)):c.createElement(`div`,{className:`dsh-tw-tid-body`,dangerouslySetInnerHTML:{__html:r}}),c.createElement(`div`,{className:`dsh-tw-tid-preview
|
|
965
|
+
`)){if(e.trim().length===0)continue;let t=/^([^\s:][^:]*):\s?(.*)$/.exec(e);if(t===null){s=!1;continue}let n=(t[1]??``).trim(),r=(t[2]??``).trim();n.length!==0&&(n===`title`?o=r:a.push([n,r]))}return n<0&&(!s||o===void 0&&a.length===0)?{fields:[],text:t}:{...o===void 0?{}:{title:o},fields:a,text:i}}function FS(e){let t=e?.content;if(typeof t==`string`)return t;if(typeof t!=`object`||!t)return``;let n=t;if(typeof n.text==`string`)return n.text;let r=n.pages,i=[];if(Array.isArray(r)){for(let e of r)if(typeof e==`object`&&e){let t=e;i.push({offset:typeof t.offset==`number`?t.offset:0,text:typeof t.text==`string`?t.text:``})}}else if(typeof r==`object`&&r){for(let[e,t]of Object.entries(r))if(typeof t==`object`&&t){let n=t;i.push({offset:Number(e)||0,text:typeof n.text==`string`?n.text:``})}}return i.sort((e,t)=>e.offset-t.offset).map(e=>e.text).join(``)}async function IS(e,t){try{let n=await fetch(De(ne,t),{method:`POST`,headers:{"content-type":`application/json`,"x-requested-with":`TiddlyWiki`},body:JSON.stringify({text:e}),signal:AbortSignal.timeout(15e3)});if(!n.ok)return null;let r=await n.text();return r.trim().length>0?r:null}catch{return null}}function LS(){return function(e){let t=FS(e),n=c.useMemo(()=>PS(t),[t]),[r,i]=c.useState(null),[a,o]=c.useState(!1);c.useEffect(()=>{let e=!0;return o(!1),n.text.trim().length===0?(i(null),()=>{e=!1}):(IS(n.text).then(t=>{e&&(t===null?(o(!0),i(null)):i(t))}),()=>{e=!1})},[n.text]);let s=[];n.title!==void 0&&n.title.length>0&&s.push(c.createElement(`div`,{key:`title`,className:`dsh-tw-tid-title`},`📄 ${n.title}`)),n.fields.length>0&&s.push(c.createElement(`div`,{key:`fields`,className:`dsh-tw-tid-fields`},n.fields.map(([e,t])=>c.createElement(`span`,{key:e,className:`dsh-tw-tid-field`},`${e}: ${t.length>60?`${t.slice(0,60)}…`:t}`))));let l;return l=t.trim().length===0?c.createElement(`div`,{className:`dsh-tw-tid-empty`},S(`frame.tidPreviewWaiting`)):n.text.trim().length===0?c.createElement(`div`,{className:`dsh-tw-tid-empty`},S(`frame.tidPreviewNoBody`)):r===null?c.createElement(`div`,{className:`dsh-tw-tid-raw`},a?c.createElement(`div`,{className:`dsh-tw-tid-note`},S(`frame.tidPreviewFallback`)):null,c.createElement(`pre`,null,n.text)):c.createElement(`div`,{className:`dsh-tw-tid-body`,dangerouslySetInnerHTML:{__html:r}}),c.createElement(`div`,{className:`dsh-tw-tid-preview`,"data-dsh-tw-tid":jS},...s,l)}}function RS(e){let t=[],n=typeof e.get==`function`?e.get.bind(e):void 0;if(console.info(`[dsh-tiddlywiki] tid preview: ctx.get=`+(n===void 0?`missing`:`present`)+`, ctx.slots=`+(e.slots===void 0?`missing`:`present`)),n===void 0)return t;let r=0,i,a=!1,o=()=>{if(a)return;r+=1;let s=n(`documentPreviews`);if(s==null){if(r>=40){console.warn(`[dsh-tiddlywiki] tid preview: documentPreviews never appeared after `+r+` attempts; .tid files will fall back to the builtin plain-text preview`);return}i=setTimeout(o,250);return}a=!0;try{t.push(s.register({id:jS,extensions:[...MS],priority:`external`,title:()=>S(`frame.tidPreviewTitle`),loading:`text-pages`,wrap:!1})),console.info(`[dsh-tiddlywiki] tid preview: metadata registered on attempt `+r+` (id=dsh-tiddlywiki-tid, suffixes=`+MS.join(`/`)+`)`)}catch(e){console.warn(`[dsh-tiddlywiki] tid preview registration failed:`,e);return}let c=e.slots;if(c===void 0){console.warn(`[dsh-tiddlywiki] tid preview: no ctx.slots; rolling back the metadata registration`);for(let e of t.splice(0))e();return}let l=c.inject(NS,()=>c.register({name:NS,key:jS},LS()));l===void 0?console.warn(`[dsh-tiddlywiki] tid preview: body registration failed (slot sidebar.right.tab.document)`):(t.push(l),console.info(`[dsh-tiddlywiki] tid preview: body registered into sidebar.right.tab.document with key=dsh-tiddlywiki-tid`))};return o(),[()=>{a=!0,i!==void 0&&clearTimeout(i);for(let e of t.splice(0))e()}]}const zS=[`slots`];function BS(e){try{let t=[],n=!1,r=()=>{n=!0;for(let e of t.splice(0))e()},i=(e,t)=>{try{t()}catch(t){console.error(`[dsh-tiddlywiki] ${e} failed:`,t)}};i(`styles`,()=>t.push(T()));let a=new ee,o,s;if(i(`quick-note widget`,()=>{o=Ub(),t.push(()=>o?.dispose())}),i(`sync controller`,()=>{s=Kb(),t.push(()=>s?.dispose())}),i(`sidebar entry`,()=>t.push(st(a))),i(`center panel`,()=>t.push(tn(a))),o!==void 0&&s!==void 0){let e=o,n=s;i(`knowledge FAB`,()=>t.push(Xb(a,e,n)))}i(`editor popup`,()=>t.push(mn)),e.slots!==void 0&&Le().then(r=>{if(n)return;let a=o;r.showQuickNoteDock&&a!==void 0&&i(`quick-note dock`,()=>{let n=e.slots?.inject(`conversation.input.dock`,()=>e.slots?.register({name:`conversation.input.dock`,id:`quick-note`,order:8,label:S(`chrome.dockQuickNote`)},Qb(a)));n!==void 0&&t.push(n)}),i(`wiki scope seat`,()=>{let n=e.slots?.inject(`conversation.input.left`,()=>e.slots?.register({name:`conversation.input.left`,id:`wiki-scope`,order:9,label:S(`chrome.scopeSlotLabel`)},ox()));n!==void 0&&t.push(n)}),i(`session summary tab`,()=>{let n=dx(e.slots,r);n!==void 0&&t.push(n)})}).catch(e=>{console.error(`[dsh-tiddlywiki] ui config load failed:`,e)}),i(`rightbar mount`,()=>{let r,i=a=>{let o=e.get?.(`sidebarRightTabs`);if(o===void 0){a<6&&!n&&(r=window.setTimeout(()=>i(a+1),500*(a+1)));return}Le().then(r=>{if(n||!r.showRightbarTab)return;let i=AS(o,e.slots);i!==void 0&&t.push(i)}).catch(e=>{console.error(`[dsh-tiddlywiki] rightbar config load failed:`,e)})};t.push(()=>{r!==void 0&&window.clearTimeout(r)}),i(0)}),i(`tool views`,()=>{e.slots!==void 0&&t.push(...TS(e.slots))}),i(`wiki link interceptor`,()=>t.push(bS())),i(`tid preview`,()=>t.push(...RS(e))),i(`locale registration`,()=>t.push(...p(e.get))),i(`settings section`,()=>{let n=e.slots?.inject(`settings.section`,()=>e.slots?.register({name:`settings.section`,id:`dsh-tiddlywiki`,order:50,label:S(`frame.settingsSection`)},Vx));n!==void 0&&t.push(n)}),e.effect===void 0?window.addEventListener(`pagehide`,r,{once:!0}):e.effect(()=>r,`dsh-tiddlywiki: client mount`)}catch(e){console.error(`[dsh-tiddlywiki] client half failed to start:`,e)}}exports.apply=BS,exports.inject=zS,exports.name=`dsh-tiddlywiki/client`;
|
|
966
966
|
return module.exports;
|
|
967
967
|
}
|
|
968
968
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tiddlywiki",
|
|
3
3
|
"description": "把 TiddlyWiki 5 变成你和 Agent 共用的本地文档中心(纯文本 + git):你在 DSH 界面里阅读、写作、记日记,Agent 用 16 个 tiddlywiki_* 工具读写同一批笔记;每条笔记都是你能读、能改、能审计、能随时带走的文件——不是自动记忆插件,不做后台抓取。可选一键发布到微信公众号草稿箱。 Turn TiddlyWiki 5 into a document center you and your agent share, in plain text under git — a knowledge base you can read, edit, audit and take with you, not an auto-memory plugin. Mounts via the official dsh plugin system; no DSH source changes.",
|
|
4
|
-
"version": "0.33.
|
|
4
|
+
"version": "0.33.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"dsh",
|
|
@@ -148,7 +148,7 @@ export function createTidPreviewBody(): (props: unknown) => React.ReactElement {
|
|
|
148
148
|
)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
return React.createElement('div', { className: 'dsh-tw-tid-preview' }, ...head, body)
|
|
151
|
+
return React.createElement('div', { className: 'dsh-tw-tid-preview', 'data-dsh-tw-tid': TID_PREVIEW_ID }, ...head, body)
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -187,40 +187,85 @@ interface PreviewCtx {
|
|
|
187
187
|
/**
|
|
188
188
|
* 注册 `.tid` 预览(元数据 + 正文**成对**)。
|
|
189
189
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
190
|
+
* 为什么要「等」而不是查一次:`documentPreviews` 是**另一个插件**(宿主的
|
|
191
|
+
* `dsh-client-ui-sidebar-documentpreview`)用 `ctx.reflect.provide('documentPreviews', …)`
|
|
192
|
+
* 提供的。如果本插件先加载,`ctx.get('documentPreviews')` 那一刻还是 `undefined` ——
|
|
193
|
+
* v0.32/0.33.0 就是在这里**静默放弃**的(用户看到的仍是内置纯文本,console 里
|
|
194
|
+
* 一条日志都没有,排查成本极高)。现在改成**短轮询**(250ms × 40 ≈ 10s):
|
|
195
|
+
* 服务一出现就注册;始终没出现才记一条 warn 说明原因。
|
|
196
|
+
*
|
|
197
|
+
* 诊断日志都带 `[dsh-tiddlywiki]` 前缀,方便在 devtools 里一眼认出是我们的。
|
|
192
198
|
*/
|
|
193
199
|
export function registerTidPreview(ctx: PreviewCtx): Array<() => void> {
|
|
194
200
|
const disposers: Array<() => void> = []
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
previews.register({
|
|
200
|
-
id: TID_PREVIEW_ID,
|
|
201
|
-
extensions: [...TID_EXTENSIONS],
|
|
202
|
-
// 外部实现压过宿主的纯文本兜底(宿主按 `priority === 'builtin'` 分档)。
|
|
203
|
-
priority: 'external',
|
|
204
|
-
// 宿主自己传的是函数(`) => t('viewer.text')`),语言切换时能重取。
|
|
205
|
-
title: () => t('frame.tidPreviewTitle'),
|
|
206
|
-
loading: 'text-pages',
|
|
207
|
-
wrap: false,
|
|
208
|
-
}),
|
|
209
|
-
)
|
|
210
|
-
} catch (err) {
|
|
211
|
-
// 开发者日志,不是用户文案(与仓库其它模块的 console.warn 同一性质)。
|
|
212
|
-
console.warn('[dsh-tiddlywiki] tid preview registration failed:', err)
|
|
201
|
+
const getter = typeof ctx.get === 'function' ? ctx.get.bind(ctx) : undefined
|
|
202
|
+
console.info('[dsh-tiddlywiki] tid preview: ctx.get=' + (getter === undefined ? 'missing' : 'present') + ', ctx.slots=' + (ctx.slots === undefined ? 'missing' : 'present'))
|
|
203
|
+
if (getter === undefined) {
|
|
204
|
+
// 没有服务读取器 ⇒ 这个宿主版本给不了 documentPreviews,按设计跳过。
|
|
213
205
|
return disposers
|
|
214
206
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
207
|
+
|
|
208
|
+
let attempts = 0
|
|
209
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
210
|
+
let done = false
|
|
211
|
+
|
|
212
|
+
const attempt = (): void => {
|
|
213
|
+
if (done) return
|
|
214
|
+
attempts += 1
|
|
215
|
+
const previews = getter('documentPreviews') as DocumentPreviewsFace | undefined
|
|
216
|
+
if (previews === undefined || previews === null) {
|
|
217
|
+
if (attempts >= 40) {
|
|
218
|
+
// 开发者日志(客户端守门禁止中文字面量,故一律英文)
|
|
219
|
+
console.warn('[dsh-tiddlywiki] tid preview: documentPreviews never appeared after ' + attempts + ' attempts; .tid files will fall back to the builtin plain-text preview')
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
timer = setTimeout(attempt, 250)
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
done = true
|
|
226
|
+
try {
|
|
227
|
+
disposers.push(
|
|
228
|
+
previews.register({
|
|
229
|
+
id: TID_PREVIEW_ID,
|
|
230
|
+
extensions: [...TID_EXTENSIONS],
|
|
231
|
+
// 外部实现压过宿主的纯文本兜底(宿主按 `priority === 'builtin'` 分档)。
|
|
232
|
+
priority: 'external',
|
|
233
|
+
// 宿主自己传的是函数(`) => t('viewer.text')`),语言切换时能重取。
|
|
234
|
+
title: () => t('frame.tidPreviewTitle'),
|
|
235
|
+
loading: 'text-pages',
|
|
236
|
+
wrap: false,
|
|
237
|
+
}),
|
|
238
|
+
)
|
|
239
|
+
console.info('[dsh-tiddlywiki] tid preview: metadata registered on attempt ' + attempts + ' (id=' + TID_PREVIEW_ID + ', suffixes=' + TID_EXTENSIONS.join('/') + ')')
|
|
240
|
+
} catch (err) {
|
|
241
|
+
// 开发者日志,不是用户文案(与仓库其它模块的 console.warn 同一性质)。
|
|
242
|
+
console.warn('[dsh-tiddlywiki] tid preview registration failed:', err)
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
const slots = ctx.slots
|
|
246
|
+
if (slots === undefined) {
|
|
247
|
+
// 元数据已注册但没有正文 → 宿主会拿不到渲染器,宁可整体撤回。
|
|
248
|
+
console.warn('[dsh-tiddlywiki] tid preview: no ctx.slots; rolling back the metadata registration')
|
|
249
|
+
for (const dispose of disposers.splice(0)) dispose()
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
const bodyDispose = slots.inject(TID_PREVIEW_SLOT, () =>
|
|
253
|
+
slots.register({ name: TID_PREVIEW_SLOT, key: TID_PREVIEW_ID }, createTidPreviewBody()),
|
|
254
|
+
)
|
|
255
|
+
if (bodyDispose === undefined) console.warn('[dsh-tiddlywiki] tid preview: body registration failed (slot ' + TID_PREVIEW_SLOT + ')')
|
|
256
|
+
else {
|
|
257
|
+
disposers.push(bodyDispose)
|
|
258
|
+
console.info('[dsh-tiddlywiki] tid preview: body registered into ' + TID_PREVIEW_SLOT + ' with key=' + TID_PREVIEW_ID)
|
|
259
|
+
}
|
|
220
260
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
261
|
+
|
|
262
|
+
attempt()
|
|
263
|
+
// 清理:停掉还在等服务的定时器 + 回收已注册的两半。
|
|
264
|
+
return [
|
|
265
|
+
() => {
|
|
266
|
+
done = true
|
|
267
|
+
if (timer !== undefined) clearTimeout(timer)
|
|
268
|
+
for (const dispose of disposers.splice(0)) dispose()
|
|
269
|
+
},
|
|
270
|
+
]
|
|
226
271
|
}
|