dsh-thoughtdag 0.5.18 → 0.5.19
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 +13 -12
- package/dist-app/assets/{canonical-agWec4XS.js → canonical-bSxBmsm7.js} +2 -2
- package/dist-app/assets/{canvas-record-C2yZbu5N.js → canvas-record-qO1KINUh.js} +1 -1
- package/dist-app/assets/{claude-code-session-CbBcaUqO.js → claude-code-session-DkNDRQp8.js} +1 -1
- package/dist-app/assets/{codex-session-wxU_-LWp.js → codex-session-B2hAZ_ax.js} +1 -1
- package/dist-app/assets/{dsh-session-DmOP3XKa.js → dsh-session-AQk-ryCb.js} +1 -1
- package/dist-app/assets/{experiment-loop-XP_t_khd.js → experiment-loop-BzzzDlbH.js} +1 -1
- package/dist-app/assets/{http-bridge-Cyr8eePQ.js → http-bridge-BnYAV4lB.js} +1 -1
- package/dist-app/assets/{index-DWanOFbr.js → index-BH9ozg79.js} +14 -14
- package/dist-app/assets/{index-ShRKYhWs.js → index-BmwffA_p.js} +1 -1
- package/dist-app/assets/{index-DFZu6h8O.js → index-YWyx765g.js} +3 -3
- package/dist-app/assets/{index-1Y_JzMpx.js → index-aOSCk5D-.js} +1 -1
- package/dist-app/assets/{pi-session-DXj3K4Qb.js → pi-session-CNcLBGJ1.js} +1 -1
- package/dist-app/assets/{sensitive-scan-B3jSpKVr.js → sensitive-scan-Cs2TuwIB.js} +1 -1
- package/dist-app/assets/{session-handoff-y5-kuOb1.js → session-handoff-CLQ0ZIYD.js} +2 -2
- package/dist-app/assets/{shared-DxaHN0fp.js → shared-LHIg0YHa.js} +1 -1
- package/dist-app/assets/{turndown-plugin-gfm.cjs-wNy9Tytn.js → turndown-plugin-gfm.cjs-j992pbuV.js} +1 -1
- package/dist-app/assets/{update-check-DyyT5hjM.js → update-check-3zMP9HL5.js} +1 -1
- package/dist-app/index.html +1 -1
- package/lib/client.js +161 -67
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1,28 +1,45 @@
|
|
|
1
1
|
// dsh-thoughtdag client half — the lightest possible browser shim.
|
|
2
|
-
// It
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
2
|
+
// It puts ThoughtDAG where the harness puts its own pages: an entry in the
|
|
3
|
+
// sidebar's panel list (beside Plugins and Scheduled tasks) that opens the
|
|
4
|
+
// canvas in the main column, through the host's own `main` panel slot and
|
|
5
|
+
// `layout.selectPanel`. The canvas itself is a SAME-ORIGIN iframe at
|
|
6
|
+
// /thoughtdag/ (the SPA is served by the host half on the same web server —
|
|
7
|
+
// no CORS, no second origin). The iframe never lives inside the host's React
|
|
8
|
+
// tree: the main slot renders only the selected panel and would unmount it on
|
|
9
|
+
// every switch, reloading the canvas. So the panel page is a placeholder that
|
|
10
|
+
// fills the main column, and the iframe is a fixed layer laid exactly over
|
|
11
|
+
// it while the page is mounted — the host owns navigation, chrome, locale and
|
|
12
|
+
// theme; the canvas keeps its state across switches.
|
|
13
13
|
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// Hosts without the panel slot (older harnesses) get the previous door: a
|
|
15
|
+
// floating 对话 | 思维图 pill over the chat and a full-window overlay (0.4.19
|
|
16
|
+
// to 0.5.18; its placement was the subject of #55, #61, #63 and #73 — every
|
|
17
|
+
// spot in a stranger's chrome collides with something, which is why the
|
|
18
|
+
// panel entry replaces it wherever the host offers one).
|
|
19
|
+
//
|
|
20
|
+
// All conversation smarts live inside the ThoughtDAG app; this file only
|
|
21
|
+
// opens the door and forwards the current session id so the canvas can offer
|
|
22
|
+
// to mirror it. Same pattern as dsh-synapse: window.__ModuleLoader__.load
|
|
23
|
+
// with a module whose inject lists the client services it reads and whose
|
|
24
|
+
// apply touches the DOM.
|
|
17
25
|
|
|
18
26
|
window.__ModuleLoader__.load({
|
|
19
27
|
id: 'dsh-thoughtdag',
|
|
20
|
-
factory: () => {
|
|
28
|
+
factory: (require) => {
|
|
21
29
|
const module = { exports: {} }
|
|
22
30
|
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
31
|
+
// the host's React, for the two slot components (the sidebar glyph and
|
|
32
|
+
// the panel page); absent on a host that lends none, which also has no
|
|
33
|
+
// panel slot to fill
|
|
34
|
+
let React = null
|
|
35
|
+
try { React = require('react') } catch { React = null }
|
|
36
|
+
|
|
37
|
+
// sessions: the current session for the canvas to mirror. uiWorkspace: the
|
|
38
|
+
// harness's directory picker (the OS dialog when the harness runs on this
|
|
39
|
+
// machine, its in-app browser when reached remotely). slots / locale /
|
|
40
|
+
// layout: the panel entry, its label in the host's language, and the
|
|
41
|
+
// switch back to the conversation.
|
|
42
|
+
module.exports.inject = ['sessions', 'uiWorkspace', 'slots', 'locale', 'layout']
|
|
26
43
|
module.exports.apply = ctx => {
|
|
27
44
|
const currentSession = () => {
|
|
28
45
|
const snapshot = ctx.sessions.list.getSnapshot()
|
|
@@ -46,26 +63,15 @@ window.__ModuleLoader__.load({
|
|
|
46
63
|
style.setAttribute('data-plugin-css', CSS_ID)
|
|
47
64
|
document.head.append(style)
|
|
48
65
|
}
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
// the lights and the window controls are never covered, and nothing of
|
|
59
|
-
// the host's session header shows through (#39). A browser tab has no
|
|
60
|
-
// clearance: no band, the overlay fills the window, the canvas keeps its
|
|
61
|
-
// own switch.
|
|
62
|
-
// The floating pill sits in the window's top strip, centre-right, on every platform: 12px down in a
|
|
63
|
-
// browser tab, vertically centred in the host's own strip on the desktop (40px on Windows, 48px on
|
|
64
|
-
// macOS). It is no-drag, so the strip's drag region never takes its clicks (#55: pinned half into the
|
|
65
|
-
// drag region without no-drag, its upper half was swallowed; moved below the strip, it landed in the
|
|
66
|
-
// host's session header). Centre-right keeps it clear of the host's menu on the left and the window
|
|
67
|
-
// controls on the right.
|
|
68
|
-
style.textContent = '.dsh-td-switch{position:fixed;z-index:120;top:12px;left:60%;display:flex;align-items:center;gap:2px;transform:translateX(-50%);-webkit-app-region:no-drag;border:1px solid #d1d5db;border-radius:999px;background:rgba(255,255,255,.96);padding:3px;backdrop-filter:blur(10px)}.dsh-td-switch button{height:28px;border:0;border-radius:999px;background:transparent;padding:0 11px;color:#6b7280;font:600 12px Inter,system-ui,sans-serif;cursor:pointer;white-space:nowrap}.dsh-td-switch button:hover{background:#f3f4f6;color:#111827}.dsh-td-switch button.active{background:#111827;color:#fff}.dsh-td-switch .dsh-td-mark{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6d5dfc;box-shadow:0 -7px 0 #a99cff,0 7px 0 #f0a35a;margin:0 6px 0 8px;flex:none}.dsh-td-switch[hidden]{display:none}html[data-platform] .dsh-td-switch,html[data-windows-titlebar] .dsh-td-switch{top:max(2px,calc((var(--dsh-frame-top-clearance,40px) - 36px) / 2))}.dsh-td-bar{position:fixed;z-index:121;top:0;left:0;right:0;height:var(--dsh-frame-top-clearance,0px);display:flex;align-items:center;gap:14px;padding:0 16px;box-sizing:border-box;background:#faf9f7;border-bottom:1px solid #e7e2d9;font:500 12px Inter,system-ui,sans-serif;color:#6b7280;overflow:hidden;-webkit-app-region:drag;user-select:none}.dsh-td-bar[hidden]{display:none}html[data-platform="darwin"] .dsh-td-bar{padding-left:max(var(--dsh-frame-leading-clearance,0px),84px)}html[data-windows-titlebar] .dsh-td-bar{padding-right:calc(100% - env(titlebar-area-width,100%) + 16px)}.dsh-td-bar .dsh-td-brand{display:flex;align-items:center;gap:7px;color:#111827;font-weight:600;font-size:13px;white-space:nowrap}.dsh-td-bar .dsh-td-brand i{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6d5dfc;box-shadow:0 -7px 0 #a99cff,0 7px 0 #f0a35a}.dsh-td-bar .dsh-td-switch{position:static;transform:none;-webkit-app-region:no-drag}.dsh-td-bar .dsh-td-title{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#6b7280}.dsh-td-overlay{position:fixed;z-index:100;inset:var(--dsh-frame-top-clearance,0px) 0 0 0;background:#faf9f7}.dsh-td-overlay[hidden]{display:none}.dsh-td-overlay iframe{display:block;width:100%;height:100%;border:0}'
|
|
66
|
+
// Panel mode: .dsh-td-page is the placeholder the host renders in its
|
|
67
|
+
// main column; on macOS it pads by the window's top strip (the host's
|
|
68
|
+
// own entry pages do the same) so the canvas toolbar never sits under
|
|
69
|
+
// the traffic lights. .dsh-td-overlay is the iframe's fixed layer, laid
|
|
70
|
+
// over the page by place() — no inset of its own.
|
|
71
|
+
// Fallback mode (no panel slot): the floating pill in the window's top
|
|
72
|
+
// strip, the macOS title band over the strip while the canvas is up
|
|
73
|
+
// (#39), the overlay filling the window below the strip.
|
|
74
|
+
style.textContent = '.dsh-td-page{display:block;width:100%;height:100%;min-height:100%;box-sizing:border-box}html[data-platform="darwin"] .dsh-td-page{padding-top:var(--dsh-frame-top-clearance,0px)}.dsh-td-overlay{position:fixed;z-index:100;background:#faf9f7}.dsh-td-overlay[hidden]{display:none}.dsh-td-overlay iframe{display:block;width:100%;height:100%;border:0}.dsh-td-overlay.dsh-td-full{inset:var(--dsh-frame-top-clearance,0px) 0 0 0}.dsh-td-switch{position:fixed;z-index:120;top:12px;left:60%;display:flex;align-items:center;gap:2px;transform:translateX(-50%);-webkit-app-region:no-drag;border:1px solid #d1d5db;border-radius:999px;background:rgba(255,255,255,.96);padding:3px;backdrop-filter:blur(10px)}.dsh-td-switch button{height:28px;border:0;border-radius:999px;background:transparent;padding:0 11px;color:#6b7280;font:600 12px Inter,system-ui,sans-serif;cursor:pointer;white-space:nowrap}.dsh-td-switch button:hover{background:#f3f4f6;color:#111827}.dsh-td-switch button.active{background:#111827;color:#fff}.dsh-td-switch .dsh-td-mark{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6d5dfc;box-shadow:0 -7px 0 #a99cff,0 7px 0 #f0a35a;margin:0 6px 0 8px;flex:none}.dsh-td-switch[hidden]{display:none}html[data-platform] .dsh-td-switch,html[data-windows-titlebar] .dsh-td-switch{top:max(2px,calc((var(--dsh-frame-top-clearance,40px) - 36px) / 2))}.dsh-td-bar{position:fixed;z-index:121;top:0;left:0;right:0;height:var(--dsh-frame-top-clearance,0px);display:flex;align-items:center;gap:14px;padding:0 16px;box-sizing:border-box;background:#faf9f7;border-bottom:1px solid #e7e2d9;font:500 12px Inter,system-ui,sans-serif;color:#6b7280;overflow:hidden;-webkit-app-region:drag;user-select:none}.dsh-td-bar[hidden]{display:none}html[data-platform="darwin"] .dsh-td-bar{padding-left:max(var(--dsh-frame-leading-clearance,0px),84px)}html[data-windows-titlebar] .dsh-td-bar{padding-right:calc(100% - env(titlebar-area-width,100%) + 16px)}.dsh-td-bar .dsh-td-brand{display:flex;align-items:center;gap:7px;color:#111827;font-weight:600;font-size:13px;white-space:nowrap}.dsh-td-bar .dsh-td-brand i{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6d5dfc;box-shadow:0 -7px 0 #a99cff,0 7px 0 #f0a35a}.dsh-td-bar .dsh-td-switch{position:static;transform:none;-webkit-app-region:no-drag}.dsh-td-bar .dsh-td-title{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#6b7280}'
|
|
69
75
|
|
|
70
76
|
let host = document.body.querySelector(':scope > [data-dsh-thoughtdag]')
|
|
71
77
|
if (!host) {
|
|
@@ -73,7 +79,7 @@ window.__ModuleLoader__.load({
|
|
|
73
79
|
host.setAttribute('data-dsh-thoughtdag', '')
|
|
74
80
|
document.body.append(host)
|
|
75
81
|
}
|
|
76
|
-
host.innerHTML = '<div class="dsh-td-switch" role="group" aria-label="view switch"><i class="dsh-td-mark" title="ThoughtDAG"></i><button type="button" data-view="dialog" class="active" aria-pressed="true">对话</button><button type="button" data-view="map" aria-pressed="false">思维图</button></div><div class="dsh-td-bar" data-window-drag hidden><span class="dsh-td-brand"><i></i>ThoughtDAG</span><div class="dsh-td-switch" role="group" aria-label="view switch"><button type="button" data-view="dialog" aria-pressed="false">对话</button><button type="button" data-view="map" class="active" aria-pressed="true">思维图</button></div><span class="dsh-td-title"></span></div><section class="dsh-td-overlay" hidden><iframe title="ThoughtDAG" data-src="/thoughtdag/"></iframe></section>'
|
|
82
|
+
host.innerHTML = '<div class="dsh-td-switch" role="group" aria-label="view switch" hidden><i class="dsh-td-mark" title="ThoughtDAG"></i><button type="button" data-view="dialog" class="active" aria-pressed="true">对话</button><button type="button" data-view="map" aria-pressed="false">思维图</button></div><div class="dsh-td-bar" data-window-drag hidden><span class="dsh-td-brand"><i></i>ThoughtDAG</span><div class="dsh-td-switch" role="group" aria-label="view switch"><button type="button" data-view="dialog" aria-pressed="false">对话</button><button type="button" data-view="map" class="active" aria-pressed="true">思维图</button></div><span class="dsh-td-title"></span></div><section class="dsh-td-overlay" hidden><iframe title="ThoughtDAG" data-src="/thoughtdag/"></iframe></section>'
|
|
77
83
|
|
|
78
84
|
// the plugin's version, for the canvas's update dialog and release history
|
|
79
85
|
let pluginVersion = null
|
|
@@ -82,52 +88,139 @@ window.__ModuleLoader__.load({
|
|
|
82
88
|
const switchEl = host.querySelector(':scope > .dsh-td-switch')
|
|
83
89
|
const bar = host.querySelector('.dsh-td-bar')
|
|
84
90
|
const barTitle = bar.querySelector('.dsh-td-title')
|
|
85
|
-
|
|
91
|
+
const dialogBtn = host.querySelector('[data-view="dialog"]')
|
|
92
|
+
const mapBtn = host.querySelector('[data-view="map"]')
|
|
93
|
+
const overlay = host.querySelector('.dsh-td-overlay')
|
|
94
|
+
const frame = host.querySelector('iframe')
|
|
95
|
+
// the desktop host marks its root; the strip is the window's top band (not in native fullscreen)
|
|
86
96
|
const desktop = () => document.documentElement.dataset.platform !== undefined || document.documentElement.hasAttribute('data-windows-titlebar')
|
|
87
97
|
const strip = () => parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--dsh-frame-top-clearance')) || 0
|
|
98
|
+
const send = (type, payload) => frame.contentWindow?.postMessage({ source: 'dsh-thoughtdag', type, ...payload }, location.origin)
|
|
99
|
+
const syncCurrent = () => send('td:current-session', { session: currentSession() })
|
|
100
|
+
// the SPA boots on first open, never while hidden: a canvas that
|
|
101
|
+
// measures itself inside a display:none frame fits its view to a 0×0
|
|
102
|
+
// box and shows nothing when revealed
|
|
103
|
+
const ensureSrc = () => { if (!frame.src) frame.src = frame.dataset.src + (pluginVersion ? (frame.dataset.src.includes('?') ? '&' : '?') + 'dv=' + encodeURIComponent(pluginVersion) : '') }
|
|
104
|
+
|
|
105
|
+
// ── panel mode: the host's sidebar entry and main-column page ──
|
|
106
|
+
const PANEL_ID = 'thoughtdag'
|
|
107
|
+
const NS = 'dsh-thoughtdag'
|
|
108
|
+
let panelMode = false
|
|
109
|
+
// the page element while the panel is selected (null otherwise)
|
|
110
|
+
let pageEl = null
|
|
111
|
+
let pageObserver = null
|
|
112
|
+
const place = () => {
|
|
113
|
+
if (!pageEl) return
|
|
114
|
+
let box = pageEl
|
|
115
|
+
// the page fills its column; should a host give it no height, the
|
|
116
|
+
// nearest ancestor with one is the column
|
|
117
|
+
for (let i = 0; i < 3 && box.getBoundingClientRect().height < 40 && box.parentElement; i++) box = box.parentElement
|
|
118
|
+
const r = box.getBoundingClientRect()
|
|
119
|
+
const pad = box === pageEl ? parseFloat(getComputedStyle(pageEl).paddingTop) || 0 : 0
|
|
120
|
+
overlay.style.left = r.left + 'px'
|
|
121
|
+
overlay.style.top = (r.top + pad) + 'px'
|
|
122
|
+
overlay.style.width = r.width + 'px'
|
|
123
|
+
overlay.style.height = Math.max(0, r.height - pad) + 'px'
|
|
124
|
+
}
|
|
125
|
+
const openPanel = el => {
|
|
126
|
+
pageEl = el
|
|
127
|
+
ensureSrc()
|
|
128
|
+
overlay.classList.remove('dsh-td-full')
|
|
129
|
+
overlay.hidden = false
|
|
130
|
+
place()
|
|
131
|
+
pageObserver = new ResizeObserver(place)
|
|
132
|
+
pageObserver.observe(el)
|
|
133
|
+
if (el.parentElement) pageObserver.observe(el.parentElement)
|
|
134
|
+
syncCurrent()
|
|
135
|
+
// no band: the host's own column is the canvas's edge; the SPA shows its own switch
|
|
136
|
+
send('td:view', { shown: true, bar: false, desktop: desktop(), panel: true })
|
|
137
|
+
window.setTimeout(() => { if (pageEl) { syncCurrent(); send('td:view', { shown: true, bar: false, desktop: desktop(), panel: true }) } }, 400)
|
|
138
|
+
}
|
|
139
|
+
const closePanel = () => {
|
|
140
|
+
pageEl = null
|
|
141
|
+
pageObserver?.disconnect()
|
|
142
|
+
pageObserver = null
|
|
143
|
+
overlay.hidden = true
|
|
144
|
+
send('td:view', { shown: false, bar: false, desktop: desktop(), panel: true })
|
|
145
|
+
}
|
|
146
|
+
// set once the host has declared the panel slots and taken our entries; a
|
|
147
|
+
// host that never declares them (older harnesses) gets the fallback below
|
|
148
|
+
let registered = false
|
|
149
|
+
if (React && ctx.slots && ctx.layout && ctx.locale && typeof ctx.effect === 'function') {
|
|
150
|
+
try {
|
|
151
|
+
const h = React.createElement
|
|
152
|
+
// the three-dot mark, as the sidebar glyph
|
|
153
|
+
const PanelIcon = ({ size }) => h('svg', { width: size ?? 16, height: size ?? 16, viewBox: '0 0 16 16', 'aria-hidden': 'true' },
|
|
154
|
+
h('circle', { cx: 8, cy: 3, r: 2.2, fill: '#a99cff' }),
|
|
155
|
+
h('circle', { cx: 8, cy: 8, r: 2.2, fill: '#6d5dfc' }),
|
|
156
|
+
h('circle', { cx: 8, cy: 13, r: 2.2, fill: '#f0a35a' }))
|
|
157
|
+
// the page: a placeholder the iframe layer is laid over while mounted
|
|
158
|
+
const PanelPage = () => {
|
|
159
|
+
const ref = React.useRef(null)
|
|
160
|
+
React.useEffect(() => {
|
|
161
|
+
if (ref.current) openPanel(ref.current)
|
|
162
|
+
return () => closePanel()
|
|
163
|
+
}, [])
|
|
164
|
+
return h('div', { ref, className: 'dsh-td-page', 'data-td-page': '' })
|
|
165
|
+
}
|
|
166
|
+
ctx.effect(() => ctx.locale.register(NS, { zh: { panel: 'ThoughtDAG' }, en: { panel: 'ThoughtDAG' } }), 'dsh-thoughtdag: dictionaries')
|
|
167
|
+
const t = ctx.locale.bind(NS)
|
|
168
|
+
ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: PANEL_ID, locale: NS, inject: () => ({}) }, PanelPage))
|
|
169
|
+
ctx.slots.inject('sidebar.panellist', () => { const dispose = ctx.slots.register({ name: 'sidebar.panellist', id: PANEL_ID, order: 30, locale: NS, label: () => t('panel') }, PanelIcon); registered = true; return dispose })
|
|
170
|
+
panelMode = true
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.warn('[dsh-thoughtdag] panel entry unavailable, using the floating switch:', error)
|
|
173
|
+
panelMode = false
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── fallback mode: the floating pill and the full-window overlay ──
|
|
178
|
+
let spaReady = false
|
|
88
179
|
// the band only on macOS: there the strip under the traffic lights is transparent and the host's session
|
|
89
180
|
// header would show through the overlay (#39). On Windows the strip is the host's own chrome (its menu,
|
|
90
181
|
// the caption buttons), opaque and above us; a band there painted over the host's menu (#55). With no
|
|
91
182
|
// band the overlay starts below the chrome and the canvas shows its own switch.
|
|
92
|
-
const barUp = () => document.documentElement.dataset.platform === 'darwin' && strip() > 0
|
|
93
|
-
let spaReady = false
|
|
94
|
-
const dialogBtn = host.querySelector('[data-view="dialog"]')
|
|
95
|
-
const mapBtn = host.querySelector('[data-view="map"]')
|
|
96
|
-
const overlay = host.querySelector('.dsh-td-overlay')
|
|
97
|
-
const frame = host.querySelector('iframe')
|
|
98
|
-
|
|
183
|
+
const barUp = () => !panelMode && document.documentElement.dataset.platform === 'darwin' && strip() > 0
|
|
99
184
|
const setView = map => {
|
|
100
185
|
dialogBtn.classList.toggle('active', !map)
|
|
101
186
|
dialogBtn.setAttribute('aria-pressed', String(!map))
|
|
102
187
|
mapBtn.classList.toggle('active', map)
|
|
103
188
|
mapBtn.setAttribute('aria-pressed', String(map))
|
|
104
189
|
}
|
|
105
|
-
const
|
|
190
|
+
const closeFallback = () => { overlay.hidden = true; bar.hidden = true; switchEl.hidden = false; setView(false); send('td:view', { shown: false, bar: false, desktop: desktop() }) }
|
|
106
191
|
const showBand = () => { bar.hidden = !barUp(); send('td:view', { shown: true, bar: !bar.hidden, desktop: desktop() }) }
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const syncCurrent = () => {
|
|
112
|
-
const session = currentSession()
|
|
113
|
-
send('td:current-session', { session })
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
mapBtn.addEventListener('click', () => {
|
|
192
|
+
const openFallback = () => {
|
|
193
|
+
overlay.classList.add('dsh-td-full')
|
|
194
|
+
overlay.style.left = overlay.style.top = overlay.style.width = overlay.style.height = ''
|
|
117
195
|
overlay.hidden = false
|
|
118
196
|
setView(true)
|
|
119
197
|
bar.hidden = !barUp()
|
|
120
198
|
if (spaReady || !bar.hidden) switchEl.hidden = true
|
|
121
|
-
|
|
122
|
-
// measures itself inside a display:none frame fits its view to a 0×0
|
|
123
|
-
// box and shows nothing when revealed
|
|
124
|
-
if (!frame.src) frame.src = frame.dataset.src + (pluginVersion ? (frame.dataset.src.includes('?') ? '&' : '?') + 'dv=' + encodeURIComponent(pluginVersion) : '')
|
|
199
|
+
ensureSrc()
|
|
125
200
|
syncCurrent()
|
|
126
201
|
showBand()
|
|
127
202
|
// let the SPA boot, then re-sync so its listener is ready
|
|
128
203
|
window.setTimeout(() => { syncCurrent(); showBand() }, 400)
|
|
129
|
-
}
|
|
130
|
-
|
|
204
|
+
}
|
|
205
|
+
let fallbackOn = false
|
|
206
|
+
const enableFallback = () => {
|
|
207
|
+
if (fallbackOn) return
|
|
208
|
+
fallbackOn = true
|
|
209
|
+
panelMode = false
|
|
210
|
+
switchEl.hidden = false
|
|
211
|
+
window.addEventListener('resize', () => { if (!overlay.hidden) showBand() })
|
|
212
|
+
bar.querySelector('[data-view="dialog"]').addEventListener('click', closeFallback)
|
|
213
|
+
mapBtn.addEventListener('click', openFallback)
|
|
214
|
+
dialogBtn.addEventListener('click', closeFallback)
|
|
215
|
+
}
|
|
216
|
+
if (!panelMode) enableFallback()
|
|
217
|
+
// the slot system takes registrations only once the host declares the
|
|
218
|
+
// slot; a host that has not declared sidebar.panellist within a moment
|
|
219
|
+
// of our apply has no panel list at all, so the floating switch returns
|
|
220
|
+
else window.setTimeout(() => { if (!registered) { console.warn('[dsh-thoughtdag] no sidebar panel list on this host, using the floating switch'); enableFallback() } }, 2500)
|
|
221
|
+
|
|
222
|
+
// back to the conversation: the host's own navigation in panel mode, the overlay's close otherwise
|
|
223
|
+
const close = () => { if (panelMode) { try { ctx.layout.selectPanel(null) } catch { closePanel() } } else closeFallback() }
|
|
131
224
|
|
|
132
225
|
window.addEventListener('message', event => {
|
|
133
226
|
if (event.origin !== location.origin || event.data?.source !== 'dsh-thoughtdag') return
|
|
@@ -148,12 +241,13 @@ window.__ModuleLoader__.load({
|
|
|
148
241
|
return
|
|
149
242
|
}
|
|
150
243
|
if (event.data.type === 'td:request-current') {
|
|
151
|
-
// the SPA has booted and shows its own switch: the pill steps aside
|
|
244
|
+
// the SPA has booted and shows its own switch: in fallback mode the pill steps aside
|
|
152
245
|
spaReady = true
|
|
153
|
-
if (!overlay.hidden) { switchEl.hidden = true; showBand() }
|
|
246
|
+
if (!panelMode && !overlay.hidden) { switchEl.hidden = true; showBand() }
|
|
247
|
+
if (panelMode && pageEl) send('td:view', { shown: true, bar: false, desktop: desktop(), panel: true })
|
|
154
248
|
return syncCurrent()
|
|
155
249
|
}
|
|
156
|
-
// the canvas names its project: the band shows it
|
|
250
|
+
// the canvas names its project: the band shows it (fallback mode only)
|
|
157
251
|
if (event.data.type === 'td:title') { barTitle.textContent = typeof event.data.name === 'string' ? event.data.name : ''; return }
|
|
158
252
|
// the canvas forked or continued a session: stage it and go back to the
|
|
159
253
|
// chat, which now shows exactly the context the canvas produced
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-thoughtdag",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
4
4
|
"description": "ThoughtDAG for DeepSeek Harness: turn the current DSH session into an editable thought graph on an infinite canvas. Source, releases and issues: github.com/chenxiachan/thoughtdag",
|
|
5
5
|
"author": "Xia Chen",
|
|
6
6
|
"repository": {
|